xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/qbone/bonnet/tun_device_controller.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/rtnetlink.h>
8 
9 #include "absl/time/clock.h"
10 #include "quiche/quic/platform/api/quic_logging.h"
11 #include "quiche/quic/qbone/qbone_constants.h"
12 #include "quiche/common/quiche_callbacks.h"
13 
14 ABSL_FLAG(bool, qbone_tun_device_replace_default_routing_rules, true,
15           "If true, will define a rule that points packets sourced from the "
16           "qbone interface to the qbone table. This is unnecessary in "
17           "environments with no other ipv6 route.");
18 
19 ABSL_FLAG(int, qbone_route_init_cwnd, 32,
20           "If non-zero, will add initcwnd to QBONE routing rules.  Setting "
21           "a value below 10 is dangerous and not recommended.");
22 
23 namespace quic {
24 
UpdateAddress(const IpRange & desired_range)25 bool TunDeviceController::UpdateAddress(const IpRange& desired_range) {
26   if (!setup_tun_) {
27     return true;
28   }
29 
30   NetlinkInterface::LinkInfo link_info{};
31   if (!netlink_->GetLinkInfo(ifname_, &link_info)) {
32     return false;
33   }
34 
35   std::vector<NetlinkInterface::AddressInfo> addresses;
36   if (!netlink_->GetAddresses(link_info.index, 0, &addresses, nullptr)) {
37     return false;
38   }
39 
40   QuicIpAddress desired_address = desired_range.FirstAddressInRange();
41 
42   for (const auto& address : addresses) {
43     if (!netlink_->ChangeLocalAddress(
44             link_info.index, NetlinkInterface::Verb::kRemove,
45             address.interface_address, address.prefix_length, 0, 0, {})) {
46       return false;
47     }
48   }
49 
50   bool address_updated = netlink_->ChangeLocalAddress(
51       link_info.index, NetlinkInterface::Verb::kAdd, desired_address,
52       desired_range.prefix_length(), IFA_F_PERMANENT | IFA_F_NODAD,
53       RT_SCOPE_LINK, {});
54 
55   if (address_updated) {
56     current_address_ = desired_address;
57 
58     for (const auto& cb : address_update_cbs_) {
59       cb(current_address_);
60     }
61   }
62 
63   return address_updated;
64 }
65 
UpdateRoutes(const IpRange & desired_range,const std::vector<IpRange> & desired_routes)66 bool TunDeviceController::UpdateRoutes(
67     const IpRange& desired_range, const std::vector<IpRange>& desired_routes) {
68   if (!setup_tun_) {
69     return true;
70   }
71 
72   NetlinkInterface::LinkInfo link_info{};
73   if (!netlink_->GetLinkInfo(ifname_, &link_info)) {
74     QUIC_LOG(ERROR) << "Could not get link info for interface <" << ifname_
75                     << ">";
76     return false;
77   }
78 
79   std::vector<NetlinkInterface::RoutingRule> routing_rules;
80   if (!netlink_->GetRouteInfo(&routing_rules)) {
81     QUIC_LOG(ERROR) << "Unable to get route info";
82     return false;
83   }
84 
85   for (const auto& rule : routing_rules) {
86     if (rule.out_interface == link_info.index &&
87         rule.table == QboneConstants::kQboneRouteTableId) {
88       if (!netlink_->ChangeRoute(NetlinkInterface::Verb::kRemove, rule.table,
89                                  rule.destination_subnet, rule.scope,
90                                  rule.preferred_source, rule.out_interface,
91                                  rule.init_cwnd)) {
92         QUIC_LOG(ERROR) << "Unable to remove old route to <"
93                         << rule.destination_subnet.ToString() << ">";
94         return false;
95       }
96     }
97   }
98 
99   if (!UpdateRules(desired_range)) {
100     return false;
101   }
102 
103   QuicIpAddress desired_address = desired_range.FirstAddressInRange();
104 
105   std::vector<IpRange> routes(desired_routes.begin(), desired_routes.end());
106   routes.emplace_back(*QboneConstants::TerminatorLocalAddressRange());
107 
108   for (const auto& route : routes) {
109     if (!netlink_->ChangeRoute(NetlinkInterface::Verb::kReplace,
110                                QboneConstants::kQboneRouteTableId, route,
111                                RT_SCOPE_LINK, desired_address, link_info.index,
112                                absl::GetFlag(FLAGS_qbone_route_init_cwnd))) {
113       QUIC_LOG(ERROR) << "Unable to add route <" << route.ToString() << ">";
114       return false;
115     }
116   }
117 
118   return true;
119 }
120 
UpdateRoutesWithRetries(const IpRange & desired_range,const std::vector<IpRange> & desired_routes,int retries)121 bool TunDeviceController::UpdateRoutesWithRetries(
122     const IpRange& desired_range, const std::vector<IpRange>& desired_routes,
123     int retries) {
124   while (retries-- > 0) {
125     if (UpdateRoutes(desired_range, desired_routes)) {
126       return true;
127     }
128     absl::SleepFor(absl::Milliseconds(100));
129   }
130   return false;
131 }
132 
UpdateRules(IpRange desired_range)133 bool TunDeviceController::UpdateRules(IpRange desired_range) {
134   if (!absl::GetFlag(FLAGS_qbone_tun_device_replace_default_routing_rules)) {
135     return true;
136   }
137 
138   std::vector<NetlinkInterface::IpRule> ip_rules;
139   if (!netlink_->GetRuleInfo(&ip_rules)) {
140     QUIC_LOG(ERROR) << "Unable to get rule info";
141     return false;
142   }
143 
144   for (const auto& rule : ip_rules) {
145     if (rule.table == QboneConstants::kQboneRouteTableId) {
146       if (!netlink_->ChangeRule(NetlinkInterface::Verb::kRemove, rule.table,
147                                 rule.source_range)) {
148         QUIC_LOG(ERROR) << "Unable to remove old rule for table <" << rule.table
149                         << "> from source <" << rule.source_range.ToString()
150                         << ">";
151         return false;
152       }
153     }
154   }
155 
156   if (!netlink_->ChangeRule(NetlinkInterface::Verb::kAdd,
157                             QboneConstants::kQboneRouteTableId,
158                             desired_range)) {
159     QUIC_LOG(ERROR) << "Unable to add rule for <" << desired_range.ToString()
160                     << ">";
161     return false;
162   }
163 
164   return true;
165 }
166 
current_address()167 QuicIpAddress TunDeviceController::current_address() {
168   return current_address_;
169 }
170 
RegisterAddressUpdateCallback(quiche::MultiUseCallback<void (QuicIpAddress)> cb)171 void TunDeviceController::RegisterAddressUpdateCallback(
172     quiche::MultiUseCallback<void(QuicIpAddress)> cb) {
173   address_update_cbs_.push_back(std::move(cb));
174 }
175 
176 }  // namespace quic
177