1 // Copyright (c) 2020 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_controller.h"
6
7 #include <linux/if_addr.h>
8 #include <linux/rtnetlink.h>
9
10 #include "absl/strings/string_view.h"
11 #include "quiche/quic/platform/api/quic_test.h"
12 #include "quiche/quic/qbone/platform/mock_netlink.h"
13 #include "quiche/quic/qbone/qbone_constants.h"
14
15 ABSL_DECLARE_FLAG(bool, qbone_tun_device_replace_default_routing_rules);
16 ABSL_DECLARE_FLAG(int, qbone_route_init_cwnd);
17
18 namespace quic::test {
19 namespace {
20 using ::testing::Eq;
21
22 constexpr int kIfindex = 42;
23 constexpr char kIfname[] = "qbone0";
24
__anon37bb5a990202() 25 const IpRange kIpRange = []() {
26 IpRange range;
27 QCHECK(range.FromString("2604:31c0:2::/64"));
28 return range;
29 }();
30
31 constexpr char kOldAddress[] = "1.2.3.4";
32 constexpr int kOldPrefixLen = 24;
33
34 using ::testing::_;
35 using ::testing::Invoke;
36 using ::testing::Return;
37 using ::testing::StrictMock;
38
39 MATCHER_P(IpRangeEq, range,
40 absl::StrCat("expected IpRange to equal ", range.ToString())) {
41 return arg == range;
42 }
43
44 class TunDeviceControllerTest : public QuicTest {
45 public:
TunDeviceControllerTest()46 TunDeviceControllerTest()
47 : controller_(kIfname, true, &netlink_),
48 link_local_range_(*QboneConstants::TerminatorLocalAddressRange()) {
49 controller_.RegisterAddressUpdateCallback(
50 [this](QuicIpAddress address) { notified_address_ = address; });
51 }
52
53 protected:
ExpectLinkInfo(const std::string & interface_name,int ifindex)54 void ExpectLinkInfo(const std::string& interface_name, int ifindex) {
55 EXPECT_CALL(netlink_, GetLinkInfo(interface_name, _))
56 .WillOnce(Invoke([ifindex](absl::string_view ifname,
57 NetlinkInterface::LinkInfo* link_info) {
58 link_info->index = ifindex;
59 return true;
60 }));
61 }
62
63 MockNetlink netlink_;
64 TunDeviceController controller_;
65 QuicIpAddress notified_address_;
66
67 IpRange link_local_range_;
68 };
69
TEST_F(TunDeviceControllerTest,AddressAppliedWhenNoneExisted)70 TEST_F(TunDeviceControllerTest, AddressAppliedWhenNoneExisted) {
71 ExpectLinkInfo(kIfname, kIfindex);
72
73 EXPECT_CALL(netlink_, GetAddresses(kIfindex, _, _, _)).WillOnce(Return(true));
74
75 EXPECT_CALL(netlink_,
76 ChangeLocalAddress(
77 kIfindex, NetlinkInterface::Verb::kAdd,
78 kIpRange.FirstAddressInRange(), kIpRange.prefix_length(),
79 IFA_F_PERMANENT | IFA_F_NODAD, RT_SCOPE_LINK, _))
80 .WillOnce(Return(true));
81
82 EXPECT_TRUE(controller_.UpdateAddress(kIpRange));
83 EXPECT_THAT(notified_address_, Eq(kIpRange.FirstAddressInRange()));
84 }
85
TEST_F(TunDeviceControllerTest,OldAddressesAreRemoved)86 TEST_F(TunDeviceControllerTest, OldAddressesAreRemoved) {
87 ExpectLinkInfo(kIfname, kIfindex);
88
89 EXPECT_CALL(netlink_, GetAddresses(kIfindex, _, _, _))
90 .WillOnce(Invoke([](int interface_index, uint8_t unwanted_flags,
91 std::vector<NetlinkInterface::AddressInfo>* addresses,
92 int* num_ipv6_nodad_dadfailed_addresses) {
93 NetlinkInterface::AddressInfo info{};
94 info.interface_address.FromString(kOldAddress);
95 info.prefix_length = kOldPrefixLen;
96 addresses->emplace_back(info);
97 return true;
98 }));
99
100 QuicIpAddress old_address;
101 old_address.FromString(kOldAddress);
102
103 EXPECT_CALL(netlink_,
104 ChangeLocalAddress(kIfindex, NetlinkInterface::Verb::kRemove,
105 old_address, kOldPrefixLen, _, _, _))
106 .WillOnce(Return(true));
107
108 EXPECT_CALL(netlink_,
109 ChangeLocalAddress(
110 kIfindex, NetlinkInterface::Verb::kAdd,
111 kIpRange.FirstAddressInRange(), kIpRange.prefix_length(),
112 IFA_F_PERMANENT | IFA_F_NODAD, RT_SCOPE_LINK, _))
113 .WillOnce(Return(true));
114
115 EXPECT_TRUE(controller_.UpdateAddress(kIpRange));
116 EXPECT_THAT(notified_address_, Eq(kIpRange.FirstAddressInRange()));
117 }
118
TEST_F(TunDeviceControllerTest,UpdateRoutesRemovedOldRoutes)119 TEST_F(TunDeviceControllerTest, UpdateRoutesRemovedOldRoutes) {
120 ExpectLinkInfo(kIfname, kIfindex);
121
122 const int num_matching_routes = 3;
123 EXPECT_CALL(netlink_, GetRouteInfo(_))
124 .WillOnce(
125 Invoke([](std::vector<NetlinkInterface::RoutingRule>* routing_rules) {
126 NetlinkInterface::RoutingRule non_matching_route{};
127 non_matching_route.table = QboneConstants::kQboneRouteTableId;
128 non_matching_route.out_interface = kIfindex + 1;
129 routing_rules->push_back(non_matching_route);
130
131 NetlinkInterface::RoutingRule matching_route{};
132 matching_route.table = QboneConstants::kQboneRouteTableId;
133 matching_route.out_interface = kIfindex;
134 matching_route.init_cwnd = NetlinkInterface::kUnspecifiedInitCwnd;
135 for (int i = 0; i < num_matching_routes; i++) {
136 routing_rules->push_back(matching_route);
137 }
138
139 NetlinkInterface::RoutingRule non_matching_table{};
140 non_matching_table.table = QboneConstants::kQboneRouteTableId + 1;
141 non_matching_table.out_interface = kIfindex;
142 routing_rules->push_back(non_matching_table);
143 return true;
144 }));
145
146 EXPECT_CALL(netlink_,
147 ChangeRoute(NetlinkInterface::Verb::kRemove,
148 QboneConstants::kQboneRouteTableId, _, _, _, kIfindex,
149 NetlinkInterface::kUnspecifiedInitCwnd))
150 .Times(num_matching_routes)
151 .WillRepeatedly(Return(true));
152
153 EXPECT_CALL(netlink_, GetRuleInfo(_)).WillOnce(Return(true));
154
155 EXPECT_CALL(netlink_, ChangeRule(NetlinkInterface::Verb::kAdd,
156 QboneConstants::kQboneRouteTableId,
157 IpRangeEq(kIpRange)))
158 .WillOnce(Return(true));
159
160 EXPECT_CALL(netlink_,
161 ChangeRoute(NetlinkInterface::Verb::kReplace,
162 QboneConstants::kQboneRouteTableId,
163 IpRangeEq(link_local_range_), _, _, kIfindex, _))
164 .WillOnce(Return(true));
165
166 EXPECT_TRUE(controller_.UpdateRoutes(kIpRange, {}));
167 }
168
TEST_F(TunDeviceControllerTest,UpdateRoutesAddsNewRoutes)169 TEST_F(TunDeviceControllerTest, UpdateRoutesAddsNewRoutes) {
170 ExpectLinkInfo(kIfname, kIfindex);
171
172 EXPECT_CALL(netlink_, GetRouteInfo(_)).WillOnce(Return(true));
173
174 EXPECT_CALL(netlink_, GetRuleInfo(_)).WillOnce(Return(true));
175
176 absl::SetFlag(&FLAGS_qbone_route_init_cwnd, 32);
177 EXPECT_CALL(netlink_, ChangeRoute(NetlinkInterface::Verb::kReplace,
178 QboneConstants::kQboneRouteTableId,
179 IpRangeEq(kIpRange), _, _, kIfindex,
180 absl::GetFlag(FLAGS_qbone_route_init_cwnd)))
181 .Times(2)
182 .WillRepeatedly(Return(true))
183 .RetiresOnSaturation();
184
185 EXPECT_CALL(netlink_, ChangeRule(NetlinkInterface::Verb::kAdd,
186 QboneConstants::kQboneRouteTableId,
187 IpRangeEq(kIpRange)))
188 .WillOnce(Return(true));
189
190 EXPECT_CALL(netlink_,
191 ChangeRoute(NetlinkInterface::Verb::kReplace,
192 QboneConstants::kQboneRouteTableId,
193 IpRangeEq(link_local_range_), _, _, kIfindex, _))
194 .WillOnce(Return(true));
195
196 EXPECT_TRUE(controller_.UpdateRoutes(kIpRange, {kIpRange, kIpRange}));
197 }
198
TEST_F(TunDeviceControllerTest,EmptyUpdateRouteKeepsLinkLocalRoute)199 TEST_F(TunDeviceControllerTest, EmptyUpdateRouteKeepsLinkLocalRoute) {
200 ExpectLinkInfo(kIfname, kIfindex);
201
202 EXPECT_CALL(netlink_, GetRouteInfo(_)).WillOnce(Return(true));
203
204 EXPECT_CALL(netlink_, GetRuleInfo(_)).WillOnce(Return(true));
205
206 EXPECT_CALL(netlink_, ChangeRule(NetlinkInterface::Verb::kAdd,
207 QboneConstants::kQboneRouteTableId,
208 IpRangeEq(kIpRange)))
209 .WillOnce(Return(true));
210
211 EXPECT_CALL(netlink_,
212 ChangeRoute(NetlinkInterface::Verb::kReplace,
213 QboneConstants::kQboneRouteTableId,
214 IpRangeEq(link_local_range_), _, _, kIfindex, _))
215 .WillOnce(Return(true));
216
217 EXPECT_TRUE(controller_.UpdateRoutes(kIpRange, {}));
218 }
219
TEST_F(TunDeviceControllerTest,DisablingRoutingRulesSkipsRuleCreation)220 TEST_F(TunDeviceControllerTest, DisablingRoutingRulesSkipsRuleCreation) {
221 absl::SetFlag(&FLAGS_qbone_tun_device_replace_default_routing_rules, false);
222 ExpectLinkInfo(kIfname, kIfindex);
223
224 EXPECT_CALL(netlink_, GetRouteInfo(_)).WillOnce(Return(true));
225
226 EXPECT_CALL(netlink_, ChangeRoute(NetlinkInterface::Verb::kReplace,
227 QboneConstants::kQboneRouteTableId,
228 IpRangeEq(kIpRange), _, _, kIfindex, _))
229 .Times(2)
230 .WillRepeatedly(Return(true))
231 .RetiresOnSaturation();
232
233 EXPECT_CALL(netlink_,
234 ChangeRoute(NetlinkInterface::Verb::kReplace,
235 QboneConstants::kQboneRouteTableId,
236 IpRangeEq(link_local_range_), _, _, kIfindex, _))
237 .WillOnce(Return(true));
238
239 EXPECT_TRUE(controller_.UpdateRoutes(kIpRange, {kIpRange, kIpRange}));
240 }
241
242 class DisabledTunDeviceControllerTest : public QuicTest {
243 public:
DisabledTunDeviceControllerTest()244 DisabledTunDeviceControllerTest()
245 : controller_(kIfname, false, &netlink_),
246 link_local_range_(*QboneConstants::TerminatorLocalAddressRange()) {}
247
248 StrictMock<MockNetlink> netlink_;
249 TunDeviceController controller_;
250
251 IpRange link_local_range_;
252 };
253
TEST_F(DisabledTunDeviceControllerTest,UpdateRoutesIsNop)254 TEST_F(DisabledTunDeviceControllerTest, UpdateRoutesIsNop) {
255 EXPECT_THAT(controller_.UpdateRoutes(kIpRange, {}), Eq(true));
256 }
257
TEST_F(DisabledTunDeviceControllerTest,UpdateAddressIsNop)258 TEST_F(DisabledTunDeviceControllerTest, UpdateAddressIsNop) {
259 EXPECT_THAT(controller_.UpdateAddress(kIpRange), Eq(true));
260 }
261
262 } // namespace
263 } // namespace quic::test
264