1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/qbone/bonnet/tun_device.h"
6
7 #include <linux/if.h>
8 #include <linux/if_tun.h>
9 #include <sys/ioctl.h>
10
11 #include "quiche/quic/platform/api/quic_test.h"
12 #include "quiche/quic/qbone/platform/mock_kernel.h"
13
14 namespace quic::test {
15 namespace {
16
17 using ::testing::_;
18 using ::testing::AnyNumber;
19 using ::testing::Invoke;
20 using ::testing::Return;
21 using ::testing::StrEq;
22 using ::testing::Unused;
23
24 const char kDeviceName[] = "tun0";
25 const int kSupportedFeatures =
26 IFF_TUN | IFF_TAP | IFF_MULTI_QUEUE | IFF_ONE_QUEUE | IFF_NO_PI;
27
28 // Quite a bit of EXPECT_CALL().Times(AnyNumber()).WillRepeatedly() are used to
29 // make sure we can correctly set common expectations and override the
30 // expectation with later call to EXPECT_CALL(). ON_CALL cannot be used here
31 // since when EPXECT_CALL overrides ON_CALL, it ignores the parameter matcher
32 // which results in unexpected call even if ON_CALL exists.
33 class TunDeviceTest : public QuicTest {
34 protected:
SetUp()35 void SetUp() override {
36 EXPECT_CALL(mock_kernel_, socket(AF_INET6, _, _))
37 .Times(AnyNumber())
38 .WillRepeatedly(Invoke([this](Unused, Unused, Unused) {
39 EXPECT_CALL(mock_kernel_, close(next_fd_)).WillOnce(Return(0));
40 return next_fd_++;
41 }));
42 }
43
44 // Set the expectations for calling Init().
SetInitExpectations(int mtu,bool persist)45 void SetInitExpectations(int mtu, bool persist) {
46 EXPECT_CALL(mock_kernel_, open(StrEq("/dev/net/tun"), _))
47 .Times(AnyNumber())
48 .WillRepeatedly(Invoke([this](Unused, Unused) {
49 EXPECT_CALL(mock_kernel_, close(next_fd_)).WillOnce(Return(0));
50 return next_fd_++;
51 }));
52 EXPECT_CALL(mock_kernel_, ioctl(_, TUNGETFEATURES, _))
53 .Times(AnyNumber())
54 .WillRepeatedly(Invoke([](Unused, Unused, void* argp) {
55 auto* actual_flags = reinterpret_cast<int*>(argp);
56 *actual_flags = kSupportedFeatures;
57 return 0;
58 }));
59 EXPECT_CALL(mock_kernel_, ioctl(_, TUNSETIFF, _))
60 .Times(AnyNumber())
61 .WillRepeatedly(Invoke([](Unused, Unused, void* argp) {
62 auto* ifr = reinterpret_cast<struct ifreq*>(argp);
63 EXPECT_EQ(IFF_TUN | IFF_MULTI_QUEUE | IFF_NO_PI, ifr->ifr_flags);
64 EXPECT_THAT(ifr->ifr_name, StrEq(kDeviceName));
65 return 0;
66 }));
67 EXPECT_CALL(mock_kernel_, ioctl(_, TUNSETPERSIST, _))
68 .Times(AnyNumber())
69 .WillRepeatedly(Invoke([persist](Unused, Unused, void* argp) {
70 auto* ifr = reinterpret_cast<struct ifreq*>(argp);
71 if (persist) {
72 EXPECT_THAT(ifr->ifr_name, StrEq(kDeviceName));
73 } else {
74 EXPECT_EQ(nullptr, ifr);
75 }
76 return 0;
77 }));
78 EXPECT_CALL(mock_kernel_, ioctl(_, SIOCSIFMTU, _))
79 .Times(AnyNumber())
80 .WillRepeatedly(Invoke([mtu](Unused, Unused, void* argp) {
81 auto* ifr = reinterpret_cast<struct ifreq*>(argp);
82 EXPECT_EQ(mtu, ifr->ifr_mtu);
83 EXPECT_THAT(ifr->ifr_name, StrEq(kDeviceName));
84 return 0;
85 }));
86 }
87
88 // Expect that Up() will be called. Force the call to fail when fail == true.
ExpectUp(bool fail)89 void ExpectUp(bool fail) {
90 EXPECT_CALL(mock_kernel_, ioctl(_, SIOCSIFFLAGS, _))
91 .WillOnce(Invoke([fail](Unused, Unused, void* argp) {
92 auto* ifr = reinterpret_cast<struct ifreq*>(argp);
93 EXPECT_TRUE(ifr->ifr_flags & IFF_UP);
94 EXPECT_THAT(ifr->ifr_name, StrEq(kDeviceName));
95 if (fail) {
96 return -1;
97 } else {
98 return 0;
99 }
100 }));
101 }
102
103 // Expect that Down() will be called *after* the interface is up. Force the
104 // call to fail when fail == true.
ExpectDown(bool fail)105 void ExpectDown(bool fail) {
106 EXPECT_CALL(mock_kernel_, ioctl(_, SIOCSIFFLAGS, _))
107 .WillOnce(Invoke([fail](Unused, Unused, void* argp) {
108 auto* ifr = reinterpret_cast<struct ifreq*>(argp);
109 EXPECT_FALSE(ifr->ifr_flags & IFF_UP);
110 EXPECT_THAT(ifr->ifr_name, StrEq(kDeviceName));
111 if (fail) {
112 return -1;
113 } else {
114 return 0;
115 }
116 }));
117 }
118
119 MockKernel mock_kernel_;
120 int next_fd_ = 100;
121 };
122
123 // A TunTapDevice can be initialized and up
TEST_F(TunDeviceTest,BasicWorkFlow)124 TEST_F(TunDeviceTest, BasicWorkFlow) {
125 SetInitExpectations(/* mtu = */ 1500, /* persist = */ false);
126 TunTapDevice tun_device(kDeviceName, 1500, false, true, false, &mock_kernel_);
127 EXPECT_TRUE(tun_device.Init());
128 EXPECT_GT(tun_device.GetFileDescriptor(), -1);
129
130 ExpectUp(/* fail = */ false);
131 EXPECT_TRUE(tun_device.Up());
132 ExpectDown(/* fail = */ false);
133 }
134
TEST_F(TunDeviceTest,FailToOpenTunDevice)135 TEST_F(TunDeviceTest, FailToOpenTunDevice) {
136 SetInitExpectations(/* mtu = */ 1500, /* persist = */ false);
137 EXPECT_CALL(mock_kernel_, open(StrEq("/dev/net/tun"), _))
138 .WillOnce(Return(-1));
139 TunTapDevice tun_device(kDeviceName, 1500, false, true, false, &mock_kernel_);
140 EXPECT_FALSE(tun_device.Init());
141 EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
142 ExpectDown(false);
143 }
144
TEST_F(TunDeviceTest,FailToCheckFeature)145 TEST_F(TunDeviceTest, FailToCheckFeature) {
146 SetInitExpectations(/* mtu = */ 1500, /* persist = */ false);
147 EXPECT_CALL(mock_kernel_, ioctl(_, TUNGETFEATURES, _)).WillOnce(Return(-1));
148 TunTapDevice tun_device(kDeviceName, 1500, false, true, false, &mock_kernel_);
149 EXPECT_FALSE(tun_device.Init());
150 EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
151 ExpectDown(false);
152 }
153
TEST_F(TunDeviceTest,TooFewFeature)154 TEST_F(TunDeviceTest, TooFewFeature) {
155 SetInitExpectations(/* mtu = */ 1500, /* persist = */ false);
156 EXPECT_CALL(mock_kernel_, ioctl(_, TUNGETFEATURES, _))
157 .WillOnce(Invoke([](Unused, Unused, void* argp) {
158 int* actual_features = reinterpret_cast<int*>(argp);
159 *actual_features = IFF_TUN | IFF_ONE_QUEUE;
160 return 0;
161 }));
162 TunTapDevice tun_device(kDeviceName, 1500, false, true, false, &mock_kernel_);
163 EXPECT_FALSE(tun_device.Init());
164 EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
165 ExpectDown(false);
166 }
167
TEST_F(TunDeviceTest,FailToSetFlag)168 TEST_F(TunDeviceTest, FailToSetFlag) {
169 SetInitExpectations(/* mtu = */ 1500, /* persist = */ true);
170 EXPECT_CALL(mock_kernel_, ioctl(_, TUNSETIFF, _)).WillOnce(Return(-1));
171 TunTapDevice tun_device(kDeviceName, 1500, true, true, false, &mock_kernel_);
172 EXPECT_FALSE(tun_device.Init());
173 EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
174 }
175
TEST_F(TunDeviceTest,FailToPersistDevice)176 TEST_F(TunDeviceTest, FailToPersistDevice) {
177 SetInitExpectations(/* mtu = */ 1500, /* persist = */ true);
178 EXPECT_CALL(mock_kernel_, ioctl(_, TUNSETPERSIST, _)).WillOnce(Return(-1));
179 TunTapDevice tun_device(kDeviceName, 1500, true, true, false, &mock_kernel_);
180 EXPECT_FALSE(tun_device.Init());
181 EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
182 }
183
TEST_F(TunDeviceTest,FailToOpenSocket)184 TEST_F(TunDeviceTest, FailToOpenSocket) {
185 SetInitExpectations(/* mtu = */ 1500, /* persist = */ true);
186 EXPECT_CALL(mock_kernel_, socket(AF_INET6, _, _)).WillOnce(Return(-1));
187 TunTapDevice tun_device(kDeviceName, 1500, true, true, false, &mock_kernel_);
188 EXPECT_FALSE(tun_device.Init());
189 EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
190 }
191
TEST_F(TunDeviceTest,FailToSetMtu)192 TEST_F(TunDeviceTest, FailToSetMtu) {
193 SetInitExpectations(/* mtu = */ 1500, /* persist = */ true);
194 EXPECT_CALL(mock_kernel_, ioctl(_, SIOCSIFMTU, _)).WillOnce(Return(-1));
195 TunTapDevice tun_device(kDeviceName, 1500, true, true, false, &mock_kernel_);
196 EXPECT_FALSE(tun_device.Init());
197 EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
198 }
199
TEST_F(TunDeviceTest,FailToUp)200 TEST_F(TunDeviceTest, FailToUp) {
201 SetInitExpectations(/* mtu = */ 1500, /* persist = */ true);
202 TunTapDevice tun_device(kDeviceName, 1500, true, true, false, &mock_kernel_);
203 EXPECT_TRUE(tun_device.Init());
204 EXPECT_GT(tun_device.GetFileDescriptor(), -1);
205
206 ExpectUp(/* fail = */ true);
207 EXPECT_FALSE(tun_device.Up());
208 }
209
210 } // namespace
211 } // namespace quic::test
212