1 /*
2 * Copyright (C) 2017 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 #pragma once
18
19 #include <linux/if_ether.h>
20 #include <linux/pfkeyv2.h>
21 #include <net/if.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/resource.h>
25 #include <sys/socket.h>
26 #include <sys/utsname.h>
27
28 #include <string>
29
30 #include <android-base/unique_fd.h>
31 #include <log/log.h>
32
33 #include "BpfSyscallWrappers.h"
34
35 // The buffer size for the buffer that records program loading logs, needs to be large enough for
36 // the largest kernel program.
37
38 namespace android {
39 namespace bpf {
40
41 constexpr const int OVERFLOW_COUNTERSET = 2;
42
43 constexpr const uint64_t NONEXISTENT_COOKIE = 0;
44
getSocketCookie(int sockFd)45 static inline uint64_t getSocketCookie(int sockFd) {
46 uint64_t sock_cookie;
47 socklen_t cookie_len = sizeof(sock_cookie);
48 int res = getsockopt(sockFd, SOL_SOCKET, SO_COOKIE, &sock_cookie, &cookie_len);
49 if (res < 0) {
50 res = -errno;
51 ALOGE("Failed to get socket cookie: %s\n", strerror(errno));
52 errno = -res;
53 // 0 is an invalid cookie. See sock_gen_cookie.
54 return NONEXISTENT_COOKIE;
55 }
56 return sock_cookie;
57 }
58
synchronizeKernelRCU()59 static inline int synchronizeKernelRCU() {
60 // This is a temporary hack for network stats map swap on devices running
61 // 4.9 kernels. The kernel code of socket release on pf_key socket will
62 // explicitly call synchronize_rcu() which is exactly what we need.
63 int pfSocket = socket(AF_KEY, SOCK_RAW | SOCK_CLOEXEC, PF_KEY_V2);
64
65 if (pfSocket < 0) {
66 int ret = -errno;
67 ALOGE("create PF_KEY socket failed: %s", strerror(errno));
68 return ret;
69 }
70
71 // When closing socket, synchronize_rcu() gets called in sock_release().
72 if (close(pfSocket)) {
73 int ret = -errno;
74 ALOGE("failed to close the PF_KEY socket: %s", strerror(errno));
75 return ret;
76 }
77 return 0;
78 }
79
setrlimitForTest()80 static inline int setrlimitForTest() {
81 // Set the memory rlimit for the test process if the default MEMLOCK rlimit is not enough.
82 struct rlimit limit = {
83 .rlim_cur = 1073741824, // 1 GiB
84 .rlim_max = 1073741824, // 1 GiB
85 };
86 int res = setrlimit(RLIMIT_MEMLOCK, &limit);
87 if (res) {
88 ALOGE("Failed to set the default MEMLOCK rlimit: %s", strerror(errno));
89 }
90 return res;
91 }
92
93 #define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c))
94
uncachedKernelVersion()95 static inline unsigned uncachedKernelVersion() {
96 struct utsname buf;
97 int ret = uname(&buf);
98 if (ret) return 0;
99
100 unsigned kver_major;
101 unsigned kver_minor;
102 unsigned kver_sub;
103 char unused;
104 ret = sscanf(buf.release, "%u.%u.%u%c", &kver_major, &kver_minor, &kver_sub, &unused);
105 // Check the device kernel version
106 if (ret < 3) return 0;
107
108 return KVER(kver_major, kver_minor, kver_sub);
109 }
110
kernelVersion()111 static inline unsigned kernelVersion() {
112 static unsigned kver = uncachedKernelVersion();
113 return kver;
114 }
115
isAtLeastKernelVersion(unsigned major,unsigned minor,unsigned sub)116 static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) {
117 return kernelVersion() >= KVER(major, minor, sub);
118 }
119
120 #define SKIP_IF_BPF_SUPPORTED \
121 do { \
122 if (android::bpf::isAtLeastKernelVersion(4, 9, 0)) \
123 GTEST_SKIP() << "Skip: bpf is supported."; \
124 } while (0)
125
126 #define SKIP_IF_BPF_NOT_SUPPORTED \
127 do { \
128 if (!android::bpf::isAtLeastKernelVersion(4, 9, 0)) \
129 GTEST_SKIP() << "Skip: bpf is not supported."; \
130 } while (0)
131
132 #define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED \
133 do { \
134 if (!android::bpf::isAtLeastKernelVersion(4, 14, 0)) \
135 GTEST_SKIP() << "Skip: extended bpf feature not supported."; \
136 } while (0)
137
138 #define SKIP_IF_XDP_NOT_SUPPORTED \
139 do { \
140 if (!android::bpf::isAtLeastKernelVersion(5, 9, 0)) \
141 GTEST_SKIP() << "Skip: xdp not supported."; \
142 } while (0)
143
144 } // namespace bpf
145 } // namespace android
146