blob: dd25f969c6237d1949f64d481be98fa27593f1db [file] [log] [blame]
Pierre Imai904ce3a2016-02-18 13:13:12 +09001/*
2 * Copyright (C) 2016 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 *
Lorenzo Colitti93a0d642019-06-26 22:31:03 +090010 * Unless required by applicable law or agreed to in writing, software
Pierre Imai904ce3a2016-02-18 13:13:12 +090011 * 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
Maciej Żenczykowski8d6ed4a2020-05-29 00:41:22 -070018#include <arpa/inet.h>
Pierre Imai904ce3a2016-02-18 13:13:12 +090019#include <errno.h>
Maciej Żenczykowski8d6ed4a2020-05-29 00:41:22 -070020#include <linux/if_packet.h>
21#include <linux/if_tun.h>
22#include <net/if.h>
23#include <poll.h>
Maciej Żenczykowski6b479262020-05-29 23:51:18 +000024#include <sched.h>
Chenbo Feng66165472018-07-23 19:05:56 -070025#include <sys/capability.h>
Maciej Żenczykowski8d6ed4a2020-05-29 00:41:22 -070026#include <sys/ioctl.h>
27#include <sys/socket.h>
28#include <sys/types.h>
Pierre Imai904ce3a2016-02-18 13:13:12 +090029
30#include <gtest/gtest.h>
Pierre Imaibeedec32016-04-13 06:44:51 +090031
Maciej Żenczykowski8d6ed4a2020-05-29 00:41:22 -070032#include <android-base/unique_fd.h>
33
34#define LOG_TAG "NetdTest"
35#include "bpf/BpfMap.h"
36#include "netdbpf/bpf_shared.h"
37
38#include "OffloadUtils.h"
39
40namespace android {
41namespace net {
42
43using base::unique_fd;
44
Chenbo Feng66165472018-07-23 19:05:56 -070045TEST(NetUtilsWrapperTest, TestFileCapabilities) {
46 errno = 0;
47 ASSERT_EQ(NULL, cap_get_file("/system/bin/netutils-wrapper-1.0"));
48 ASSERT_EQ(ENODATA, errno);
49}
Maciej Żenczykowski5a914822019-05-02 21:57:10 -070050
51TEST(NetdSELinuxTest, CheckProperMTULabels) {
52 // Since we expect the egrep regexp to filter everything out,
53 // we thus expect no matches and thus a return code of 1
54 // NOLINTNEXTLINE(cert-env33-c)
55 ASSERT_EQ(W_EXITCODE(1, 0), system("ls -Z /sys/class/net/*/mtu | egrep -q -v "
56 "'^u:object_r:sysfs_net:s0 /sys/class/net/'"));
57}
Maciej Żenczykowski6b479262020-05-29 23:51:18 +000058
59// Trivial thread function that simply immediately terminates successfully.
60static int thread(void*) {
61 return 0;
62}
63
64typedef int (*thread_t)(void*);
65
66static void nsTest(int flags, bool success, thread_t newThread) {
67 // We need a minimal stack, but not clear if it will grow up or down,
68 // So allocate 2 pages and give a pointer to the middle.
69 static char stack[PAGE_SIZE * 2];
70 errno = 0;
71 // VFORK: if thread is successfully created, then kernel will wait for it
72 // to terminate before we resume -> hence static stack is safe to reuse.
73 int tid = clone(newThread, &stack[PAGE_SIZE], flags | CLONE_VFORK, NULL);
74 if (success) {
75 ASSERT_EQ(errno, 0);
76 ASSERT_GE(tid, 0);
77 } else {
78 ASSERT_EQ(errno, EINVAL);
79 ASSERT_EQ(tid, -1);
80 }
81}
82
83// Test kernel configuration option CONFIG_NAMESPACES=y
Maciej Zenczykowskieffd1f02020-05-30 01:10:29 +000084TEST(NetdNamespaceTest, CheckMountNamespaceSupport) {
Maciej Żenczykowski6b479262020-05-29 23:51:18 +000085 nsTest(CLONE_NEWNS, true, thread);
86}
87
88// Test kernel configuration option CONFIG_UTS_NS=y
Maciej Zenczykowskieffd1f02020-05-30 01:10:29 +000089TEST(NetdNamespaceTest, CheckUTSNamespaceSupport) {
Maciej Żenczykowski6b479262020-05-29 23:51:18 +000090 nsTest(CLONE_NEWUTS, true, thread);
91}
92
93// Test kernel configuration option CONFIG_NET_NS=y
Maciej Zenczykowskieffd1f02020-05-30 01:10:29 +000094TEST(NetdNamespaceTest, CheckNetworkNamespaceSupport) {
Maciej Żenczykowski6b479262020-05-29 23:51:18 +000095 nsTest(CLONE_NEWNET, true, thread);
96}
97
98// Test kernel configuration option CONFIG_USER_NS=n
Maciej Zenczykowskieffd1f02020-05-30 01:10:29 +000099TEST(NetdNamespaceTest, /*DISABLED_*/ CheckNoUserNamespaceSupport) {
Maciej Żenczykowski6b479262020-05-29 23:51:18 +0000100 nsTest(CLONE_NEWUSER, false, thread);
101}
102
103// Test for all of the above
Maciej Zenczykowskieffd1f02020-05-30 01:10:29 +0000104TEST(NetdNamespaceTest, CheckFullNamespaceSupport) {
Maciej Żenczykowski6b479262020-05-29 23:51:18 +0000105 nsTest(CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWNET, true, thread);
106}
Maciej Żenczykowski8d6ed4a2020-05-29 00:41:22 -0700107
108// Test for presence of kernel patch:
109// ANDROID: net: bpf: permit redirect from ingress L3 to egress L2 devices at near max mtu
110// on 4.14+ kernels.
111TEST(NetdBpfTest, testBpfSkbChangeHeadAboveMTU) {
112 SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED;
113
114 constexpr int mtu = 1500;
115
116 errno = 0;
117
118 // Amusingly can't use SIOC... on tun/tap fds.
119 int rv = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0);
120 ASSERT_EQ(errno, 0);
121 ASSERT_GE(rv, 3);
122 unique_fd unixfd(rv);
123
124 rv = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
125 ASSERT_EQ(errno, 0);
126 ASSERT_GE(rv, 3);
127 unique_fd tun(rv);
128
129 rv = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
130 ASSERT_EQ(errno, 0);
131 ASSERT_GE(rv, 3);
132 unique_fd tap(rv);
133
134 struct ifreq tun_ifr = {
135 .ifr_flags = IFF_TUN | IFF_NO_PI,
136 .ifr_name = "tun_bpftest",
137 };
138
139 struct ifreq tap_ifr = {
140 .ifr_flags = IFF_TAP | IFF_NO_PI,
141 .ifr_name = "tap_bpftest",
142 };
143
144 rv = ioctl(tun, TUNSETIFF, &tun_ifr);
145 ASSERT_EQ(errno, 0);
146 ASSERT_EQ(rv, 0);
147
148 rv = ioctl(tap, TUNSETIFF, &tap_ifr);
149 ASSERT_EQ(errno, 0);
150 ASSERT_EQ(rv, 0);
151
152 // prevents kernel from sending us spurious ipv6 packets
153 rv = open("/proc/sys/net/ipv6/conf/tap_bpftest/disable_ipv6", O_WRONLY);
154 ASSERT_EQ(errno, 0);
155 ASSERT_GE(rv, 3);
156 unique_fd f(rv);
157
158 rv = write(f, "1\n", 2);
159 ASSERT_EQ(errno, 0);
160 ASSERT_EQ(rv, 2);
161
162 rv = close(f.release());
163 ASSERT_EQ(errno, 0);
164 ASSERT_EQ(rv, 0);
165
166 int tunif = if_nametoindex(tun_ifr.ifr_name);
167 ASSERT_GE(tunif, 2);
168
169 int tapif = if_nametoindex(tap_ifr.ifr_name);
170 ASSERT_GE(tapif, 2);
171
172 tun_ifr.ifr_mtu = mtu;
173 rv = ioctl(unixfd, SIOCSIFMTU, &tun_ifr);
174 ASSERT_EQ(errno, 0);
175 ASSERT_EQ(rv, 0);
176
177 tap_ifr.ifr_mtu = mtu;
178 rv = ioctl(unixfd, SIOCSIFMTU, &tap_ifr);
179 ASSERT_EQ(errno, 0);
180 ASSERT_EQ(rv, 0);
181
182 rv = ioctl(unixfd, SIOCGIFFLAGS, &tun_ifr);
183 ASSERT_EQ(errno, 0);
184 ASSERT_EQ(rv, 0);
185
186 rv = ioctl(unixfd, SIOCGIFFLAGS, &tap_ifr);
187 ASSERT_EQ(errno, 0);
188 ASSERT_EQ(rv, 0);
189
190 tun_ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
191
192 tap_ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
193
194 rv = ioctl(unixfd, SIOCSIFFLAGS, &tun_ifr);
195 ASSERT_EQ(errno, 0);
196 ASSERT_EQ(rv, 0);
197
198 rv = ioctl(unixfd, SIOCSIFFLAGS, &tap_ifr);
199 ASSERT_EQ(errno, 0);
200 ASSERT_EQ(rv, 0);
201
202 rv = tcQdiscAddDevClsact(tunif);
203 ASSERT_EQ(rv, 0);
204
205 int bpfFd = getTetherIngressProgFd(/* ethernet */ false);
206 ASSERT_EQ(errno, 0);
207 ASSERT_GE(bpfFd, 3);
208
209 rv = tcFilterAddDevIngressTether(tunif, bpfFd, /* ethernet*/ false);
210 ASSERT_EQ(rv, 0);
211
212 bpf::BpfMap<TetherIngressKey, TetherIngressValue> bpfIngressMap;
213 bpf::BpfMap<uint32_t, TetherStatsValue> bpfStatsMap;
214 bpf::BpfMap<uint32_t, uint64_t> bpfLimitMap;
215
216 rv = getTetherIngressMapFd();
217 ASSERT_GE(rv, 3);
218 bpfIngressMap.reset(rv);
219
220 rv = getTetherStatsMapFd();
221 ASSERT_GE(rv, 3);
222 bpfStatsMap.reset(rv);
223
224 rv = getTetherLimitMapFd();
225 ASSERT_GE(rv, 3);
226 bpfLimitMap.reset(rv);
227
228 TetherIngressKey key = {
229 .iif = static_cast<uint32_t>(tunif),
230 //.neigh6 = ,
231 };
232
233 ethhdr hdr = {
234 .h_proto = htons(ETH_P_IPV6),
235 };
236
237 TetherIngressValue value = {
238 .oif = static_cast<uint32_t>(tapif),
239 .macHeader = hdr,
240 .pmtu = mtu,
241 };
242
243#define ASSERT_OK(status) ASSERT_TRUE((status).ok())
244
245 ASSERT_OK(bpfIngressMap.writeValue(key, value, BPF_ANY));
246
247 uint32_t k = tunif;
248 TetherStatsValue stats = {};
249 ASSERT_OK(bpfStatsMap.writeValue(k, stats, BPF_NOEXIST));
250
251 uint64_t limit = ~0uLL;
252 ASSERT_OK(bpfLimitMap.writeValue(k, limit, BPF_NOEXIST));
253
Maciej Żenczykowskia28a1da2020-06-03 10:18:45 +0000254 // minimal 'acceptable' 40-byte hoplimit 255 IPv6 packet, src ip 2000::
Maciej Żenczykowski8d6ed4a2020-05-29 00:41:22 -0700255 uint8_t pkt[mtu] = {
Maciej Żenczykowskia28a1da2020-06-03 10:18:45 +0000256 0x60, 0, 0, 0, 0, 40, 0, 255, 0x20,
Maciej Żenczykowski8d6ed4a2020-05-29 00:41:22 -0700257 };
258
259 // Iterate over all packet sizes from minimal ipv6 packet to mtu.
260 // Tethering ebpf program should forward the packet from tun to tap interface.
261 // TUN is L3, TAP is L2, so it will add a 14 byte ethernet header.
Maciej Żenczykowski834fd1a2020-05-30 02:12:31 -0700262 for (int pkt_size = 40; pkt_size <= mtu; ++pkt_size) {
Maciej Żenczykowski8d6ed4a2020-05-29 00:41:22 -0700263 rv = write(tun, pkt, pkt_size);
264 ASSERT_EQ(errno, 0);
265 ASSERT_EQ(rv, pkt_size);
266
267 struct pollfd p = {
268 .fd = tap,
269 .events = POLLIN,
270 };
271
272 rv = poll(&p, 1, 1000 /*milliseconds*/);
273 if (rv == 0) {
274 // we hit a timeout at this packet size, log it
275 EXPECT_EQ(pkt_size, -1);
276 // this particular packet size is where it fails without the oneline kernel fix
277 if (pkt_size + ETH_HLEN == mtu + 1) EXPECT_EQ("detected missing kernel patch", "");
278 break;
279 }
280 EXPECT_EQ(errno, 0);
281 EXPECT_EQ(rv, 1);
282 EXPECT_EQ(p.revents, POLLIN);
283
284 // use a buffer 1 byte larger then what we expect so we don't simply get truncated down
285 uint8_t buf[ETH_HLEN + mtu + 1];
286 rv = read(tap, buf, sizeof(buf));
287 EXPECT_EQ(errno, 0);
288 EXPECT_EQ(rv, ETH_HLEN + pkt_size);
289 errno = 0;
290 if (rv < 0) break;
291 }
292
293 ASSERT_OK(bpfIngressMap.deleteValue(key));
294 ASSERT_OK(bpfStatsMap.deleteValue(k));
295 ASSERT_OK(bpfLimitMap.deleteValue(k));
296}
297
298} // namespace net
299} // namespace android