1 /*
2 * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
3 * Copyright (c) 2017-2022 The strace developers.
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "tests.h"
10
11 #include <stdio.h>
12 #include <stddef.h>
13 #include "test_nlattr.h"
14
15 #include <linux/if.h>
16 #include <linux/if_arp.h>
17 #include <linux/if_link.h>
18 #include <linux/rtnetlink.h>
19
20 static const unsigned int hdrlen = sizeof(struct ifinfomsg);
21
22 static void
23 init_ifinfomsg(struct nlmsghdr *const nlh, const unsigned int msg_len)
24 {
25 SET_STRUCT(struct nlmsghdr, nlh,
26 .nlmsg_len = msg_len,
27 .nlmsg_type = RTM_GETLINK,
28 .nlmsg_flags = NLM_F_DUMP
29 );
30
31 struct ifinfomsg *const msg = NLMSG_DATA(nlh);
32 SET_STRUCT(struct ifinfomsg, msg,
33 .ifi_family = AF_UNIX,
34 .ifi_type = ARPHRD_LOOPBACK,
35 .ifi_index = ifindex_lo(),
36 .ifi_flags = IFF_UP,
37 );
38 }
39
40 static void
41 print_ifinfomsg(const unsigned int msg_len)
42 {
43 printf("{nlmsg_len=%u, nlmsg_type=RTM_GETLINK, nlmsg_flags=NLM_F_DUMP"
44 ", nlmsg_seq=0, nlmsg_pid=0}, {ifi_family=AF_UNIX"
45 ", ifi_type=ARPHRD_LOOPBACK"
46 ", ifi_index=" IFINDEX_LO_STR
47 ", ifi_flags=IFF_UP, ifi_change=0}",
48 msg_len);
49 }
50
51 static void
52 init_prop_list_msg(struct nlmsghdr *const nlh,
53 const unsigned int msg_len)
54 {
55 init_ifinfomsg(nlh, msg_len);
56
57 struct nlattr *nla = NLMSG_ATTR(nlh, hdrlen);
58 SET_STRUCT(struct nlattr, nla,
59 .nla_len = msg_len - NLMSG_SPACE(hdrlen),
60 .nla_type = IFLA_PROP_LIST,
61 );
62 }
63
64 static void
65 print_prop_list_msg(const unsigned int msg_len)
66 {
67 print_ifinfomsg(msg_len);
68 printf(", [{nla_len=%u, nla_type=IFLA_PROP_LIST}",
69 msg_len - NLMSG_SPACE(hdrlen));
70 }
71
72 int
73 main(void)
74 {
75 skip_if_unavailable("/proc/self/fd/");
76
77 static const struct rtnl_link_stats st = {
78 .rx_packets = 0xabcdefac,
79 .tx_packets = 0xbcdacdab,
80 .rx_bytes = 0xcdbafaab,
81 .tx_bytes = 0xdafabadb,
82 .rx_errors = 0xeabcdaeb,
83 .tx_errors = 0xfefabeab,
84 .rx_dropped = 0xadbafafb,
85 .tx_dropped = 0xbdffabda,
86 .multicast = 0xcdabdfea,
87 .collisions = 0xefadbaeb,
88 .rx_length_errors = 0xfabffabd,
89 .rx_over_errors = 0xafbafabc,
90 .rx_crc_errors = 0xbfdabdad,
91 .rx_frame_errors = 0xcfdabfad,
92 .rx_fifo_errors = 0xddfdebad,
93 .rx_missed_errors = 0xefabdcba,
94 .tx_aborted_errors = 0xefdadbfa,
95 .tx_carrier_errors = 0xfaefbada,
96 .tx_fifo_errors = 0xaebdffab,
97 .tx_heartbeat_errors = 0xbadebaaf,
98 .tx_window_errors = 0xcdafbada,
99 .rx_compressed = 0xdeffadbd,
100 .tx_compressed = 0xefdadfab
101 };
102 const int fd = create_nl_socket(NETLINK_ROUTE);
103 void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen),
104 2 * NLA_HDRLEN + MAX(sizeof(st), 20));
105
106 static char pattern[4096];
107 fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
108
109 const unsigned int nla_type = 0xffff & NLA_TYPE_MASK;
110 char nla_type_str[256];
111 sprintf(nla_type_str, "%#x /* IFLA_??? */", nla_type);
112 TEST_NLATTR_(fd, nlh0, hdrlen,
113 init_ifinfomsg, print_ifinfomsg,
114 nla_type, nla_type_str,
115 4, pattern, 4,
116 print_quoted_hex(pattern, 4));
117
118 const int32_t netnsid = 0xacbdabda;
119 TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
120 init_ifinfomsg, print_ifinfomsg,
121 IFLA_LINK_NETNSID, pattern, netnsid,
122 printf("%d", netnsid));
123
124 const unsigned int sizeof_stats =
125 offsetofend(struct rtnl_link_stats, tx_compressed);
126 TEST_NLATTR_OBJECT_MINSZ(fd, nlh0, hdrlen,
127 init_ifinfomsg, print_ifinfomsg,
128 IFLA_STATS, pattern, st, sizeof_stats,
129 printf("{");
130 PRINT_FIELD_U(st, rx_packets);
131 printf(", ");
132 PRINT_FIELD_U(st, tx_packets);
133 printf(", ");
134 PRINT_FIELD_U(st, rx_bytes);
135 printf(", ");
136 PRINT_FIELD_U(st, tx_bytes);
137 printf(", ");
138 PRINT_FIELD_U(st, rx_errors);
139 printf(", ");
140 PRINT_FIELD_U(st, tx_errors);
141 printf(", ");
142 PRINT_FIELD_U(st, rx_dropped);
143 printf(", ");
144 PRINT_FIELD_U(st, tx_dropped);
145 printf(", ");
146 PRINT_FIELD_U(st, multicast);
147 printf(", ");
148 PRINT_FIELD_U(st, collisions);
149 printf(", ");
150 PRINT_FIELD_U(st, rx_length_errors);
151 printf(", ");
152 PRINT_FIELD_U(st, rx_over_errors);
153 printf(", ");
154 PRINT_FIELD_U(st, rx_crc_errors);
155 printf(", ");
156 PRINT_FIELD_U(st, rx_frame_errors);
157 printf(", ");
158 PRINT_FIELD_U(st, rx_fifo_errors);
159 printf(", ");
160 PRINT_FIELD_U(st, rx_missed_errors);
161 printf(", ");
162 PRINT_FIELD_U(st, tx_aborted_errors);
163 printf(", ");
164 PRINT_FIELD_U(st, tx_carrier_errors);
165 printf(", ");
166 PRINT_FIELD_U(st, tx_fifo_errors);
167 printf(", ");
168 PRINT_FIELD_U(st, tx_heartbeat_errors);
169 printf(", ");
170 PRINT_FIELD_U(st, tx_window_errors);
171 printf(", ");
172 PRINT_FIELD_U(st, rx_compressed);
173 printf(", ");
174 PRINT_FIELD_U(st, tx_compressed);
175 printf(", ");
176 PRINT_FIELD_U(st, rx_nohandler);
177 printf("}"));
178
179 TEST_NLATTR(fd, nlh0, hdrlen,
180 init_ifinfomsg, print_ifinfomsg,
181 IFLA_STATS, sizeof_stats, &st, sizeof_stats,
182 printf("{");
183 PRINT_FIELD_U(st, rx_packets);
184 printf(", ");
185 PRINT_FIELD_U(st, tx_packets);
186 printf(", ");
187 PRINT_FIELD_U(st, rx_bytes);
188 printf(", ");
189 PRINT_FIELD_U(st, tx_bytes);
190 printf(", ");
191 PRINT_FIELD_U(st, rx_errors);
192 printf(", ");
193 PRINT_FIELD_U(st, tx_errors);
194 printf(", ");
195 PRINT_FIELD_U(st, rx_dropped);
196 printf(", ");
197 PRINT_FIELD_U(st, tx_dropped);
198 printf(", ");
199 PRINT_FIELD_U(st, multicast);
200 printf(", ");
201 PRINT_FIELD_U(st, collisions);
202 printf(", ");
203 PRINT_FIELD_U(st, rx_length_errors);
204 printf(", ");
205 PRINT_FIELD_U(st, rx_over_errors);
206 printf(", ");
207 PRINT_FIELD_U(st, rx_crc_errors);
208 printf(", ");
209 PRINT_FIELD_U(st, rx_frame_errors);
210 printf(", ");
211 PRINT_FIELD_U(st, rx_fifo_errors);
212 printf(", ");
213 PRINT_FIELD_U(st, rx_missed_errors);
214 printf(", ");
215 PRINT_FIELD_U(st, tx_aborted_errors);
216 printf(", ");
217 PRINT_FIELD_U(st, tx_carrier_errors);
218 printf(", ");
219 PRINT_FIELD_U(st, tx_fifo_errors);
220 printf(", ");
221 PRINT_FIELD_U(st, tx_heartbeat_errors);
222 printf(", ");
223 PRINT_FIELD_U(st, tx_window_errors);
224 printf(", ");
225 PRINT_FIELD_U(st, rx_compressed);
226 printf(", ");
227 PRINT_FIELD_U(st, tx_compressed);
228 printf("}"));
229
230 static const struct rtnl_link_ifmap map = {
231 .mem_start = 0xadcbefedefbcdedb,
232 .mem_end = 0xefcbeabdecdcdefa,
233 .base_addr = 0xaddbeabdfaacdbae,
234 .irq = 0xefaf,
235 .dma = 0xab,
236 .port = 0xcd
237 };
238 const unsigned int sizeof_ifmap =
239 offsetofend(struct rtnl_link_ifmap, port);
240 const unsigned int plen = sizeof_ifmap - 1 > DEFAULT_STRLEN
241 ? DEFAULT_STRLEN
242 : (int) sizeof_ifmap - 1;
243 /* len < sizeof_ifmap */
244 TEST_NLATTR(fd, nlh0, hdrlen,
245 init_ifinfomsg, print_ifinfomsg,
246 IFLA_MAP, plen, pattern, plen,
247 print_quoted_hex(pattern, plen));
248
249 /* short read of sizeof_ifmap */
250 TEST_NLATTR(fd, nlh0, hdrlen,
251 init_ifinfomsg, print_ifinfomsg,
252 IFLA_MAP, sizeof_ifmap, &map, sizeof_ifmap - 1,
253 printf("%p", RTA_DATA(TEST_NLATTR_nla)));
254
255 /* sizeof_ifmap */
256 TEST_NLATTR(fd, nlh0, hdrlen,
257 init_ifinfomsg, print_ifinfomsg,
258 IFLA_MAP, sizeof_ifmap, &map, sizeof_ifmap,
259 printf("{");
260 PRINT_FIELD_X(map, mem_start);
261 printf(", ");
262 PRINT_FIELD_X(map, mem_end);
263 printf(", ");
264 PRINT_FIELD_X(map, base_addr);
265 printf(", ");
266 PRINT_FIELD_U(map, irq);
267 printf(", ");
268 PRINT_FIELD_U(map, dma);
269 printf(", ");
270 PRINT_FIELD_U(map, port);
271 printf("}"));
272
273 static const struct rtnl_link_stats64 st64 = {
274 .rx_packets = 0xadcbefedefbcdedb,
275 .tx_packets = 0xbdabdedabdcdeabd,
276 .rx_bytes = 0xcdbaefbaeadfabec,
277 .tx_bytes = 0xdbaedbafabbeacdb,
278 .rx_errors = 0xefabfdaefabaefab,
279 .tx_errors = 0xfaebfabfabbaeabf,
280 .rx_dropped = 0xacdbaedbadbabeba,
281 .tx_dropped = 0xbcdeffebdabeadbe,
282 .multicast = 0xeeffbaeabaeffabe,
283 .collisions = 0xffbaefcefbafacef,
284 .rx_length_errors = 0xaabbdeabceffdecb,
285 .rx_over_errors = 0xbbdcdadebadeaeed,
286 .rx_crc_errors= 0xccdeabecefaedbef,
287 .rx_frame_errors = 0xddbedaedebcedaef,
288 .rx_fifo_errors = 0xeffbadefafdaeaab,
289 .rx_missed_errors = 0xfefaebccceadeecd,
290 .tx_aborted_errors = 0xabcdadefcdadef,
291 .tx_carrier_errors = 0xbccdafaeeaaefe,
292 .tx_fifo_errors = 0xcddefdbedeadce,
293 .tx_heartbeat_errors = 0xedaededdadcdea,
294 .tx_window_errors = 0xfdacdeaccedcda,
295 .rx_compressed = 0xacdbbcacdbccef,
296 .tx_compressed = 0xbcdadefcdedfea,
297 .rx_nohandler = 0xcbdbacbfbafffd,
298 .rx_otherhost_dropped = 0xbefdafcfeeadcbfb
299 };
300 TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
301 init_ifinfomsg, print_ifinfomsg,
302 IFLA_STATS64, pattern, st64,
303 printf("{");
304 PRINT_FIELD_U(st64, rx_packets);
305 printf(", ");
306 PRINT_FIELD_U(st64, tx_packets);
307 printf(", ");
308 PRINT_FIELD_U(st64, rx_bytes);
309 printf(", ");
310 PRINT_FIELD_U(st64, tx_bytes);
311 printf(", ");
312 PRINT_FIELD_U(st64, rx_errors);
313 printf(", ");
314 PRINT_FIELD_U(st64, tx_errors);
315 printf(", ");
316 PRINT_FIELD_U(st64, rx_dropped);
317 printf(", ");
318 PRINT_FIELD_U(st64, tx_dropped);
319 printf(", ");
320 PRINT_FIELD_U(st64, multicast);
321 printf(", ");
322 PRINT_FIELD_U(st64, collisions);
323 printf(", ");
324 PRINT_FIELD_U(st64, rx_length_errors);
325 printf(", ");
326 PRINT_FIELD_U(st64, rx_over_errors);
327 printf(", ");
328 PRINT_FIELD_U(st64, rx_crc_errors);
329 printf(", ");
330 PRINT_FIELD_U(st64, rx_frame_errors);
331 printf(", ");
332 PRINT_FIELD_U(st64, rx_fifo_errors);
333 printf(", ");
334 PRINT_FIELD_U(st64, rx_missed_errors);
335 printf(", ");
336 PRINT_FIELD_U(st64, tx_aborted_errors);
337 printf(", ");
338 PRINT_FIELD_U(st64, tx_carrier_errors);
339 printf(", ");
340 PRINT_FIELD_U(st64, tx_fifo_errors);
341 printf(", ");
342 PRINT_FIELD_U(st64, tx_heartbeat_errors);
343 printf(", ");
344 PRINT_FIELD_U(st64, tx_window_errors);
345 printf(", ");
346 PRINT_FIELD_U(st64, rx_compressed);
347 printf(", ");
348 PRINT_FIELD_U(st64, tx_compressed);
349 printf(", ");
350 PRINT_FIELD_U(st64, rx_nohandler);
351 printf(", ");
352 PRINT_FIELD_U(st64, rx_otherhost_dropped);
353 printf("}"));
354
355 const unsigned int stats64_rx_nohandler_size =
356 offsetofend(struct rtnl_link_stats64, rx_nohandler);
357 TEST_NLATTR(fd, nlh0, hdrlen,
358 init_ifinfomsg, print_ifinfomsg,
359 IFLA_STATS64, stats64_rx_nohandler_size,
360 &st64, stats64_rx_nohandler_size,
361 printf("{");
362 PRINT_FIELD_U(st64, rx_packets);
363 printf(", ");
364 PRINT_FIELD_U(st64, tx_packets);
365 printf(", ");
366 PRINT_FIELD_U(st64, rx_bytes);
367 printf(", ");
368 PRINT_FIELD_U(st64, tx_bytes);
369 printf(", ");
370 PRINT_FIELD_U(st64, rx_errors);
371 printf(", ");
372 PRINT_FIELD_U(st64, tx_errors);
373 printf(", ");
374 PRINT_FIELD_U(st64, rx_dropped);
375 printf(", ");
376 PRINT_FIELD_U(st64, tx_dropped);
377 printf(", ");
378 PRINT_FIELD_U(st64, multicast);
379 printf(", ");
380 PRINT_FIELD_U(st64, collisions);
381 printf(", ");
382 PRINT_FIELD_U(st64, rx_length_errors);
383 printf(", ");
384 PRINT_FIELD_U(st64, rx_over_errors);
385 printf(", ");
386 PRINT_FIELD_U(st64, rx_crc_errors);
387 printf(", ");
388 PRINT_FIELD_U(st64, rx_frame_errors);
389 printf(", ");
390 PRINT_FIELD_U(st64, rx_fifo_errors);
391 printf(", ");
392 PRINT_FIELD_U(st64, rx_missed_errors);
393 printf(", ");
394 PRINT_FIELD_U(st64, tx_aborted_errors);
395 printf(", ");
396 PRINT_FIELD_U(st64, tx_carrier_errors);
397 printf(", ");
398 PRINT_FIELD_U(st64, tx_fifo_errors);
399 printf(", ");
400 PRINT_FIELD_U(st64, tx_heartbeat_errors);
401 printf(", ");
402 PRINT_FIELD_U(st64, tx_window_errors);
403 printf(", ");
404 PRINT_FIELD_U(st64, rx_compressed);
405 printf(", ");
406 PRINT_FIELD_U(st64, tx_compressed);
407 printf(", ");
408 PRINT_FIELD_U(st64, rx_nohandler);
409 printf("}"));
410
411 const unsigned int stats64_tx_compressed_size =
412 offsetofend(struct rtnl_link_stats64, tx_compressed);
413 TEST_NLATTR(fd, nlh0, hdrlen,
414 init_ifinfomsg, print_ifinfomsg,
415 IFLA_STATS64, stats64_tx_compressed_size,
416 &st64, stats64_tx_compressed_size,
417 printf("{");
418 PRINT_FIELD_U(st64, rx_packets);
419 printf(", ");
420 PRINT_FIELD_U(st64, tx_packets);
421 printf(", ");
422 PRINT_FIELD_U(st64, rx_bytes);
423 printf(", ");
424 PRINT_FIELD_U(st64, tx_bytes);
425 printf(", ");
426 PRINT_FIELD_U(st64, rx_errors);
427 printf(", ");
428 PRINT_FIELD_U(st64, tx_errors);
429 printf(", ");
430 PRINT_FIELD_U(st64, rx_dropped);
431 printf(", ");
432 PRINT_FIELD_U(st64, tx_dropped);
433 printf(", ");
434 PRINT_FIELD_U(st64, multicast);
435 printf(", ");
436 PRINT_FIELD_U(st64, collisions);
437 printf(", ");
438 PRINT_FIELD_U(st64, rx_length_errors);
439 printf(", ");
440 PRINT_FIELD_U(st64, rx_over_errors);
441 printf(", ");
442 PRINT_FIELD_U(st64, rx_crc_errors);
443 printf(", ");
444 PRINT_FIELD_U(st64, rx_frame_errors);
445 printf(", ");
446 PRINT_FIELD_U(st64, rx_fifo_errors);
447 printf(", ");
448 PRINT_FIELD_U(st64, rx_missed_errors);
449 printf(", ");
450 PRINT_FIELD_U(st64, tx_aborted_errors);
451 printf(", ");
452 PRINT_FIELD_U(st64, tx_carrier_errors);
453 printf(", ");
454 PRINT_FIELD_U(st64, tx_fifo_errors);
455 printf(", ");
456 PRINT_FIELD_U(st64, tx_heartbeat_errors);
457 printf(", ");
458 PRINT_FIELD_U(st64, tx_window_errors);
459 printf(", ");
460 PRINT_FIELD_U(st64, rx_compressed);
461 printf(", ");
462 PRINT_FIELD_U(st64, tx_compressed);
463 printf("}"));
464
465 struct nlattr nla = {
466 .nla_len = sizeof(nla),
467 .nla_type = IFLA_INFO_KIND,
468 };
469 TEST_NLATTR(fd, nlh0, hdrlen,
470 init_ifinfomsg, print_ifinfomsg,
471 IFLA_LINKINFO, sizeof(nla), &nla, sizeof(nla),
472 printf("{nla_len=%u, nla_type=IFLA_INFO_KIND}",
473 nla.nla_len));
474
475 /* IFLA_VF_PORTS */
476 nla.nla_type = IFLA_VF_PORT;
477 TEST_NLATTR(fd, nlh0, hdrlen,
478 init_ifinfomsg, print_ifinfomsg,
479 IFLA_VF_PORTS, sizeof(nla), &nla, sizeof(nla),
480 printf("{nla_len=%u, nla_type=IFLA_VF_PORT}",
481 nla.nla_len));
482
483 /* IFLA_EXT_MASK */
484 static const struct strval32 ifla_ext_masks[] = {
485 { ARG_STR(0) },
486 { ARG_STR(RTEXT_FILTER_VF) },
487 { ARG_STR(0xdeface80) " /* RTEXT_FILTER_??? */" },
488 { 0xdeadfeed, "RTEXT_FILTER_VF|RTEXT_FILTER_BRVLAN_COMPRESSED"
489 "|RTEXT_FILTER_SKIP_STATS|RTEXT_FILTER_CFM_CONFIG"
490 "|RTEXT_FILTER_CFM_STATUS|0xdeadfe80" },
491 };
492 for (size_t i = 0; i < ARRAY_SIZE(ifla_ext_masks); i++) {
493 TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
494 init_ifinfomsg, print_ifinfomsg,
495 IFLA_EXT_MASK, pattern,
496 ifla_ext_masks[i].val,
497 printf("%s", ifla_ext_masks[i].str));
498 }
499
500 /* IFLA_EVENT */
501 static const struct {
502 uint32_t val;
503 const char *str;
504 } ifla_events[] = {
505 { 0, "IFLA_EVENT_NONE" },
506 { 6, "IFLA_EVENT_BONDING_OPTIONS" },
507 { ARG_STR(0x7) " /* IFLA_EVENT_??? */" },
508 { ARG_STR(0xdeadfeed) " /* IFLA_EVENT_??? */" },
509 };
510 for (size_t i = 0; i < ARRAY_SIZE(ifla_events); i++) {
511 TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
512 init_ifinfomsg, print_ifinfomsg,
513 IFLA_EVENT, pattern, ifla_events[i].val,
514 printf("%s", ifla_events[i].str));
515 }
516
517 /* IFLA_PROP_LIST */
518 struct {
519 char p1[20];
520 } buf;
521 fill_memory(&buf, sizeof(buf));
522 TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
523 init_prop_list_msg, print_prop_list_msg,
524 IFLA_ALT_IFNAME, "IFLA_ALT_IFNAME",
525 pattern, buf, print_quoted_stringn, 1,
526 print_quoted_memory(&buf, sizeof(buf));
527 printf("..."));
528
529 /* IFLA_ALT_IFNAME, IFLA_PARENT_DEV_NAME, IFLA_PARENT_DEV_BUS_NAME */
530 static const char str[] = "OH HAI THAR\r\n\t\377\0\v\x7e";
531 static const struct {
532 uint32_t val;
533 const char *str;
534 } attrs[] = {
535 { ARG_STR(IFLA_ALT_IFNAME) },
536 { ARG_STR(IFLA_PARENT_DEV_NAME) },
537 { ARG_STR(IFLA_PARENT_DEV_BUS_NAME) },
538 };
539 for (size_t i = 0; i < ARRAY_SIZE(attrs); i++) {
540 TEST_NLATTR_(fd, nlh0, hdrlen,
541 init_ifinfomsg, print_ifinfomsg,
542 attrs[i].val, attrs[i].str,
543 sizeof(str), str, sizeof(str),
544 print_quoted_memory(str, sizeof(str) - 1));
545
546 TEST_NLATTR_(fd, nlh0, hdrlen,
547 init_ifinfomsg, print_ifinfomsg,
548 attrs[i].val, attrs[i].str,
549 sizeof(str) - 1, str, sizeof(str) - 1,
550 print_quoted_memory(str, sizeof(str) - 1);
551 printf("..."));
552 }
553
554 puts("+++ exited with 0 +++");
555 return 0;
556 }