• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 
18 #include <unistd.h>
19 
20 #include <android-base/properties.h>
21 #include <gtest/gtest.h>
22 #include <vintf/VintfObject.h>
23 
24 #include <fstream>
25 #include <string>
26 #include <unordered_set>
27 
28 #include "bpf/KernelUtils.h"
29 
30 namespace android {
31 namespace net {
32 
33 namespace {
34 
35 using ::android::base::GetProperty;
36 using ::android::vintf::RuntimeInfo;
37 using ::android::vintf::VintfObject;
38 
39 class KernelConfigVerifier final {
40   public:
KernelConfigVerifier()41     KernelConfigVerifier() : mRuntimeInfo(VintfObject::GetRuntimeInfo()) {
42         std::ifstream procModules("/proc/modules", std::ios::in);
43         if (!procModules) {
44             // Return early, this will likely cause the test to fail. However, gtest FAIL() cannot
45             // be used outside of an actual test method.
46             return;
47         }
48         std::string modline;
49         while (std::getline(procModules, modline)) {
50             // modline contains a single line read from /proc/modules. For example:
51             // virtio_snd 45056 0 - Live 0x0000000000000000 (E)
52             mLoadedModules.emplace(modline.substr(0, modline.find(' ')));
53         }
54     }
55 
hasOption(const std::string & option) const56     bool hasOption(const std::string& option) const {
57         const auto& configMap = mRuntimeInfo->kernelConfigs();
58         auto it = configMap.find(option);
59         if (it != configMap.cend()) {
60             return it->second == "y";
61         }
62         return false;
63     }
64 
hasModule(const std::string & option) const65     bool hasModule(const std::string& option) const {
66         const auto& configMap = mRuntimeInfo->kernelConfigs();
67         auto it = configMap.find(option);
68         if (it != configMap.cend()) {
69             return (it->second == "y") || (it->second == "m");
70         }
71         return false;
72     }
73 
isAvailable(const std::string & option,const std::string & koName) const74     bool isAvailable(const std::string& option, const std::string& koName) const {
75         return hasOption(option) || mLoadedModules.contains(koName);
76     }
77 
78   private:
79     std::shared_ptr<const RuntimeInfo> mRuntimeInfo;
80     std::unordered_set<std::string> mLoadedModules;
81 };
82 
isCuttlefish()83 bool isCuttlefish() {
84     return GetProperty("ro.product.board", "") == "cutf";
85 }
86 
87 }  // namespace
88 
89 /**
90  * If this test fails, enable the following kernel modules in your kernel config:
91  * CONFIG_NET_CLS_MATCHALL=y
92  * CONFIG_NET_ACT_POLICE=y
93  * CONFIG_NET_ACT_BPF=y
94  * CONFIG_BPF_JIT=y
95  */
TEST(KernelTest,TestRateLimitingSupport)96 TEST(KernelTest, TestRateLimitingSupport) {
97     KernelConfigVerifier configVerifier;
98     EXPECT_TRUE(configVerifier.hasOption("CONFIG_NET_CLS_MATCHALL"));
99     EXPECT_TRUE(configVerifier.hasOption("CONFIG_NET_ACT_POLICE"));
100     EXPECT_TRUE(configVerifier.hasOption("CONFIG_NET_ACT_BPF"));
101     EXPECT_TRUE(configVerifier.hasOption("CONFIG_BPF_JIT"));
102 }
103 
TEST(KernelTest,TestRequireBpfUnprivDefaultOn)104 TEST(KernelTest, TestRequireBpfUnprivDefaultOn) {
105     KernelConfigVerifier configVerifier;
106     EXPECT_FALSE(configVerifier.hasOption("CONFIG_BPF_UNPRIV_DEFAULT_OFF"));
107 }
108 
TEST(KernelTest,TestBpfJitAlwaysOn)109 TEST(KernelTest, TestBpfJitAlwaysOn) {
110     KernelConfigVerifier configVerifier;
111     ASSERT_TRUE(configVerifier.hasOption("CONFIG_BPF_JIT_ALWAYS_ON"));
112 }
113 
TEST(KernelTest,TestHaveEfficientUnalignedAccess)114 TEST(KernelTest, TestHaveEfficientUnalignedAccess) {
115     // Turns out the bpf verifier is stricter if you don't have this option.
116     // At least *some* of our bpf code fails to verify without it.
117     KernelConfigVerifier configVerifier;
118     ASSERT_TRUE(configVerifier.hasOption("CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS"));
119 }
120 
121 /* Android 14/U should only launch on 64-bit kernels
122  *   T launches on 5.10/5.15
123  *   U launches on 5.15/6.1
124  * So >=5.16 implies isKernel64Bit()
125  */
TEST(KernelTest,TestKernel64Bit)126 TEST(KernelTest, TestKernel64Bit) {
127     if (!bpf::isAtLeastKernelVersion(5, 16, 0)) GTEST_SKIP() << "Exempt on < 5.16 kernel.";
128     ASSERT_TRUE(bpf::isKernel64Bit());
129 }
130 
131 // Android V requires x86 kernels to be 64-bit, as among other things
132 // 32-bit x86 kernels have subtly different structure layouts for XFRM
TEST(KernelTest,TestX86Kernel64Bit)133 TEST(KernelTest, TestX86Kernel64Bit) {
134     if (!bpf::isX86()) GTEST_SKIP() << "Exempt on non-x86 architecture.";
135     ASSERT_TRUE(bpf::isKernel64Bit());
136 }
137 
138 // Android 25Q2 requires 64-bit userspace on new 6.7+ kernels.
TEST(KernelTest,DISABLED_TestUser64Bit)139 TEST(KernelTest, DISABLED_TestUser64Bit) {
140     if (!bpf::isAtLeastKernelVersion(6, 7, 0)) GTEST_SKIP() << "Exempt on < 6.7 kernel.";
141     ASSERT_TRUE(bpf::isUserspace64bit());
142 }
143 
144 // Android 25Q2 requires 5.4+
TEST(KernelTest,TestKernel54)145 TEST(KernelTest, TestKernel54) {
146     ASSERT_TRUE(bpf::isAtLeastKernelVersion(5, 4, 0));
147 }
148 
149 // RiscV is not yet supported: make it fail VTS.
TEST(KernelTest,TestNotRiscV)150 TEST(KernelTest, TestNotRiscV) {
151     ASSERT_TRUE(!bpf::isRiscV());
152 }
153 
TEST(KernelTest,TestIsLTS)154 TEST(KernelTest, TestIsLTS) {
155     ASSERT_TRUE(bpf::isLtsKernel());
156 }
157 
exists(const char * filename)158 static bool exists(const char* filename) {
159     return !access(filename, F_OK);
160 }
161 
isGSI()162 static bool isGSI() {
163     // From //system/gsid/libgsi.cpp IsGsiRunning()
164     return exists("/metadata/gsi/dsu/booted");
165 }
166 
167 #define ifIsKernelThenMinLTS(major, minor, sub) do { \
168     if (isGSI()) GTEST_SKIP() << "Test is meaningless on GSI."; \
169     if (!bpf::isKernelVersion((major), (minor))) GTEST_SKIP() << "Not for this LTS ver."; \
170     ASSERT_TRUE(bpf::isAtLeastKernelVersion((major), (minor), (sub))); \
171 } while (0)
172 
TEST(KernelTest,TestMinRequiredLTS_5_4)173 TEST(KernelTest, TestMinRequiredLTS_5_4)  { ifIsKernelThenMinLTS(5, 4, 277); }
TEST(KernelTest,TestMinRequiredLTS_5_10)174 TEST(KernelTest, TestMinRequiredLTS_5_10) { ifIsKernelThenMinLTS(5, 10, 210); }
TEST(KernelTest,TestMinRequiredLTS_5_15)175 TEST(KernelTest, TestMinRequiredLTS_5_15) { ifIsKernelThenMinLTS(5, 15, 149); }
TEST(KernelTest,TestMinRequiredLTS_6_1)176 TEST(KernelTest, TestMinRequiredLTS_6_1)  { ifIsKernelThenMinLTS(6, 1, 78); }
TEST(KernelTest,TestMinRequiredLTS_6_6)177 TEST(KernelTest, TestMinRequiredLTS_6_6)  { ifIsKernelThenMinLTS(6, 6, 30); }
TEST(KernelTest,TestMinRequiredLTS_6_12)178 TEST(KernelTest, TestMinRequiredLTS_6_12) { ifIsKernelThenMinLTS(6, 12, 13); }
179 
TEST(KernelTest,TestSupportsAcceptRaMinLft)180 TEST(KernelTest, TestSupportsAcceptRaMinLft) {
181     if (isGSI()) GTEST_SKIP() << "Meaningless on GSI due to ancient kernels.";
182     if (!bpf::isAtLeastKernelVersion(5, 10, 0)) GTEST_SKIP() << "Too old base kernel.";
183     ASSERT_TRUE(exists("/proc/sys/net/ipv6/conf/default/accept_ra_min_lft"));
184 }
185 
TEST(KernelTest,TestSupportsBpfLsm)186 TEST(KernelTest, TestSupportsBpfLsm) {
187     if (isGSI()) GTEST_SKIP() << "Meaningless on GSI due to ancient kernels.";
188     if (!bpf::isAtLeastKernelVersion(6, 2, 0)) GTEST_SKIP() << "Too old base kernel.";
189     KernelConfigVerifier configVerifier;
190     ASSERT_TRUE(configVerifier.hasOption("CONFIG_BPF_LSM"));
191 }
192 
193 // https://source.android.com/docs/compatibility/15/android-15-cdd#7452_ipv6 C-0-6
194 // MUST provide third-party applications with direct IPv6 connectivity to the
195 // network when connected to an IPv6 network, without any form of address
196 // or port translation happening locally on the device.
TEST(KernelTest,TestNoIpv6Nat)197 TEST(KernelTest, TestNoIpv6Nat) {
198     KernelConfigVerifier configVerifier;
199     ASSERT_FALSE(configVerifier.hasOption("CONFIG_IP6_NF_NAT"));
200 }
201 
TEST(KernelTest,TestSupportsCommonUsbEthernetDongles)202 TEST(KernelTest, TestSupportsCommonUsbEthernetDongles) {
203     KernelConfigVerifier configVerifier;
204     if (!configVerifier.hasModule("CONFIG_USB")) GTEST_SKIP() << "Exempt without USB support.";
205     EXPECT_TRUE(configVerifier.hasModule("CONFIG_USB_NET_AX8817X"));
206     EXPECT_TRUE(configVerifier.hasModule("CONFIG_USB_NET_AX88179_178A"));
207     EXPECT_TRUE(configVerifier.hasModule("CONFIG_USB_NET_CDCETHER"));
208     EXPECT_TRUE(configVerifier.hasModule("CONFIG_USB_NET_CDC_EEM"));
209     EXPECT_TRUE(configVerifier.hasModule("CONFIG_USB_NET_CDC_NCM"));
210     if (bpf::isAtLeastKernelVersion(5, 4, 0))
211         EXPECT_TRUE(configVerifier.hasModule("CONFIG_USB_NET_AQC111"));
212 
213     EXPECT_TRUE(configVerifier.hasModule("CONFIG_USB_RTL8152"));
214     EXPECT_TRUE(configVerifier.hasModule("CONFIG_USB_RTL8150"));
215     if (bpf::isAtLeastKernelVersion(5, 15, 0)) {
216         EXPECT_TRUE(configVerifier.hasModule("CONFIG_USB_RTL8153_ECM"));
217         EXPECT_TRUE(configVerifier.hasModule("CONFIG_AX88796B_PHY"));
218     }
219 }
220 
221 /**
222  * In addition to TestSupportsCommonUsbEthernetDongles, ensure that USB CDC host drivers are either
223  * builtin or loaded on physical devices.
224  */
225 // TODO: check for hasSystemFeature(FEATURE_USB_HOST)
TEST(KernelTest,TestSupportsUsbCdcHost)226 TEST(KernelTest, TestSupportsUsbCdcHost) {
227     KernelConfigVerifier configVerifier;
228     // TODO: Load these modules on cuttlefish.
229     if (isCuttlefish()) GTEST_SKIP() << "Exempt on cuttlefish";
230 
231     EXPECT_TRUE(configVerifier.isAvailable("CONFIG_USB_NET_CDC_NCM", "cdc_ncm"));
232     EXPECT_TRUE(configVerifier.isAvailable("CONFIG_USB_NET_CDC_EEM", "cdc_eem"));
233     EXPECT_TRUE(configVerifier.isAvailable("CONFIG_USB_NET_CDCETHER", "cdc_ether"));
234 }
235 
236 // TODO: check for hasSystemFeature(FEATURE_USB_ACCESSORY)
TEST(KernelTest,TestSupportsUsbNcmGadget)237 TEST(KernelTest, TestSupportsUsbNcmGadget) {
238     KernelConfigVerifier configVerifier;
239     EXPECT_TRUE(configVerifier.isAvailable("CONFIG_USB_F_NCM", "usb_f_ncm"));
240     EXPECT_TRUE(configVerifier.hasOption("CONFIG_USB_CONFIGFS_NCM"));
241 }
242 
243 }  // namespace net
244 }  // namespace android
245