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/platform/netlink.h"
6
7 #include <utility>
8
9 #include "absl/container/node_hash_set.h"
10 #include "quiche/quic/platform/api/quic_bug_tracker.h"
11 #include "quiche/quic/platform/api/quic_test.h"
12 #include "quiche/quic/qbone/platform/mock_kernel.h"
13 #include "quiche/quic/qbone/qbone_constants.h"
14
15 namespace quic::test {
16 namespace {
17
18 using ::testing::_;
19 using ::testing::Contains;
20 using ::testing::InSequence;
21 using ::testing::Invoke;
22 using ::testing::Return;
23 using ::testing::Unused;
24
25 const int kSocketFd = 101;
26
27 class NetlinkTest : public QuicTest {
28 protected:
NetlinkTest()29 NetlinkTest() {
30 ON_CALL(mock_kernel_, socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE))
31 .WillByDefault(Invoke([this](Unused, Unused, Unused) {
32 EXPECT_CALL(mock_kernel_, close(kSocketFd)).WillOnce(Return(0));
33 return kSocketFd;
34 }));
35 }
36
ExpectNetlinkPacket(uint16_t type,uint16_t flags,const std::function<ssize_t (void * buf,size_t len,int seq)> & recv_callback,const std::function<void (const void * buf,size_t len)> & send_callback=nullptr)37 void ExpectNetlinkPacket(
38 uint16_t type, uint16_t flags,
39 const std::function<ssize_t(void* buf, size_t len, int seq)>&
40 recv_callback,
41 const std::function<void(const void* buf, size_t len)>& send_callback =
42 nullptr) {
43 static int seq = -1;
44 InSequence s;
45
46 EXPECT_CALL(mock_kernel_, sendmsg(kSocketFd, _, _))
47 .WillOnce(Invoke([type, flags, send_callback](
48 Unused, const struct msghdr* msg, int) {
49 EXPECT_EQ(sizeof(struct sockaddr_nl), msg->msg_namelen);
50 auto* nl_addr =
51 reinterpret_cast<const struct sockaddr_nl*>(msg->msg_name);
52 EXPECT_EQ(AF_NETLINK, nl_addr->nl_family);
53 EXPECT_EQ(0, nl_addr->nl_pid);
54 EXPECT_EQ(0, nl_addr->nl_groups);
55
56 EXPECT_GE(msg->msg_iovlen, 1);
57 EXPECT_GE(msg->msg_iov[0].iov_len, sizeof(struct nlmsghdr));
58
59 std::string buf;
60 for (int i = 0; i < msg->msg_iovlen; i++) {
61 buf.append(
62 std::string(reinterpret_cast<char*>(msg->msg_iov[i].iov_base),
63 msg->msg_iov[i].iov_len));
64 }
65
66 auto* netlink_message =
67 reinterpret_cast<const struct nlmsghdr*>(buf.c_str());
68 EXPECT_EQ(type, netlink_message->nlmsg_type);
69 EXPECT_EQ(flags, netlink_message->nlmsg_flags);
70 EXPECT_GE(buf.size(), netlink_message->nlmsg_len);
71
72 if (send_callback != nullptr) {
73 send_callback(buf.c_str(), buf.size());
74 }
75
76 QUICHE_CHECK_EQ(seq, -1);
77 seq = netlink_message->nlmsg_seq;
78 return buf.size();
79 }));
80
81 EXPECT_CALL(mock_kernel_,
82 recvfrom(kSocketFd, _, 0, MSG_PEEK | MSG_TRUNC, _, _))
83 .WillOnce(Invoke([this, recv_callback](Unused, Unused, Unused, Unused,
84 struct sockaddr* src_addr,
85 socklen_t* addrlen) {
86 auto* nl_addr = reinterpret_cast<struct sockaddr_nl*>(src_addr);
87 nl_addr->nl_family = AF_NETLINK;
88 nl_addr->nl_pid = 0; // from kernel
89 nl_addr->nl_groups = 0; // no multicast
90
91 int ret = recv_callback(reply_packet_, sizeof(reply_packet_), seq);
92 QUICHE_CHECK_LE(ret, sizeof(reply_packet_));
93 return ret;
94 }));
95
96 EXPECT_CALL(mock_kernel_, recvfrom(kSocketFd, _, _, _, _, _))
97 .WillOnce(Invoke([recv_callback](Unused, void* buf, size_t len, Unused,
98 struct sockaddr* src_addr,
99 socklen_t* addrlen) {
100 auto* nl_addr = reinterpret_cast<struct sockaddr_nl*>(src_addr);
101 nl_addr->nl_family = AF_NETLINK;
102 nl_addr->nl_pid = 0; // from kernel
103 nl_addr->nl_groups = 0; // no multicast
104
105 int ret = recv_callback(buf, len, seq);
106 EXPECT_GE(len, ret);
107 seq = -1;
108 return ret;
109 }));
110 }
111
112 char reply_packet_[4096];
113 MockKernel mock_kernel_;
114 };
115
AddRTA(struct nlmsghdr * netlink_message,uint16_t type,const void * data,size_t len)116 void AddRTA(struct nlmsghdr* netlink_message, uint16_t type, const void* data,
117 size_t len) {
118 auto* next_header_ptr = reinterpret_cast<char*>(netlink_message) +
119 NLMSG_ALIGN(netlink_message->nlmsg_len);
120
121 auto* rta = reinterpret_cast<struct rtattr*>(next_header_ptr);
122 rta->rta_type = type;
123 rta->rta_len = RTA_LENGTH(len);
124 memcpy(RTA_DATA(rta), data, len);
125
126 netlink_message->nlmsg_len =
127 NLMSG_ALIGN(netlink_message->nlmsg_len) + RTA_LENGTH(len);
128 }
129
CreateIfinfomsg(struct nlmsghdr * netlink_message,const std::string & interface_name,uint16_t type,int index,unsigned int flags,unsigned int change,uint8_t address[],int address_len,uint8_t broadcast[],int broadcast_len)130 void CreateIfinfomsg(struct nlmsghdr* netlink_message,
131 const std::string& interface_name, uint16_t type,
132 int index, unsigned int flags, unsigned int change,
133 uint8_t address[], int address_len, uint8_t broadcast[],
134 int broadcast_len) {
135 auto* interface_info =
136 reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(netlink_message));
137 interface_info->ifi_family = AF_UNSPEC;
138 interface_info->ifi_type = type;
139 interface_info->ifi_index = index;
140 interface_info->ifi_flags = flags;
141 interface_info->ifi_change = change;
142 netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
143
144 // Add address
145 AddRTA(netlink_message, IFLA_ADDRESS, address, address_len);
146
147 // Add broadcast address
148 AddRTA(netlink_message, IFLA_BROADCAST, broadcast, broadcast_len);
149
150 // Add name
151 AddRTA(netlink_message, IFLA_IFNAME, interface_name.c_str(),
152 interface_name.size());
153 }
154
CreateNetlinkMessage(void * buf,struct nlmsghdr * previous_netlink_message,uint16_t type,int seq)155 struct nlmsghdr* CreateNetlinkMessage(void* buf, // NOLINT
156 struct nlmsghdr* previous_netlink_message,
157 uint16_t type, int seq) {
158 auto* next_header_ptr = reinterpret_cast<char*>(buf);
159 if (previous_netlink_message != nullptr) {
160 next_header_ptr = reinterpret_cast<char*>(previous_netlink_message) +
161 NLMSG_ALIGN(previous_netlink_message->nlmsg_len);
162 }
163 auto* netlink_message = reinterpret_cast<nlmsghdr*>(next_header_ptr);
164 netlink_message->nlmsg_len = NLMSG_LENGTH(0);
165 netlink_message->nlmsg_type = type;
166 netlink_message->nlmsg_flags = NLM_F_MULTI;
167 netlink_message->nlmsg_pid = 0; // from the kernel
168 netlink_message->nlmsg_seq = seq;
169
170 return netlink_message;
171 }
172
CreateIfaddrmsg(struct nlmsghdr * nlm,int interface_index,unsigned char prefixlen,unsigned char flags,unsigned char scope,QuicIpAddress ip)173 void CreateIfaddrmsg(struct nlmsghdr* nlm, int interface_index,
174 unsigned char prefixlen, unsigned char flags,
175 unsigned char scope, QuicIpAddress ip) {
176 QUICHE_CHECK(ip.IsInitialized());
177 unsigned char family;
178 switch (ip.address_family()) {
179 case IpAddressFamily::IP_V4:
180 family = AF_INET;
181 break;
182 case IpAddressFamily::IP_V6:
183 family = AF_INET6;
184 break;
185 default:
186 QUIC_BUG(quic_bug_11034_1)
187 << absl::StrCat("unexpected address family: ", ip.address_family());
188 family = AF_UNSPEC;
189 }
190 auto* msg = reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(nlm));
191 msg->ifa_family = family;
192 msg->ifa_prefixlen = prefixlen;
193 msg->ifa_flags = flags;
194 msg->ifa_scope = scope;
195 msg->ifa_index = interface_index;
196 nlm->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
197
198 // Add local address
199 AddRTA(nlm, IFA_LOCAL, ip.ToPackedString().c_str(),
200 ip.ToPackedString().size());
201 }
202
CreateRtmsg(struct nlmsghdr * nlm,unsigned char family,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,int init_cwnd)203 void CreateRtmsg(struct nlmsghdr* nlm, unsigned char family,
204 unsigned char destination_length, unsigned char source_length,
205 unsigned char tos, unsigned char table, unsigned char protocol,
206 unsigned char scope, unsigned char type, unsigned int flags,
207 QuicIpAddress destination, int interface_index,
208 int init_cwnd) {
209 auto* msg = reinterpret_cast<struct rtmsg*>(NLMSG_DATA(nlm));
210 msg->rtm_family = family;
211 msg->rtm_dst_len = destination_length;
212 msg->rtm_src_len = source_length;
213 msg->rtm_tos = tos;
214 msg->rtm_table = table;
215 msg->rtm_protocol = protocol;
216 msg->rtm_scope = scope;
217 msg->rtm_type = type;
218 msg->rtm_flags = flags;
219 nlm->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
220
221 // Add destination
222 AddRTA(nlm, RTA_DST, destination.ToPackedString().c_str(),
223 destination.ToPackedString().size());
224
225 // Add egress interface
226 AddRTA(nlm, RTA_OIF, &interface_index, sizeof(interface_index));
227
228 // Add initcwnd
229 if (init_cwnd > 0) {
230 char data[RTA_LENGTH(sizeof(uint32_t))];
231 struct rtattr* rta = reinterpret_cast<struct rtattr*>(data);
232 rta->rta_len = sizeof(data);
233 rta->rta_type = RTA_METRICS;
234 *reinterpret_cast<uint32_t*>(RTA_DATA(rta)) = init_cwnd;
235 AddRTA(nlm, RTA_METRICS, data, sizeof(data));
236 }
237 }
238
TEST_F(NetlinkTest,GetLinkInfoWorks)239 TEST_F(NetlinkTest, GetLinkInfoWorks) {
240 auto netlink = std::make_unique<Netlink>(&mock_kernel_);
241
242 uint8_t hwaddr[] = {'a', 'b', 'c', 'd', 'e', 'f'};
243 uint8_t bcaddr[] = {'c', 'b', 'a', 'f', 'e', 'd'};
244
245 ExpectNetlinkPacket(
246 RTM_GETLINK, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST,
247 [&hwaddr, &bcaddr](void* buf, size_t len, int seq) {
248 int ret = 0;
249
250 struct nlmsghdr* netlink_message =
251 CreateNetlinkMessage(buf, nullptr, RTM_NEWLINK, seq);
252 CreateIfinfomsg(netlink_message, "tun0", /* type = */ 1,
253 /* index = */ 7,
254 /* flags = */ 0,
255 /* change = */ 0xFFFFFFFF, hwaddr, 6, bcaddr, 6);
256 ret += NLMSG_ALIGN(netlink_message->nlmsg_len);
257
258 netlink_message =
259 CreateNetlinkMessage(buf, netlink_message, NLMSG_DONE, seq);
260 ret += NLMSG_ALIGN(netlink_message->nlmsg_len);
261
262 return ret;
263 });
264
265 Netlink::LinkInfo link_info;
266 EXPECT_TRUE(netlink->GetLinkInfo("tun0", &link_info));
267
268 EXPECT_EQ(7, link_info.index);
269 EXPECT_EQ(1, link_info.type);
270
271 for (int i = 0; i < link_info.hardware_address_length; ++i) {
272 EXPECT_EQ(hwaddr[i], link_info.hardware_address[i]);
273 }
274 for (int i = 0; i < link_info.broadcast_address_length; ++i) {
275 EXPECT_EQ(bcaddr[i], link_info.broadcast_address[i]);
276 }
277 }
278
TEST_F(NetlinkTest,GetAddressesWorks)279 TEST_F(NetlinkTest, GetAddressesWorks) {
280 auto netlink = std::make_unique<Netlink>(&mock_kernel_);
281
282 absl::node_hash_set<std::string> addresses = {
283 QuicIpAddress::Any4().ToString(), QuicIpAddress::Any6().ToString()};
284
285 ExpectNetlinkPacket(
286 RTM_GETADDR, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST,
287 [&addresses](void* buf, size_t len, int seq) {
288 int ret = 0;
289
290 struct nlmsghdr* nlm = nullptr;
291
292 for (const auto& address : addresses) {
293 QuicIpAddress ip;
294 ip.FromString(address);
295 nlm = CreateNetlinkMessage(buf, nlm, RTM_NEWADDR, seq);
296 CreateIfaddrmsg(nlm, /* interface_index = */ 7, /* prefixlen = */ 24,
297 /* flags = */ 0, /* scope = */ RT_SCOPE_UNIVERSE, ip);
298
299 ret += NLMSG_ALIGN(nlm->nlmsg_len);
300 }
301
302 // Create IPs with unwanted flags.
303 {
304 QuicIpAddress ip;
305 ip.FromString("10.0.0.1");
306 nlm = CreateNetlinkMessage(buf, nlm, RTM_NEWADDR, seq);
307 CreateIfaddrmsg(nlm, /* interface_index = */ 7, /* prefixlen = */ 16,
308 /* flags = */ IFA_F_OPTIMISTIC, /* scope = */
309 RT_SCOPE_UNIVERSE, ip);
310
311 ret += NLMSG_ALIGN(nlm->nlmsg_len);
312
313 ip.FromString("10.0.0.2");
314 nlm = CreateNetlinkMessage(buf, nlm, RTM_NEWADDR, seq);
315 CreateIfaddrmsg(nlm, /* interface_index = */ 7, /* prefixlen = */ 16,
316 /* flags = */ IFA_F_TENTATIVE, /* scope = */
317 RT_SCOPE_UNIVERSE, ip);
318
319 ret += NLMSG_ALIGN(nlm->nlmsg_len);
320 }
321
322 nlm = CreateNetlinkMessage(buf, nlm, NLMSG_DONE, seq);
323 ret += NLMSG_ALIGN(nlm->nlmsg_len);
324
325 return ret;
326 });
327
328 std::vector<Netlink::AddressInfo> reported_addresses;
329 int num_ipv6_nodad_dadfailed_addresses = 0;
330 EXPECT_TRUE(netlink->GetAddresses(7, IFA_F_TENTATIVE | IFA_F_OPTIMISTIC,
331 &reported_addresses,
332 &num_ipv6_nodad_dadfailed_addresses));
333
334 for (const auto& reported_address : reported_addresses) {
335 EXPECT_TRUE(reported_address.local_address.IsInitialized());
336 EXPECT_FALSE(reported_address.interface_address.IsInitialized());
337 EXPECT_THAT(addresses, Contains(reported_address.local_address.ToString()));
338 addresses.erase(reported_address.local_address.ToString());
339
340 EXPECT_EQ(24, reported_address.prefix_length);
341 }
342
343 EXPECT_TRUE(addresses.empty());
344 }
345
TEST_F(NetlinkTest,ChangeLocalAddressAdd)346 TEST_F(NetlinkTest, ChangeLocalAddressAdd) {
347 auto netlink = std::make_unique<Netlink>(&mock_kernel_);
348
349 QuicIpAddress ip = QuicIpAddress::Any6();
350 ExpectNetlinkPacket(
351 RTM_NEWADDR, NLM_F_ACK | NLM_F_REQUEST,
352 [](void* buf, size_t len, int seq) {
353 struct nlmsghdr* netlink_message =
354 CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
355 auto* err =
356 reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
357 // Ack the request
358 err->error = 0;
359 netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
360 return netlink_message->nlmsg_len;
361 },
362 [ip](const void* buf, size_t len) {
363 auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
364 auto* ifa = reinterpret_cast<const struct ifaddrmsg*>(
365 NLMSG_DATA(netlink_message));
366 EXPECT_EQ(19, ifa->ifa_prefixlen);
367 EXPECT_EQ(RT_SCOPE_UNIVERSE, ifa->ifa_scope);
368 EXPECT_EQ(IFA_F_PERMANENT, ifa->ifa_flags);
369 EXPECT_EQ(7, ifa->ifa_index);
370 EXPECT_EQ(AF_INET6, ifa->ifa_family);
371
372 const struct rtattr* rta;
373 int payload_length = IFA_PAYLOAD(netlink_message);
374 int num_rta = 0;
375 for (rta = IFA_RTA(ifa); RTA_OK(rta, payload_length);
376 rta = RTA_NEXT(rta, payload_length)) {
377 switch (rta->rta_type) {
378 case IFA_LOCAL: {
379 EXPECT_EQ(ip.ToPackedString().size(), RTA_PAYLOAD(rta));
380 const auto* raw_address =
381 reinterpret_cast<const char*>(RTA_DATA(rta));
382 ASSERT_EQ(sizeof(in6_addr), RTA_PAYLOAD(rta));
383 QuicIpAddress address;
384 address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
385 EXPECT_EQ(ip, address);
386 break;
387 }
388 case IFA_CACHEINFO: {
389 EXPECT_EQ(sizeof(struct ifa_cacheinfo), RTA_PAYLOAD(rta));
390 const auto* cache_info =
391 reinterpret_cast<const struct ifa_cacheinfo*>(RTA_DATA(rta));
392 EXPECT_EQ(8, cache_info->ifa_prefered); // common_typos_disable
393 EXPECT_EQ(6, cache_info->ifa_valid);
394 EXPECT_EQ(4, cache_info->cstamp);
395 EXPECT_EQ(2, cache_info->tstamp);
396 break;
397 }
398 default:
399 EXPECT_TRUE(false) << "Seeing rtattr that should not exist";
400 }
401 ++num_rta;
402 }
403 EXPECT_EQ(2, num_rta);
404 });
405
406 struct {
407 struct rtattr rta;
408 struct ifa_cacheinfo cache_info;
409 } additional_rta;
410
411 additional_rta.rta.rta_type = IFA_CACHEINFO;
412 additional_rta.rta.rta_len = RTA_LENGTH(sizeof(struct ifa_cacheinfo));
413 additional_rta.cache_info.ifa_prefered = 8;
414 additional_rta.cache_info.ifa_valid = 6;
415 additional_rta.cache_info.cstamp = 4;
416 additional_rta.cache_info.tstamp = 2;
417
418 EXPECT_TRUE(netlink->ChangeLocalAddress(7, Netlink::Verb::kAdd, ip, 19,
419 IFA_F_PERMANENT, RT_SCOPE_UNIVERSE,
420 {&additional_rta.rta}));
421 }
422
TEST_F(NetlinkTest,ChangeLocalAddressRemove)423 TEST_F(NetlinkTest, ChangeLocalAddressRemove) {
424 auto netlink = std::make_unique<Netlink>(&mock_kernel_);
425
426 QuicIpAddress ip = QuicIpAddress::Any4();
427 ExpectNetlinkPacket(
428 RTM_DELADDR, NLM_F_ACK | NLM_F_REQUEST,
429 [](void* buf, size_t len, int seq) {
430 struct nlmsghdr* netlink_message =
431 CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
432 auto* err =
433 reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
434 // Ack the request
435 err->error = 0;
436 netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
437 return netlink_message->nlmsg_len;
438 },
439 [ip](const void* buf, size_t len) {
440 auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
441 auto* ifa = reinterpret_cast<const struct ifaddrmsg*>(
442 NLMSG_DATA(netlink_message));
443 EXPECT_EQ(32, ifa->ifa_prefixlen);
444 EXPECT_EQ(RT_SCOPE_UNIVERSE, ifa->ifa_scope);
445 EXPECT_EQ(0, ifa->ifa_flags);
446 EXPECT_EQ(7, ifa->ifa_index);
447 EXPECT_EQ(AF_INET, ifa->ifa_family);
448
449 const struct rtattr* rta;
450 int payload_length = IFA_PAYLOAD(netlink_message);
451 int num_rta = 0;
452 for (rta = IFA_RTA(ifa); RTA_OK(rta, payload_length);
453 rta = RTA_NEXT(rta, payload_length)) {
454 switch (rta->rta_type) {
455 case IFA_LOCAL: {
456 const auto* raw_address =
457 reinterpret_cast<const char*>(RTA_DATA(rta));
458 ASSERT_EQ(sizeof(in_addr), RTA_PAYLOAD(rta));
459 QuicIpAddress address;
460 address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
461 EXPECT_EQ(ip, address);
462 break;
463 }
464 default:
465 EXPECT_TRUE(false) << "Seeing rtattr that should not exist";
466 }
467 ++num_rta;
468 }
469 EXPECT_EQ(1, num_rta);
470 });
471
472 EXPECT_TRUE(netlink->ChangeLocalAddress(7, Netlink::Verb::kRemove, ip, 32, 0,
473 RT_SCOPE_UNIVERSE, {}));
474 }
475
TEST_F(NetlinkTest,GetRouteInfoWorks)476 TEST_F(NetlinkTest, GetRouteInfoWorks) {
477 auto netlink = std::make_unique<Netlink>(&mock_kernel_);
478
479 QuicIpAddress destination;
480 ASSERT_TRUE(destination.FromString("f800::2"));
481 ExpectNetlinkPacket(RTM_GETROUTE, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST,
482 [destination](void* buf, size_t len, int seq) {
483 int ret = 0;
484 struct nlmsghdr* netlink_message = CreateNetlinkMessage(
485 buf, nullptr, RTM_NEWROUTE, seq);
486 CreateRtmsg(netlink_message, AF_INET6, 48, 0, 0,
487 RT_TABLE_MAIN, RTPROT_STATIC, RT_SCOPE_LINK,
488 RTN_UNICAST, 0, destination, 7, 0);
489 ret += NLMSG_ALIGN(netlink_message->nlmsg_len);
490
491 netlink_message = CreateNetlinkMessage(
492 buf, netlink_message, NLMSG_DONE, seq);
493 ret += NLMSG_ALIGN(netlink_message->nlmsg_len);
494
495 QUIC_LOG(INFO) << "ret: " << ret;
496 return ret;
497 });
498
499 std::vector<Netlink::RoutingRule> routing_rules;
500 EXPECT_TRUE(netlink->GetRouteInfo(&routing_rules));
501
502 ASSERT_EQ(1, routing_rules.size());
503 EXPECT_EQ(RT_SCOPE_LINK, routing_rules[0].scope);
504 EXPECT_EQ(IpRange(destination, 48).ToString(),
505 routing_rules[0].destination_subnet.ToString());
506 EXPECT_FALSE(routing_rules[0].preferred_source.IsInitialized());
507 EXPECT_EQ(7, routing_rules[0].out_interface);
508 EXPECT_EQ(0, routing_rules[0].init_cwnd);
509 }
510
TEST_F(NetlinkTest,ChangeRouteAdd)511 TEST_F(NetlinkTest, ChangeRouteAdd) {
512 auto netlink = std::make_unique<Netlink>(&mock_kernel_);
513
514 QuicIpAddress preferred_ip;
515 preferred_ip.FromString("ff80:dead:beef::1");
516 IpRange subnet;
517 subnet.FromString("ff80:dead:beef::/48");
518 int egress_interface_index = 7;
519 uint32_t init_cwnd = 32;
520 ExpectNetlinkPacket(
521 RTM_NEWROUTE, NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL,
522 [](void* buf, size_t len, int seq) {
523 struct nlmsghdr* netlink_message =
524 CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
525 auto* err =
526 reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
527 // Ack the request
528 err->error = 0;
529 netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
530 return netlink_message->nlmsg_len;
531 },
532 [preferred_ip, subnet, egress_interface_index, init_cwnd](const void* buf,
533 size_t len) {
534 auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
535 auto* rtm =
536 reinterpret_cast<const struct rtmsg*>(NLMSG_DATA(netlink_message));
537 EXPECT_EQ(AF_INET6, rtm->rtm_family);
538 EXPECT_EQ(48, rtm->rtm_dst_len);
539 EXPECT_EQ(0, rtm->rtm_src_len);
540 EXPECT_EQ(RT_TABLE_MAIN, rtm->rtm_table);
541 EXPECT_EQ(RTPROT_STATIC, rtm->rtm_protocol);
542 EXPECT_EQ(RT_SCOPE_LINK, rtm->rtm_scope);
543 EXPECT_EQ(RTN_UNICAST, rtm->rtm_type);
544
545 const struct rtattr* rta;
546 int payload_length = RTM_PAYLOAD(netlink_message);
547 int num_rta = 0;
548 for (rta = RTM_RTA(rtm); RTA_OK(rta, payload_length);
549 rta = RTA_NEXT(rta, payload_length)) {
550 switch (rta->rta_type) {
551 case RTA_PREFSRC: {
552 const auto* raw_address =
553 reinterpret_cast<const char*>(RTA_DATA(rta));
554 ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
555 QuicIpAddress address;
556 address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
557 EXPECT_EQ(preferred_ip, address);
558 break;
559 }
560 case RTA_GATEWAY: {
561 const auto* raw_address =
562 reinterpret_cast<const char*>(RTA_DATA(rta));
563 ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
564 QuicIpAddress address;
565 address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
566 EXPECT_EQ(*QboneConstants::GatewayAddress(), address);
567 break;
568 }
569 case RTA_OIF: {
570 ASSERT_EQ(sizeof(int), RTA_PAYLOAD(rta));
571 const auto* interface_index =
572 reinterpret_cast<const int*>(RTA_DATA(rta));
573 EXPECT_EQ(egress_interface_index, *interface_index);
574 break;
575 }
576 case RTA_DST: {
577 const auto* raw_address =
578 reinterpret_cast<const char*>(RTA_DATA(rta));
579 ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
580 QuicIpAddress address;
581 address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
582 EXPECT_EQ(subnet.ToString(),
583 IpRange(address, rtm->rtm_dst_len).ToString());
584 break;
585 }
586 case RTA_TABLE: {
587 ASSERT_EQ(*reinterpret_cast<uint32_t*>(RTA_DATA(rta)),
588 QboneConstants::kQboneRouteTableId);
589 break;
590 }
591 case RTA_METRICS: {
592 struct rtattr* rtax =
593 reinterpret_cast<struct rtattr*>(RTA_DATA(rta));
594 ASSERT_EQ(rtax->rta_type, RTAX_INITCWND);
595 ASSERT_EQ(rtax->rta_len, RTA_LENGTH(sizeof(uint32_t)));
596 ASSERT_EQ(*reinterpret_cast<uint32_t*>(RTA_DATA(rtax)),
597 init_cwnd);
598 break;
599 }
600 default:
601 EXPECT_TRUE(false) << "Seeing rtattr that should not be sent";
602 }
603 ++num_rta;
604 }
605 EXPECT_EQ(6, num_rta);
606 });
607 EXPECT_TRUE(netlink->ChangeRoute(
608 Netlink::Verb::kAdd, QboneConstants::kQboneRouteTableId, subnet,
609 RT_SCOPE_LINK, preferred_ip, egress_interface_index, init_cwnd));
610 }
611
TEST_F(NetlinkTest,ChangeRouteRemove)612 TEST_F(NetlinkTest, ChangeRouteRemove) {
613 auto netlink = std::make_unique<Netlink>(&mock_kernel_);
614
615 QuicIpAddress preferred_ip;
616 preferred_ip.FromString("ff80:dead:beef::1");
617 IpRange subnet;
618 subnet.FromString("ff80:dead:beef::/48");
619 int egress_interface_index = 7;
620 ExpectNetlinkPacket(
621 RTM_DELROUTE, NLM_F_ACK | NLM_F_REQUEST,
622 [](void* buf, size_t len, int seq) {
623 struct nlmsghdr* netlink_message =
624 CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
625 auto* err =
626 reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
627 // Ack the request
628 err->error = 0;
629 netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
630 return netlink_message->nlmsg_len;
631 },
632 [preferred_ip, subnet, egress_interface_index](const void* buf,
633 size_t len) {
634 auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
635 auto* rtm =
636 reinterpret_cast<const struct rtmsg*>(NLMSG_DATA(netlink_message));
637 EXPECT_EQ(AF_INET6, rtm->rtm_family);
638 EXPECT_EQ(48, rtm->rtm_dst_len);
639 EXPECT_EQ(0, rtm->rtm_src_len);
640 EXPECT_EQ(RT_TABLE_MAIN, rtm->rtm_table);
641 EXPECT_EQ(RTPROT_UNSPEC, rtm->rtm_protocol);
642 EXPECT_EQ(RT_SCOPE_LINK, rtm->rtm_scope);
643 EXPECT_EQ(RTN_UNICAST, rtm->rtm_type);
644
645 const struct rtattr* rta;
646 int payload_length = RTM_PAYLOAD(netlink_message);
647 int num_rta = 0;
648 for (rta = RTM_RTA(rtm); RTA_OK(rta, payload_length);
649 rta = RTA_NEXT(rta, payload_length)) {
650 switch (rta->rta_type) {
651 case RTA_PREFSRC: {
652 const auto* raw_address =
653 reinterpret_cast<const char*>(RTA_DATA(rta));
654 ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
655 QuicIpAddress address;
656 address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
657 EXPECT_EQ(preferred_ip, address);
658 break;
659 }
660 case RTA_OIF: {
661 ASSERT_EQ(sizeof(int), RTA_PAYLOAD(rta));
662 const auto* interface_index =
663 reinterpret_cast<const int*>(RTA_DATA(rta));
664 EXPECT_EQ(egress_interface_index, *interface_index);
665 break;
666 }
667 case RTA_DST: {
668 const auto* raw_address =
669 reinterpret_cast<const char*>(RTA_DATA(rta));
670 ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
671 QuicIpAddress address;
672 address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
673 EXPECT_EQ(subnet.ToString(),
674 IpRange(address, rtm->rtm_dst_len).ToString());
675 break;
676 }
677 case RTA_TABLE: {
678 ASSERT_EQ(*reinterpret_cast<uint32_t*>(RTA_DATA(rta)),
679 QboneConstants::kQboneRouteTableId);
680 break;
681 }
682 default:
683 EXPECT_TRUE(false) << "Seeing rtattr that should not be sent";
684 }
685 ++num_rta;
686 }
687 EXPECT_EQ(4, num_rta);
688 });
689 EXPECT_TRUE(netlink->ChangeRoute(
690 Netlink::Verb::kRemove, QboneConstants::kQboneRouteTableId, subnet,
691 RT_SCOPE_LINK, preferred_ip, egress_interface_index,
692 Netlink::kUnspecifiedInitCwnd));
693 }
694
TEST_F(NetlinkTest,ChangeRouteReplace)695 TEST_F(NetlinkTest, ChangeRouteReplace) {
696 auto netlink = std::make_unique<Netlink>(&mock_kernel_);
697
698 QuicIpAddress preferred_ip;
699 preferred_ip.FromString("ff80:dead:beef::1");
700 IpRange subnet;
701 subnet.FromString("ff80:dead:beef::/48");
702 int egress_interface_index = 7;
703 ExpectNetlinkPacket(
704 RTM_NEWROUTE, NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
705 [](void* buf, size_t len, int seq) {
706 struct nlmsghdr* netlink_message =
707 CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
708 auto* err =
709 reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
710 // Ack the request
711 err->error = 0;
712 netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
713 return netlink_message->nlmsg_len;
714 },
715 [preferred_ip, subnet, egress_interface_index](const void* buf,
716 size_t len) {
717 auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
718 auto* rtm =
719 reinterpret_cast<const struct rtmsg*>(NLMSG_DATA(netlink_message));
720 EXPECT_EQ(AF_INET6, rtm->rtm_family);
721 EXPECT_EQ(48, rtm->rtm_dst_len);
722 EXPECT_EQ(0, rtm->rtm_src_len);
723 EXPECT_EQ(RT_TABLE_MAIN, rtm->rtm_table);
724 EXPECT_EQ(RTPROT_STATIC, rtm->rtm_protocol);
725 EXPECT_EQ(RT_SCOPE_LINK, rtm->rtm_scope);
726 EXPECT_EQ(RTN_UNICAST, rtm->rtm_type);
727
728 const struct rtattr* rta;
729 int payload_length = RTM_PAYLOAD(netlink_message);
730 int num_rta = 0;
731 for (rta = RTM_RTA(rtm); RTA_OK(rta, payload_length);
732 rta = RTA_NEXT(rta, payload_length)) {
733 switch (rta->rta_type) {
734 case RTA_PREFSRC: {
735 const auto* raw_address =
736 reinterpret_cast<const char*>(RTA_DATA(rta));
737 ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
738 QuicIpAddress address;
739 address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
740 EXPECT_EQ(preferred_ip, address);
741 break;
742 }
743 case RTA_GATEWAY: {
744 const auto* raw_address =
745 reinterpret_cast<const char*>(RTA_DATA(rta));
746 ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
747 QuicIpAddress address;
748 address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
749 EXPECT_EQ(*QboneConstants::GatewayAddress(), address);
750 break;
751 }
752 case RTA_OIF: {
753 ASSERT_EQ(sizeof(int), RTA_PAYLOAD(rta));
754 const auto* interface_index =
755 reinterpret_cast<const int*>(RTA_DATA(rta));
756 EXPECT_EQ(egress_interface_index, *interface_index);
757 break;
758 }
759 case RTA_DST: {
760 const auto* raw_address =
761 reinterpret_cast<const char*>(RTA_DATA(rta));
762 ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
763 QuicIpAddress address;
764 address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
765 EXPECT_EQ(subnet.ToString(),
766 IpRange(address, rtm->rtm_dst_len).ToString());
767 break;
768 }
769 case RTA_TABLE: {
770 ASSERT_EQ(*reinterpret_cast<uint32_t*>(RTA_DATA(rta)),
771 QboneConstants::kQboneRouteTableId);
772 break;
773 }
774 default:
775 EXPECT_TRUE(false) << "Seeing rtattr that should not be sent";
776 }
777 ++num_rta;
778 }
779 EXPECT_EQ(5, num_rta);
780 });
781 EXPECT_TRUE(netlink->ChangeRoute(
782 Netlink::Verb::kReplace, QboneConstants::kQboneRouteTableId, subnet,
783 RT_SCOPE_LINK, preferred_ip, egress_interface_index,
784 Netlink::kUnspecifiedInitCwnd));
785 }
786
787 } // namespace
788 } // namespace quic::test
789