xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/qbone/bonnet/tun_device_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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