blob: 77322479b2fb48c67c63390422433b3bdfd8348b [file] [log] [blame]
Patrick Rohr27846ff2022-01-17 12:22:51 +01001/*
2 * Copyright 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 * TcUtilsTest.cpp - unit tests for TcUtils.cpp
17 */
18
19#include <gtest/gtest.h>
20
Patrick Rohr66452f52023-05-17 11:35:08 -070021#include "bpf/KernelUtils.h"
Patrick Rohr27846ff2022-01-17 12:22:51 +010022#include <tcutils/tcutils.h>
23
Patrick Rohr1f7ba252022-01-17 16:14:10 +010024#include <BpfSyscallWrappers.h>
Patrick Rohr27846ff2022-01-17 12:22:51 +010025#include <errno.h>
Patrick Rohr1f7ba252022-01-17 16:14:10 +010026#include <linux/if_ether.h>
Patrick Rohr27846ff2022-01-17 12:22:51 +010027
28namespace android {
29
30TEST(LibTcUtilsTest, IsEthernetOfNonExistingIf) {
31 bool result = false;
32 int error = isEthernet("not_existing_if", result);
33 ASSERT_FALSE(result);
34 ASSERT_EQ(-ENODEV, error);
35}
36
37TEST(LibTcUtilsTest, IsEthernetOfLoopback) {
38 bool result = false;
39 int error = isEthernet("lo", result);
40 ASSERT_FALSE(result);
41 ASSERT_EQ(-EAFNOSUPPORT, error);
42}
43
44// If wireless 'wlan0' interface exists it should be Ethernet.
45// See also HardwareAddressTypeOfWireless.
46TEST(LibTcUtilsTest, IsEthernetOfWireless) {
47 bool result = false;
48 int error = isEthernet("wlan0", result);
49 if (!result && error == -ENODEV)
50 return;
51
52 ASSERT_EQ(0, error);
53 ASSERT_TRUE(result);
54}
55
56// If cellular 'rmnet_data0' interface exists it should
57// *probably* not be Ethernet and instead be RawIp.
58// See also HardwareAddressTypeOfCellular.
59TEST(LibTcUtilsTest, IsEthernetOfCellular) {
60 bool result = false;
61 int error = isEthernet("rmnet_data0", result);
62 if (!result && error == -ENODEV)
63 return;
64
65 ASSERT_EQ(0, error);
66 ASSERT_FALSE(result);
67}
68
Patrick Rohr42b58ae2022-01-17 13:09:12 +010069// See Linux kernel source in include/net/flow.h
70static constexpr int LOOPBACK_IFINDEX = 1;
71
72TEST(LibTcUtilsTest, AttachReplaceDetachClsactLo) {
73 // This attaches and detaches a configuration-less and thus no-op clsact
74 // qdisc to loopback interface (and it takes fractions of a second)
75 EXPECT_EQ(0, tcAddQdiscClsact(LOOPBACK_IFINDEX));
76 EXPECT_EQ(0, tcReplaceQdiscClsact(LOOPBACK_IFINDEX));
77 EXPECT_EQ(0, tcDeleteQdiscClsact(LOOPBACK_IFINDEX));
78 EXPECT_EQ(-EINVAL, tcDeleteQdiscClsact(LOOPBACK_IFINDEX));
79}
80
Patrick Rohr1f7ba252022-01-17 16:14:10 +010081TEST(LibTcUtilsTest, AddAndDeleteBpfFilter) {
Maciej Żenczykowski41abe752022-12-08 16:39:56 +000082 // TODO: this should likely be in the tethering module, where using netd.h would be ok
Patrick Rohr1f7ba252022-01-17 16:14:10 +010083 static constexpr char bpfProgPath[] =
84 "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_downstream6_ether";
Maciej Żenczykowskid7d3b032022-12-22 17:03:18 +000085 const int errNOENT = bpf::isAtLeastKernelVersion(4, 19, 0) ? ENOENT : EINVAL;
Patrick Rohr1f7ba252022-01-17 16:14:10 +010086
87 // static test values
88 static constexpr bool ingress = true;
89 static constexpr uint16_t prio = 17;
90 static constexpr uint16_t proto = ETH_P_ALL;
91
92 // try to delete missing filter from missing qdisc
93 EXPECT_EQ(-EINVAL, tcDeleteFilter(LOOPBACK_IFINDEX, ingress, prio, proto));
94 // try to attach bpf filter to missing qdisc
95 EXPECT_EQ(-EINVAL, tcAddBpfFilter(LOOPBACK_IFINDEX, ingress, prio, proto,
96 bpfProgPath));
97 // add the clsact qdisc
98 EXPECT_EQ(0, tcAddQdiscClsact(LOOPBACK_IFINDEX));
99 // try to delete missing filter when there is a qdisc attached
100 EXPECT_EQ(-errNOENT, tcDeleteFilter(LOOPBACK_IFINDEX, ingress, prio, proto));
101 // add and delete a bpf filter
102 EXPECT_EQ(
103 0, tcAddBpfFilter(LOOPBACK_IFINDEX, ingress, prio, proto, bpfProgPath));
104 EXPECT_EQ(0, tcDeleteFilter(LOOPBACK_IFINDEX, ingress, prio, proto));
105 // try to remove the same filter a second time
106 EXPECT_EQ(-errNOENT, tcDeleteFilter(LOOPBACK_IFINDEX, ingress, prio, proto));
107 // remove the clsact qdisc
108 EXPECT_EQ(0, tcDeleteQdiscClsact(LOOPBACK_IFINDEX));
109 // once again, try to delete missing filter from missing qdisc
110 EXPECT_EQ(-EINVAL, tcDeleteFilter(LOOPBACK_IFINDEX, ingress, prio, proto));
111}
112
Patrick Rohre815a742022-01-17 10:37:40 +0100113TEST(LibTcUtilsTest, AddAndDeleteIngressPoliceFilter) {
Maciej Żenczykowski41abe752022-12-08 16:39:56 +0000114 // TODO: this should likely be in the tethering module, where using netd.h would be ok
Patrick Rohre815a742022-01-17 10:37:40 +0100115 static constexpr char bpfProgPath[] =
Maciej Żenczykowskiaf0ae672022-08-10 12:25:56 +0000116 "/sys/fs/bpf/netd_shared/prog_netd_schedact_ingress_account";
Patrick Rohre815a742022-01-17 10:37:40 +0100117 int fd = bpf::retrieveProgram(bpfProgPath);
Maciej Żenczykowskiaf0ae672022-08-10 12:25:56 +0000118 ASSERT_LE(3, fd);
Patrick Rohre815a742022-01-17 10:37:40 +0100119 close(fd);
120
Maciej Żenczykowskid7d3b032022-12-22 17:03:18 +0000121 const int errNOENT = bpf::isAtLeastKernelVersion(4, 19, 0) ? ENOENT : EINVAL;
Patrick Rohre815a742022-01-17 10:37:40 +0100122
123 // static test values
124 static constexpr unsigned rateInBytesPerSec =
125 1024 * 1024; // 8mbit/s => 1mbyte/s => 1024*1024 bytes/s.
126 static constexpr uint16_t prio = 17;
127 static constexpr uint16_t proto = ETH_P_ALL;
128
129 // try to delete missing filter from missing qdisc
130 EXPECT_EQ(-EINVAL,
131 tcDeleteFilter(LOOPBACK_IFINDEX, true /*ingress*/, prio, proto));
132 // try to attach bpf filter to missing qdisc
133 EXPECT_EQ(-EINVAL, tcAddIngressPoliceFilter(LOOPBACK_IFINDEX, prio, proto,
134 rateInBytesPerSec, bpfProgPath));
135 // add the clsact qdisc
136 EXPECT_EQ(0, tcAddQdiscClsact(LOOPBACK_IFINDEX));
137 // try to delete missing filter when there is a qdisc attached
138 EXPECT_EQ(-errNOENT,
139 tcDeleteFilter(LOOPBACK_IFINDEX, true /*ingress*/, prio, proto));
140 // add and delete a bpf filter
141 EXPECT_EQ(0, tcAddIngressPoliceFilter(LOOPBACK_IFINDEX, prio, proto,
142 rateInBytesPerSec, bpfProgPath));
143 EXPECT_EQ(0, tcDeleteFilter(LOOPBACK_IFINDEX, true /*ingress*/, prio, proto));
144 // try to remove the same filter a second time
145 EXPECT_EQ(-errNOENT,
146 tcDeleteFilter(LOOPBACK_IFINDEX, true /*ingress*/, prio, proto));
147 // remove the clsact qdisc
148 EXPECT_EQ(0, tcDeleteQdiscClsact(LOOPBACK_IFINDEX));
149 // once again, try to delete missing filter from missing qdisc
150 EXPECT_EQ(-EINVAL,
151 tcDeleteFilter(LOOPBACK_IFINDEX, true /*ingress*/, prio, proto));
152}
153
Patrick Rohr27846ff2022-01-17 12:22:51 +0100154} // namespace android