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