No public description PiperOrigin-RevId: 639187590
diff --git a/quiche/quic/qbone/bonnet/tun_device_controller.cc b/quiche/quic/qbone/bonnet/tun_device_controller.cc index 97a6361..5169a77 100644 --- a/quiche/quic/qbone/bonnet/tun_device_controller.cc +++ b/quiche/quic/qbone/bonnet/tun_device_controller.cc
@@ -9,7 +9,6 @@ #include <utility> #include <vector> -#include "absl/flags/flag.h" #include "absl/time/clock.h" #include "quiche/quic/platform/api/quic_logging.h" #include "quiche/quic/qbone/qbone_constants.h" @@ -20,8 +19,9 @@ "qbone interface to the qbone table. This is unnecessary in " "environments with no other ipv6 route."); -ABSL_RETIRED_FLAG(int, qbone_route_init_cwnd, 0, - "Deprecated. Code no longer modifies initcwnd."); +ABSL_FLAG(int, qbone_route_init_cwnd, 0, + "If non-zero, will add initcwnd to QBONE routing rules. Setting " + "a value below 10 is dangerous and not recommended."); namespace quic { @@ -90,7 +90,8 @@ rule.table == QboneConstants::kQboneRouteTableId) { if (!netlink_->ChangeRoute(NetlinkInterface::Verb::kRemove, rule.table, rule.destination_subnet, rule.scope, - rule.preferred_source, rule.out_interface)) { + rule.preferred_source, rule.out_interface, + rule.init_cwnd)) { QUIC_LOG(ERROR) << "Unable to remove old route to <" << rule.destination_subnet.ToString() << ">"; return false; @@ -110,8 +111,8 @@ for (const auto& route : routes) { if (!netlink_->ChangeRoute(NetlinkInterface::Verb::kReplace, QboneConstants::kQboneRouteTableId, route, - RT_SCOPE_LINK, desired_address, - link_info.index)) { + RT_SCOPE_LINK, desired_address, link_info.index, + absl::GetFlag(FLAGS_qbone_route_init_cwnd))) { QUIC_LOG(ERROR) << "Unable to add route <" << route.ToString() << ">"; return false; }
diff --git a/quiche/quic/qbone/bonnet/tun_device_controller_test.cc b/quiche/quic/qbone/bonnet/tun_device_controller_test.cc index 58a57d0..fd15f31 100644 --- a/quiche/quic/qbone/bonnet/tun_device_controller_test.cc +++ b/quiche/quic/qbone/bonnet/tun_device_controller_test.cc
@@ -134,6 +134,7 @@ NetlinkInterface::RoutingRule matching_route{}; matching_route.table = QboneConstants::kQboneRouteTableId; matching_route.out_interface = kIfindex; + matching_route.init_cwnd = NetlinkInterface::kUnspecifiedInitCwnd; for (int i = 0; i < num_matching_routes; i++) { routing_rules->push_back(matching_route); } @@ -145,9 +146,10 @@ return true; })); - EXPECT_CALL(netlink_, ChangeRoute(NetlinkInterface::Verb::kRemove, - QboneConstants::kQboneRouteTableId, _, _, _, - kIfindex)) + EXPECT_CALL(netlink_, + ChangeRoute(NetlinkInterface::Verb::kRemove, + QboneConstants::kQboneRouteTableId, _, _, _, kIfindex, + NetlinkInterface::kUnspecifiedInitCwnd)) .Times(num_matching_routes) .WillRepeatedly(Return(true)); @@ -161,7 +163,7 @@ EXPECT_CALL(netlink_, ChangeRoute(NetlinkInterface::Verb::kReplace, QboneConstants::kQboneRouteTableId, - IpRangeEq(link_local_range_), _, _, kIfindex)) + IpRangeEq(link_local_range_), _, _, kIfindex, _)) .WillOnce(Return(true)); EXPECT_TRUE(controller_.UpdateRoutes(kIpRange, {})); @@ -174,9 +176,11 @@ EXPECT_CALL(netlink_, GetRuleInfo(_)).WillOnce(Return(true)); + absl::SetFlag(&FLAGS_qbone_route_init_cwnd, 32); EXPECT_CALL(netlink_, ChangeRoute(NetlinkInterface::Verb::kReplace, QboneConstants::kQboneRouteTableId, - IpRangeEq(kIpRange), _, _, kIfindex)) + IpRangeEq(kIpRange), _, _, kIfindex, + absl::GetFlag(FLAGS_qbone_route_init_cwnd))) .Times(2) .WillRepeatedly(Return(true)) .RetiresOnSaturation(); @@ -189,7 +193,7 @@ EXPECT_CALL(netlink_, ChangeRoute(NetlinkInterface::Verb::kReplace, QboneConstants::kQboneRouteTableId, - IpRangeEq(link_local_range_), _, _, kIfindex)) + IpRangeEq(link_local_range_), _, _, kIfindex, _)) .WillOnce(Return(true)); EXPECT_TRUE(controller_.UpdateRoutes(kIpRange, {kIpRange, kIpRange})); @@ -210,7 +214,7 @@ EXPECT_CALL(netlink_, ChangeRoute(NetlinkInterface::Verb::kReplace, QboneConstants::kQboneRouteTableId, - IpRangeEq(link_local_range_), _, _, kIfindex)) + IpRangeEq(link_local_range_), _, _, kIfindex, _)) .WillOnce(Return(true)); EXPECT_TRUE(controller_.UpdateRoutes(kIpRange, {})); @@ -224,7 +228,7 @@ EXPECT_CALL(netlink_, ChangeRoute(NetlinkInterface::Verb::kReplace, QboneConstants::kQboneRouteTableId, - IpRangeEq(kIpRange), _, _, kIfindex)) + IpRangeEq(kIpRange), _, _, kIfindex, _)) .Times(2) .WillRepeatedly(Return(true)) .RetiresOnSaturation(); @@ -232,7 +236,7 @@ EXPECT_CALL(netlink_, ChangeRoute(NetlinkInterface::Verb::kReplace, QboneConstants::kQboneRouteTableId, - IpRangeEq(link_local_range_), _, _, kIfindex)) + IpRangeEq(link_local_range_), _, _, kIfindex, _)) .WillOnce(Return(true)); EXPECT_TRUE(controller_.UpdateRoutes(kIpRange, {kIpRange, kIpRange}));
diff --git a/quiche/quic/qbone/platform/mock_netlink.h b/quiche/quic/qbone/platform/mock_netlink.h index 6e33d9c..72e3b66 100644 --- a/quiche/quic/qbone/platform/mock_netlink.h +++ b/quiche/quic/qbone/platform/mock_netlink.h
@@ -25,7 +25,8 @@ MOCK_METHOD(bool, GetRouteInfo, (std::vector<RoutingRule>*), (override)); MOCK_METHOD(bool, ChangeRoute, - (Verb, uint32_t, const IpRange&, uint8_t, QuicIpAddress, int32_t), + (Verb, uint32_t, const IpRange&, uint8_t, QuicIpAddress, int32_t, + uint32_t), (override)); MOCK_METHOD(bool, GetRuleInfo, (std::vector<IpRule>*), (override));
diff --git a/quiche/quic/qbone/platform/netlink.cc b/quiche/quic/qbone/platform/netlink.cc index 6ebc669..04567d9 100644 --- a/quiche/quic/qbone/platform/netlink.cc +++ b/quiche/quic/qbone/platform/netlink.cc
@@ -425,6 +425,7 @@ Netlink::RoutingRule rule; rule.scope = route->rtm_scope; rule.table = route->rtm_table; + rule.init_cwnd = Netlink::kUnspecifiedInitCwnd; struct rtattr* rta; for (rta = RTM_RTA(route); RTA_OK(rta, payload_length); @@ -451,6 +452,25 @@ rule.out_interface = *reinterpret_cast<int*>(RTA_DATA(rta)); break; } + case RTA_METRICS: { + struct rtattr* rtax; + int rta_payload_length = RTA_PAYLOAD(rta); + for (rtax = reinterpret_cast<struct rtattr*>(RTA_DATA(rta)); + RTA_OK(rtax, rta_payload_length); + rtax = RTA_NEXT(rtax, rta_payload_length)) { + switch (rtax->rta_type) { + case RTAX_INITCWND: { + rule.init_cwnd = *reinterpret_cast<uint32_t*>(RTA_DATA(rtax)); + break; + } + default: { + QUIC_VLOG(2) << absl::StrCat( + "Uninteresting RTA_METRICS attribute: ", rtax->rta_type); + } + } + } + break; + } default: { QUIC_VLOG(2) << absl::StrCat("Uninteresting attribute: ", rta->rta_type); @@ -492,7 +512,7 @@ bool Netlink::ChangeRoute(Netlink::Verb verb, uint32_t table, const IpRange& destination_subnet, uint8_t scope, QuicIpAddress preferred_source, - int32_t interface_index) { + int32_t interface_index, uint32_t init_cwnd) { if (!destination_subnet.prefix().IsInitialized()) { return false; } @@ -554,6 +574,15 @@ message.AppendAttribute(RTA_TABLE, &table, sizeof(table)); + if (init_cwnd != kUnspecifiedInitCwnd) { + char data[RTA_LENGTH(sizeof(uint32_t))]; + struct rtattr* rta = reinterpret_cast<struct rtattr*>(data); + rta->rta_type = RTAX_INITCWND; + rta->rta_len = sizeof(data); + *reinterpret_cast<uint32_t*>(RTA_DATA(rta)) = init_cwnd; + message.AppendAttribute(RTA_METRICS, data, sizeof(data)); + } + // RTA_OIF is the target interface for this rule. message.AppendAttribute(RTA_OIF, &interface_index, sizeof(interface_index)); // The actual destination subnet must be truncated of all the tailing zeros.
diff --git a/quiche/quic/qbone/platform/netlink.h b/quiche/quic/qbone/platform/netlink.h index 27a341a..857b8bf 100644 --- a/quiche/quic/qbone/platform/netlink.h +++ b/quiche/quic/qbone/platform/netlink.h
@@ -88,8 +88,8 @@ // matching rule is found, a new entry will be created. bool ChangeRoute(Netlink::Verb verb, uint32_t table, const IpRange& destination_subnet, uint8_t scope, - QuicIpAddress preferred_source, - int32_t interface_index) override; + QuicIpAddress preferred_source, int32_t interface_index, + uint32_t init_cwnd) override; // Returns the set of all rules in the routing policy database. bool GetRuleInfo(std::vector<Netlink::IpRule>* ip_rules) override;
diff --git a/quiche/quic/qbone/platform/netlink_interface.h b/quiche/quic/qbone/platform/netlink_interface.h index 4bbde21..c4fc42c 100644 --- a/quiche/quic/qbone/platform/netlink_interface.h +++ b/quiche/quic/qbone/platform/netlink_interface.h
@@ -73,6 +73,8 @@ uint8_t prefix_length, uint8_t ifa_flags, uint8_t ifa_scope, const std::vector<struct rtattr*>& additional_attributes) = 0; + static constexpr uint32_t kUnspecifiedInitCwnd = 0; + // Routing rule reported back from GetRouteInfo. struct RoutingRule { uint32_t table; @@ -80,6 +82,7 @@ QuicIpAddress preferred_source; uint8_t scope; int out_interface; + uint32_t init_cwnd; // kUnspecifiedInitCwnd if unspecified }; struct IpRule { @@ -109,7 +112,7 @@ virtual bool ChangeRoute(Verb verb, uint32_t table, const IpRange& destination_subnet, uint8_t scope, QuicIpAddress preferred_source, - int32_t interface_index) = 0; + int32_t interface_index, uint32_t init_cwnd) = 0; // Returns the set of all rules in the routing policy database. virtual bool GetRuleInfo(std::vector<IpRule>* ip_rules) = 0;
diff --git a/quiche/quic/qbone/platform/netlink_test.cc b/quiche/quic/qbone/platform/netlink_test.cc index e1f57c5..ad159c5 100644 --- a/quiche/quic/qbone/platform/netlink_test.cc +++ b/quiche/quic/qbone/platform/netlink_test.cc
@@ -208,7 +208,8 @@ unsigned char destination_length, unsigned char source_length, unsigned char tos, unsigned char table, unsigned char protocol, unsigned char scope, unsigned char type, unsigned int flags, - QuicIpAddress destination, int interface_index) { + QuicIpAddress destination, int interface_index, + int init_cwnd) { auto* msg = reinterpret_cast<struct rtmsg*>(NLMSG_DATA(nlm)); msg->rtm_family = family; msg->rtm_dst_len = destination_length; @@ -227,6 +228,16 @@ // Add egress interface AddRTA(nlm, RTA_OIF, &interface_index, sizeof(interface_index)); + + // Add initcwnd + if (init_cwnd > 0) { + char data[RTA_LENGTH(sizeof(uint32_t))]; + struct rtattr* rta = reinterpret_cast<struct rtattr*>(data); + rta->rta_len = sizeof(data); + rta->rta_type = RTA_METRICS; + *reinterpret_cast<uint32_t*>(RTA_DATA(rta)) = init_cwnd; + AddRTA(nlm, RTA_METRICS, data, sizeof(data)); + } } TEST_F(NetlinkTest, GetLinkInfoWorks) { @@ -478,7 +489,7 @@ buf, nullptr, RTM_NEWROUTE, seq); CreateRtmsg(netlink_message, AF_INET6, 48, 0, 0, RT_TABLE_MAIN, RTPROT_STATIC, RT_SCOPE_LINK, - RTN_UNICAST, 0, destination, 7); + RTN_UNICAST, 0, destination, 7, 0); ret += NLMSG_ALIGN(netlink_message->nlmsg_len); netlink_message = CreateNetlinkMessage( @@ -498,6 +509,7 @@ routing_rules[0].destination_subnet.ToString()); EXPECT_FALSE(routing_rules[0].preferred_source.IsInitialized()); EXPECT_EQ(7, routing_rules[0].out_interface); + EXPECT_EQ(0, routing_rules[0].init_cwnd); } TEST_F(NetlinkTest, ChangeRouteAdd) { @@ -508,6 +520,7 @@ IpRange subnet; subnet.FromString("ff80:dead:beef::/48"); int egress_interface_index = 7; + uint32_t init_cwnd = 32; ExpectNetlinkPacket( RTM_NEWROUTE, NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL, [](void* buf, size_t len, int seq) { @@ -520,8 +533,8 @@ netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); return netlink_message->nlmsg_len; }, - [preferred_ip, subnet, egress_interface_index](const void* buf, - size_t len) { + [preferred_ip, subnet, egress_interface_index, init_cwnd](const void* buf, + size_t len) { auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf); auto* rtm = reinterpret_cast<const struct rtmsg*>(NLMSG_DATA(netlink_message)); @@ -579,16 +592,25 @@ QboneConstants::kQboneRouteTableId); break; } + case RTA_METRICS: { + struct rtattr* rtax = + reinterpret_cast<struct rtattr*>(RTA_DATA(rta)); + ASSERT_EQ(rtax->rta_type, RTAX_INITCWND); + ASSERT_EQ(rtax->rta_len, RTA_LENGTH(sizeof(uint32_t))); + ASSERT_EQ(*reinterpret_cast<uint32_t*>(RTA_DATA(rtax)), + init_cwnd); + break; + } default: EXPECT_TRUE(false) << "Seeing rtattr that should not be sent"; } ++num_rta; } - EXPECT_EQ(5, num_rta); + EXPECT_EQ(6, num_rta); }); EXPECT_TRUE(netlink->ChangeRoute( Netlink::Verb::kAdd, QboneConstants::kQboneRouteTableId, subnet, - RT_SCOPE_LINK, preferred_ip, egress_interface_index)); + RT_SCOPE_LINK, preferred_ip, egress_interface_index, init_cwnd)); } TEST_F(NetlinkTest, ChangeRouteRemove) { @@ -670,7 +692,8 @@ }); EXPECT_TRUE(netlink->ChangeRoute( Netlink::Verb::kRemove, QboneConstants::kQboneRouteTableId, subnet, - RT_SCOPE_LINK, preferred_ip, egress_interface_index)); + RT_SCOPE_LINK, preferred_ip, egress_interface_index, + Netlink::kUnspecifiedInitCwnd)); } TEST_F(NetlinkTest, ChangeRouteReplace) { @@ -761,7 +784,8 @@ }); EXPECT_TRUE(netlink->ChangeRoute( Netlink::Verb::kReplace, QboneConstants::kQboneRouteTableId, subnet, - RT_SCOPE_LINK, preferred_ip, egress_interface_index)); + RT_SCOPE_LINK, preferred_ip, egress_interface_index, + Netlink::kUnspecifiedInitCwnd)); } } // namespace