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