]> git.proxmox.com Git - mirror_frr.git/blob - zebra/debug_nl.c
Merge pull request #10592 from patrasar/master_pimv6_bsm
[mirror_frr.git] / zebra / debug_nl.c
1 /*
2 * Copyright (c) 2018 Rafael Zalamena
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <zebra.h>
18
19 #if defined(HAVE_NETLINK) && defined(NETLINK_DEBUG)
20
21 #include <sys/socket.h>
22
23 #include <linux/netconf.h>
24 #include <linux/netlink.h>
25 #include <linux/nexthop.h>
26 #include <linux/rtnetlink.h>
27 #include <net/if_arp.h>
28 #include <linux/fib_rules.h>
29 #include <linux/lwtunnel.h>
30
31 #include <stdio.h>
32 #include <stdint.h>
33
34 #include "zebra/rt_netlink.h"
35 #include "zebra/kernel_netlink.h"
36 #include "lib/vxlan.h"
37
38 const char *nlmsg_type2str(uint16_t type)
39 {
40 switch (type) {
41 /* Generic */
42 case NLMSG_NOOP:
43 return "NOOP";
44 case NLMSG_ERROR:
45 return "ERROR";
46 case NLMSG_DONE:
47 return "DONE";
48 case NLMSG_OVERRUN:
49 return "OVERRUN";
50
51 /* RTM */
52 case RTM_NEWLINK:
53 return "NEWLINK";
54 case RTM_DELLINK:
55 return "DELLINK";
56 case RTM_GETLINK:
57 return "GETLINK";
58 case RTM_SETLINK:
59 return "SETLINK";
60
61 case RTM_NEWADDR:
62 return "NEWADDR";
63 case RTM_DELADDR:
64 return "DELADDR";
65 case RTM_GETADDR:
66 return "GETADDR";
67
68 case RTM_NEWROUTE:
69 return "NEWROUTE";
70 case RTM_DELROUTE:
71 return "DELROUTE";
72 case RTM_GETROUTE:
73 return "GETROUTE";
74
75 case RTM_NEWNEIGH:
76 return "NEWNEIGH";
77 case RTM_DELNEIGH:
78 return "DELNEIGH";
79 case RTM_GETNEIGH:
80 return "GETNEIGH";
81
82 case RTM_NEWRULE:
83 return "NEWRULE";
84 case RTM_DELRULE:
85 return "DELRULE";
86 case RTM_GETRULE:
87 return "GETRULE";
88
89 case RTM_NEWNEXTHOP:
90 return "NEWNEXTHOP";
91 case RTM_DELNEXTHOP:
92 return "DELNEXTHOP";
93 case RTM_GETNEXTHOP:
94 return "GETNEXTHOP";
95
96 case RTM_NEWTUNNEL:
97 return "NEWTUNNEL";
98 case RTM_DELTUNNEL:
99 return "DELTUNNEL";
100 case RTM_GETTUNNEL:
101 return "GETTUNNEL";
102
103 case RTM_NEWNETCONF:
104 return "RTM_NEWNETCONF";
105 case RTM_DELNETCONF:
106 return "RTM_DELNETCONF";
107
108 default:
109 return "UNKNOWN";
110 }
111 }
112
113 const char *af_type2str(int type)
114 {
115 switch (type) {
116 case AF_UNSPEC:
117 return "AF_UNSPEC";
118 case AF_UNIX:
119 return "AF_UNIX";
120 case AF_INET:
121 return "AF_INET";
122 case AF_INET6:
123 return "AF_INET6";
124 case AF_BRIDGE:
125 return "AF_BRIDGE";
126 case AF_NETLINK:
127 return "AF_NETLINK";
128 #ifdef AF_MPLS
129 case AF_MPLS:
130 return "AF_MPLS";
131 #endif /* AF_MPLS */
132 case AF_BLUETOOTH:
133 return "AF_BLUETOOTH";
134 case AF_VSOCK:
135 return "AF_VSOCK";
136 case AF_KEY:
137 return "AF_KEY";
138 case AF_PACKET:
139 return "AF_PACKET";
140 default:
141 return "UNKNOWN";
142 }
143 }
144
145 const char *ifi_type2str(int type)
146 {
147 switch (type) {
148 case ARPHRD_ETHER:
149 return "ETHER";
150 case ARPHRD_EETHER:
151 return "EETHER";
152 case ARPHRD_NETROM:
153 return "NETROM";
154 case ARPHRD_AX25:
155 return "AX25";
156 case ARPHRD_PRONET:
157 return "PRONET";
158 case ARPHRD_CHAOS:
159 return "CHAOS";
160 case ARPHRD_IEEE802:
161 return "IEEE802";
162 case ARPHRD_ARCNET:
163 return "ARCNET";
164 case ARPHRD_APPLETLK:
165 return "APPLETLK";
166 case ARPHRD_DLCI:
167 return "DLCI";
168 case ARPHRD_ATM:
169 return "ATM";
170 case ARPHRD_METRICOM:
171 return "METRICOM";
172 case ARPHRD_IEEE1394:
173 return "IEEE1394";
174 case ARPHRD_EUI64:
175 return "EUI64";
176 case ARPHRD_INFINIBAND:
177 return "INFINIBAND";
178 case ARPHRD_SLIP:
179 return "SLIP";
180 case ARPHRD_CSLIP:
181 return "CSLIP";
182 case ARPHRD_SLIP6:
183 return "SLIP6";
184 case ARPHRD_CSLIP6:
185 return "CSLIP6";
186 case ARPHRD_RSRVD:
187 return "RSRVD";
188 case ARPHRD_ADAPT:
189 return "ADAPT";
190 case ARPHRD_ROSE:
191 return "ROSE";
192 case ARPHRD_X25:
193 return "X25";
194 case ARPHRD_PPP:
195 return "PPP";
196 case ARPHRD_HDLC:
197 return "HDLC";
198 case ARPHRD_LAPB:
199 return "LAPB";
200 case ARPHRD_DDCMP:
201 return "DDCMP";
202 case ARPHRD_RAWHDLC:
203 return "RAWHDLC";
204 case ARPHRD_TUNNEL:
205 return "TUNNEL";
206 case ARPHRD_TUNNEL6:
207 return "TUNNEL6";
208 case ARPHRD_FRAD:
209 return "FRAD";
210 case ARPHRD_SKIP:
211 return "SKIP";
212 case ARPHRD_LOOPBACK:
213 return "LOOPBACK";
214 case ARPHRD_LOCALTLK:
215 return "LOCALTLK";
216 case ARPHRD_FDDI:
217 return "FDDI";
218 case ARPHRD_BIF:
219 return "BIF";
220 case ARPHRD_SIT:
221 return "SIT";
222 case ARPHRD_IPDDP:
223 return "IPDDP";
224 case ARPHRD_IPGRE:
225 return "IPGRE";
226 case ARPHRD_PIMREG:
227 return "PIMREG";
228 case ARPHRD_HIPPI:
229 return "HIPPI";
230 case ARPHRD_ASH:
231 return "ASH";
232 case ARPHRD_ECONET:
233 return "ECONET";
234 case ARPHRD_IRDA:
235 return "IRDA";
236 case ARPHRD_FCPP:
237 return "FCPP";
238 case ARPHRD_FCAL:
239 return "FCAL";
240 case ARPHRD_FCPL:
241 return "FCPL";
242 case ARPHRD_FCFABRIC:
243 return "FCFABRIC";
244 case ARPHRD_IEEE802_TR:
245 return "IEEE802_TR";
246 case ARPHRD_IEEE80211:
247 return "IEEE80211";
248 case ARPHRD_IEEE80211_PRISM:
249 return "IEEE80211_PRISM";
250 case ARPHRD_IEEE80211_RADIOTAP:
251 return "IEEE80211_RADIOTAP";
252 case ARPHRD_IEEE802154:
253 return "IEEE802154";
254 #ifdef ARPHRD_VSOCKMON
255 case ARPHRD_VSOCKMON:
256 return "VSOCKMON";
257 #endif /* ARPHRD_VSOCKMON */
258 case ARPHRD_VOID:
259 return "VOID";
260 case ARPHRD_NONE:
261 return "NONE";
262 default:
263 return "UNKNOWN";
264 }
265 }
266
267 const char *ifla_pdr_type2str(int type)
268 {
269 switch (type) {
270 case IFLA_PROTO_DOWN_REASON_UNSPEC:
271 return "UNSPEC";
272 case IFLA_PROTO_DOWN_REASON_MASK:
273 return "MASK";
274 case IFLA_PROTO_DOWN_REASON_VALUE:
275 return "VALUE";
276 default:
277 return "UNKNOWN";
278 }
279 }
280
281 const char *ifla_info_type2str(int type)
282 {
283 switch (type) {
284 case IFLA_INFO_UNSPEC:
285 return "UNSPEC";
286 case IFLA_INFO_KIND:
287 return "KIND";
288 case IFLA_INFO_DATA:
289 return "DATA";
290 case IFLA_INFO_XSTATS:
291 return "XSTATS";
292 case IFLA_INFO_SLAVE_KIND:
293 return "SLAVE_KIND";
294 case IFLA_INFO_SLAVE_DATA:
295 return "SLAVE_DATA";
296 default:
297 return "UNKNOWN";
298 }
299 }
300
301 const char *rta_type2str(int type)
302 {
303 switch (type) {
304 case IFLA_UNSPEC:
305 return "UNSPEC";
306 case IFLA_ADDRESS:
307 return "ADDRESS";
308 case IFLA_BROADCAST:
309 return "BROADCAST";
310 case IFLA_IFNAME:
311 return "IFNAME";
312 case IFLA_MTU:
313 return "MTU";
314 case IFLA_LINK:
315 return "LINK";
316 case IFLA_QDISC:
317 return "QDISC";
318 case IFLA_STATS:
319 return "STATS";
320 case IFLA_COST:
321 return "COST";
322 case IFLA_PRIORITY:
323 return "PRIORITY";
324 case IFLA_MASTER:
325 return "MASTER";
326 case IFLA_WIRELESS:
327 return "WIRELESS";
328 case IFLA_PROTINFO:
329 return "PROTINFO";
330 case IFLA_TXQLEN:
331 return "TXQLEN";
332 case IFLA_MAP:
333 return "MAP";
334 case IFLA_WEIGHT:
335 return "WEIGHT";
336 case IFLA_OPERSTATE:
337 return "OPERSTATE";
338 case IFLA_LINKMODE:
339 return "LINKMODE";
340 case IFLA_LINKINFO:
341 return "LINKINFO";
342 case IFLA_NET_NS_PID:
343 return "NET_NS_PID";
344 case IFLA_IFALIAS:
345 return "IFALIAS";
346 case IFLA_NUM_VF:
347 return "NUM_VF";
348 case IFLA_VFINFO_LIST:
349 return "VFINFO_LIST";
350 case IFLA_STATS64:
351 return "STATS64";
352 case IFLA_VF_PORTS:
353 return "VF_PORTS";
354 case IFLA_PORT_SELF:
355 return "PORT_SELF";
356 case IFLA_AF_SPEC:
357 return "AF_SPEC";
358 case IFLA_GROUP:
359 return "GROUP";
360 case IFLA_NET_NS_FD:
361 return "NET_NS_FD";
362 case IFLA_EXT_MASK:
363 return "EXT_MASK";
364 case IFLA_PROMISCUITY:
365 return "PROMISCUITY";
366 case IFLA_NUM_TX_QUEUES:
367 return "NUM_TX_QUEUES";
368 case IFLA_NUM_RX_QUEUES:
369 return "NUM_RX_QUEUES";
370 case IFLA_CARRIER:
371 return "CARRIER";
372 case IFLA_PHYS_PORT_ID:
373 return "PHYS_PORT_ID";
374 case IFLA_CARRIER_CHANGES:
375 return "CARRIER_CHANGES";
376 case IFLA_PHYS_SWITCH_ID:
377 return "PHYS_SWITCH_ID";
378 case IFLA_LINK_NETNSID:
379 return "LINK_NETNSID";
380 case IFLA_PHYS_PORT_NAME:
381 return "PHYS_PORT_NAME";
382 case IFLA_PROTO_DOWN:
383 return "PROTO_DOWN";
384 #ifdef IFLA_GSO_MAX_SEGS
385 case IFLA_GSO_MAX_SEGS:
386 return "GSO_MAX_SEGS";
387 #endif /* IFLA_GSO_MAX_SEGS */
388 #ifdef IFLA_GSO_MAX_SIZE
389 case IFLA_GSO_MAX_SIZE:
390 return "GSO_MAX_SIZE";
391 #endif /* IFLA_GSO_MAX_SIZE */
392 #ifdef IFLA_PAD
393 case IFLA_PAD:
394 return "PAD";
395 #endif /* IFLA_PAD */
396 #ifdef IFLA_XDP
397 case IFLA_XDP:
398 return "XDP";
399 #endif /* IFLA_XDP */
400 #ifdef IFLA_EVENT
401 case IFLA_EVENT:
402 return "EVENT";
403 #endif /* IFLA_EVENT */
404 case IFLA_PROTO_DOWN_REASON:
405 return "PROTO_DOWN_REASON";
406 default:
407 return "UNKNOWN";
408 }
409 }
410
411 const char *rtm_type2str(int type)
412 {
413 switch (type) {
414 case RTN_UNSPEC:
415 return "UNSPEC";
416 case RTN_UNICAST:
417 return "UNICAST";
418 case RTN_LOCAL:
419 return "LOCAL";
420 case RTN_BROADCAST:
421 return "BROADCAST";
422 case RTN_ANYCAST:
423 return "ANYCAST";
424 case RTN_MULTICAST:
425 return "MULTICAST";
426 case RTN_BLACKHOLE:
427 return "BLACKHOLE";
428 case RTN_UNREACHABLE:
429 return "UNREACHABLE";
430 case RTN_PROHIBIT:
431 return "PROHIBIT";
432 case RTN_THROW:
433 return "THROW";
434 case RTN_NAT:
435 return "NAT";
436 case RTN_XRESOLVE:
437 return "XRESOLVE";
438 default:
439 return "UNKNOWN";
440 }
441 }
442
443 const char *rtm_protocol2str(int type)
444 {
445 switch (type) {
446 case RTPROT_UNSPEC:
447 return "UNSPEC";
448 case RTPROT_REDIRECT:
449 return "REDIRECT";
450 case RTPROT_KERNEL:
451 return "KERNEL";
452 case RTPROT_BOOT:
453 return "BOOT";
454 case RTPROT_STATIC:
455 return "STATIC";
456 case RTPROT_GATED:
457 return "GATED";
458 case RTPROT_RA:
459 return "RA";
460 case RTPROT_MRT:
461 return "MRT";
462 case RTPROT_ZEBRA:
463 return "ZEBRA";
464 case RTPROT_BGP:
465 return "BGP";
466 case RTPROT_ISIS:
467 return "ISIS";
468 case RTPROT_OSPF:
469 return "OSPF";
470 case RTPROT_BIRD:
471 return "BIRD";
472 case RTPROT_DNROUTED:
473 return "DNROUTED";
474 case RTPROT_XORP:
475 return "XORP";
476 case RTPROT_NTK:
477 return "NTK";
478 case RTPROT_DHCP:
479 return "DHCP";
480 case RTPROT_MROUTED:
481 return "MROUTED";
482 case RTPROT_BABEL:
483 return "BABEL";
484 default:
485 return "UNKNOWN";
486 }
487 }
488
489 const char *rtm_scope2str(int type)
490 {
491 switch (type) {
492 case RT_SCOPE_UNIVERSE:
493 return "UNIVERSE";
494 case RT_SCOPE_SITE:
495 return "SITE";
496 case RT_SCOPE_LINK:
497 return "LINK";
498 case RT_SCOPE_HOST:
499 return "HOST";
500 case RT_SCOPE_NOWHERE:
501 return "NOWHERE";
502 default:
503 return "UNKNOWN";
504 }
505 }
506
507 const char *rtm_rta2str(int type)
508 {
509 switch (type) {
510 case RTA_UNSPEC:
511 return "UNSPEC";
512 case RTA_DST:
513 return "DST";
514 case RTA_SRC:
515 return "SRC";
516 case RTA_IIF:
517 return "IIF";
518 case RTA_OIF:
519 return "OIF";
520 case RTA_GATEWAY:
521 return "GATEWAY";
522 case RTA_PRIORITY:
523 return "PRIORITY";
524 case RTA_PREF:
525 return "PREF";
526 case RTA_PREFSRC:
527 return "PREFSRC";
528 case RTA_MARK:
529 return "MARK";
530 case RTA_METRICS:
531 return "METRICS";
532 case RTA_MULTIPATH:
533 return "MULTIPATH";
534 case RTA_PROTOINFO:
535 return "PROTOINFO";
536 case RTA_FLOW:
537 return "FLOW";
538 case RTA_CACHEINFO:
539 return "CACHEINFO";
540 case RTA_TABLE:
541 return "TABLE";
542 case RTA_MFC_STATS:
543 return "MFC_STATS";
544 case RTA_NH_ID:
545 return "NH_ID";
546 case RTA_EXPIRES:
547 return "EXPIRES";
548 default:
549 return "UNKNOWN";
550 }
551 }
552
553 const char *neigh_rta2str(int type)
554 {
555 switch (type) {
556 case NDA_UNSPEC:
557 return "UNSPEC";
558 case NDA_DST:
559 return "DST";
560 case NDA_LLADDR:
561 return "LLADDR";
562 case NDA_CACHEINFO:
563 return "CACHEINFO";
564 case NDA_PROBES:
565 return "PROBES";
566 case NDA_VLAN:
567 return "VLAN";
568 case NDA_PORT:
569 return "PORT";
570 case NDA_VNI:
571 return "VNI";
572 case NDA_IFINDEX:
573 return "IFINDEX";
574 case NDA_MASTER:
575 return "MASTER";
576 case NDA_LINK_NETNSID:
577 return "LINK_NETNSID";
578 default:
579 return "UNKNOWN";
580 }
581 }
582
583 const char *ifa_rta2str(int type)
584 {
585 switch (type) {
586 case IFA_UNSPEC:
587 return "UNSPEC";
588 case IFA_ADDRESS:
589 return "ADDRESS";
590 case IFA_LOCAL:
591 return "LOCAL";
592 case IFA_LABEL:
593 return "LABEL";
594 case IFA_BROADCAST:
595 return "BROADCAST";
596 case IFA_ANYCAST:
597 return "ANYCAST";
598 case IFA_CACHEINFO:
599 return "CACHEINFO";
600 case IFA_MULTICAST:
601 return "MULTICAST";
602 case IFA_FLAGS:
603 return "FLAGS";
604 default:
605 return "UNKNOWN";
606 }
607 }
608
609 const char *nhm_rta2str(int type)
610 {
611 switch (type) {
612 case NHA_UNSPEC:
613 return "UNSPEC";
614 case NHA_ID:
615 return "ID";
616 case NHA_GROUP:
617 return "GROUP";
618 case NHA_GROUP_TYPE:
619 return "GROUP_TYPE";
620 case NHA_BLACKHOLE:
621 return "BLACKHOLE";
622 case NHA_OIF:
623 return "OIF";
624 case NHA_GATEWAY:
625 return "GATEWAY";
626 case NHA_ENCAP_TYPE:
627 return "ENCAP_TYPE";
628 case NHA_ENCAP:
629 return "ENCAP";
630 case NHA_GROUPS:
631 return "GROUPS";
632 case NHA_MASTER:
633 return "MASTER";
634 default:
635 return "UNKNOWN";
636 }
637 }
638
639 const char *frh_rta2str(int type)
640 {
641 switch (type) {
642 case FRA_DST:
643 return "DST";
644 case FRA_SRC:
645 return "SRC";
646 case FRA_IIFNAME:
647 return "IIFNAME";
648 case FRA_GOTO:
649 return "GOTO";
650 case FRA_UNUSED2:
651 return "UNUSED2";
652 case FRA_PRIORITY:
653 return "PRIORITY";
654 case FRA_UNUSED3:
655 return "UNUSED3";
656 case FRA_UNUSED4:
657 return "UNUSED4";
658 case FRA_UNUSED5:
659 return "UNUSED5";
660 case FRA_FWMARK:
661 return "FWMARK";
662 case FRA_FLOW:
663 return "FLOW";
664 case FRA_TUN_ID:
665 return "TUN_ID";
666 case FRA_SUPPRESS_IFGROUP:
667 return "SUPPRESS_IFGROUP";
668 case FRA_SUPPRESS_PREFIXLEN:
669 return "SUPPRESS_PREFIXLEN";
670 case FRA_TABLE:
671 return "TABLE";
672 case FRA_FWMASK:
673 return "FWMASK";
674 case FRA_OIFNAME:
675 return "OIFNAME";
676 case FRA_PAD:
677 return "PAD";
678 case FRA_L3MDEV:
679 return "L3MDEV";
680 case FRA_UID_RANGE:
681 return "UID_RANGE";
682 case FRA_PROTOCOL:
683 return "PROTOCOL";
684 case FRA_IP_PROTO:
685 return "IP_PROTO";
686 case FRA_SPORT_RANGE:
687 return "SPORT_RANGE";
688 case FRA_DPORT_RANGE:
689 return "DPORT_RANGE";
690 default:
691 return "UNKNOWN";
692 }
693 }
694
695 const char *frh_action2str(uint8_t action)
696 {
697 switch (action) {
698 case FR_ACT_TO_TBL:
699 return "TO_TBL";
700 case FR_ACT_GOTO:
701 return "GOTO";
702 case FR_ACT_NOP:
703 return "NOP";
704 case FR_ACT_RES3:
705 return "RES3";
706 case FR_ACT_RES4:
707 return "RES4";
708 case FR_ACT_BLACKHOLE:
709 return "BLACKHOLE";
710 case FR_ACT_UNREACHABLE:
711 return "UNREACHABLE";
712 case FR_ACT_PROHIBIT:
713 return "PROHIBIT";
714 default:
715 return "UNKNOWN";
716 }
717 }
718
719 static const char *ncm_rta2str(int type)
720 {
721 switch (type) {
722 case NETCONFA_UNSPEC:
723 return "UNSPEC";
724 case NETCONFA_IFINDEX:
725 return "IFINDEX";
726 case NETCONFA_FORWARDING:
727 return "FORWARDING";
728 case NETCONFA_RP_FILTER:
729 return "RP_FILTER";
730 case NETCONFA_MC_FORWARDING:
731 return "MCAST";
732 case NETCONFA_PROXY_NEIGH:
733 return "PROXY_NEIGH";
734 case NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN:
735 return "IGNORE_LINKDOWN";
736 case NETCONFA_INPUT:
737 return "MPLS";
738 case NETCONFA_BC_FORWARDING:
739 return "BCAST";
740 default:
741 return "UNKNOWN";
742 }
743 }
744
745 static void dump_on_off(uint32_t ival, const char *prefix)
746 {
747 zlog_debug("%s%s", prefix, (ival != 0) ? "on" : "off");
748 }
749
750 static inline void flag_write(int flags, int flag, const char *flagstr,
751 char *buf, size_t buflen)
752 {
753 if (CHECK_FLAG(flags, flag) == 0)
754 return;
755
756 if (buf[0])
757 strlcat(buf, ",", buflen);
758
759 strlcat(buf, flagstr, buflen);
760 }
761
762 const char *nlmsg_flags2str(uint16_t flags, char *buf, size_t buflen)
763 {
764 const char *bufp = buf;
765
766 *buf = 0;
767 /* Specific flags. */
768 flag_write(flags, NLM_F_REQUEST, "REQUEST", buf, buflen);
769 flag_write(flags, NLM_F_MULTI, "MULTI", buf, buflen);
770 flag_write(flags, NLM_F_ACK, "ACK", buf, buflen);
771 flag_write(flags, NLM_F_ECHO, "ECHO", buf, buflen);
772 flag_write(flags, NLM_F_DUMP, "DUMP", buf, buflen);
773
774 /* Netlink family type dependent. */
775 flag_write(flags, 0x0100, "(ROOT|REPLACE|CAPPED)", buf, buflen);
776 flag_write(flags, 0x0200, "(MATCH|EXCLUDE|ACK_TLVS)", buf, buflen);
777 flag_write(flags, 0x0400, "(ATOMIC|CREATE)", buf, buflen);
778 flag_write(flags, 0x0800, "(DUMP|APPEND)", buf, buflen);
779
780 return (bufp);
781 }
782
783 const char *if_flags2str(uint32_t flags, char *buf, size_t buflen)
784 {
785 const char *bufp = buf;
786
787 *buf = 0;
788 flag_write(flags, IFF_UP, "UP", buf, buflen);
789 flag_write(flags, IFF_BROADCAST, "BROADCAST", buf, buflen);
790 flag_write(flags, IFF_DEBUG, "DEBUG", buf, buflen);
791 flag_write(flags, IFF_LOOPBACK, "LOOPBACK", buf, buflen);
792 flag_write(flags, IFF_POINTOPOINT, "POINTOPOINT", buf, buflen);
793 flag_write(flags, IFF_NOTRAILERS, "NOTRAILERS", buf, buflen);
794 flag_write(flags, IFF_RUNNING, "RUNNING", buf, buflen);
795 flag_write(flags, IFF_NOARP, "NOARP", buf, buflen);
796 flag_write(flags, IFF_PROMISC, "PROMISC", buf, buflen);
797 flag_write(flags, IFF_ALLMULTI, "ALLMULTI", buf, buflen);
798 flag_write(flags, IFF_MASTER, "MASTER", buf, buflen);
799 flag_write(flags, IFF_SLAVE, "SLAVE", buf, buflen);
800 flag_write(flags, IFF_MULTICAST, "MULTICAST", buf, buflen);
801 flag_write(flags, IFF_PORTSEL, "PORTSEL", buf, buflen);
802 flag_write(flags, IFF_AUTOMEDIA, "AUTOMEDIA", buf, buflen);
803 flag_write(flags, IFF_DYNAMIC, "DYNAMIC", buf, buflen);
804
805 return (bufp);
806 }
807
808 const char *rtm_flags2str(uint32_t flags, char *buf, size_t buflen)
809 {
810 const char *bufp = buf;
811
812 *buf = 0;
813 flag_write(flags, RTM_F_NOTIFY, "NOTIFY", buf, buflen);
814 flag_write(flags, RTM_F_CLONED, "CLONED", buf, buflen);
815 flag_write(flags, RTM_F_EQUALIZE, "EQUALIZE", buf, buflen);
816
817 return (bufp);
818 }
819
820 const char *neigh_state2str(uint32_t flags, char *buf, size_t buflen)
821 {
822 const char *bufp = buf;
823
824 *buf = 0;
825 flag_write(flags, NUD_INCOMPLETE, "INCOMPLETE", buf, buflen);
826 flag_write(flags, NUD_REACHABLE, "REACHABLE", buf, buflen);
827 flag_write(flags, NUD_STALE, "STALE", buf, buflen);
828 flag_write(flags, NUD_DELAY, "DELAY", buf, buflen);
829 flag_write(flags, NUD_PROBE, "PROBE", buf, buflen);
830 flag_write(flags, NUD_FAILED, "FAILED", buf, buflen);
831 flag_write(flags, NUD_NOARP, "NOARP", buf, buflen);
832 flag_write(flags, NUD_PERMANENT, "PERMANENT", buf, buflen);
833
834 return (bufp);
835 }
836
837 const char *neigh_flags2str(uint32_t flags, char *buf, size_t buflen)
838 {
839 const char *bufp = buf;
840
841 *buf = 0;
842 flag_write(flags, NTF_USE, "USE", buf, buflen);
843 flag_write(flags, NTF_SELF, "SELF", buf, buflen);
844 flag_write(flags, NTF_MASTER, "MASTER", buf, buflen);
845 flag_write(flags, NTF_PROXY, "PROXY", buf, buflen);
846 flag_write(flags, NTF_EXT_LEARNED, "EXT_LEARNED", buf, buflen);
847 #ifdef NTF_OFFLOADED
848 flag_write(flags, NTF_OFFLOADED, "OFFLOADED", buf, buflen);
849 #endif /* NTF_OFFLOADED */
850 flag_write(flags, NTF_ROUTER, "ROUTER", buf, buflen);
851
852 return (bufp);
853 }
854
855 const char *ifa_flags2str(uint32_t flags, char *buf, size_t buflen)
856 {
857 const char *bufp = buf;
858
859 *buf = 0;
860 flag_write(flags, IFA_F_SECONDARY, "SECONDARY", buf, buflen);
861 flag_write(flags, IFA_F_NODAD, "NODAD", buf, buflen);
862 flag_write(flags, IFA_F_OPTIMISTIC, "OPTIMISTIC", buf, buflen);
863 flag_write(flags, IFA_F_DADFAILED, "DADFAILED", buf, buflen);
864 flag_write(flags, IFA_F_HOMEADDRESS, "HOMEADDRESS", buf, buflen);
865 flag_write(flags, IFA_F_DEPRECATED, "DEPRECATED", buf, buflen);
866 flag_write(flags, IFA_F_TENTATIVE, "TENTATIVE", buf, buflen);
867 flag_write(flags, IFA_F_PERMANENT, "PERMANENT", buf, buflen);
868 flag_write(flags, IFA_F_MANAGETEMPADDR, "MANAGETEMPADDR", buf, buflen);
869 flag_write(flags, IFA_F_NOPREFIXROUTE, "NOPREFIXROUTE", buf, buflen);
870 flag_write(flags, IFA_F_MCAUTOJOIN, "MCAUTOJOIN", buf, buflen);
871 flag_write(flags, IFA_F_STABLE_PRIVACY, "STABLE_PRIVACY", buf, buflen);
872
873 return (bufp);
874 }
875
876 const char *nh_flags2str(uint32_t flags, char *buf, size_t buflen)
877 {
878 const char *bufp = buf;
879
880 *buf = 0;
881 flag_write(flags, RTNH_F_DEAD, "DEAD", buf, buflen);
882 flag_write(flags, RTNH_F_PERVASIVE, "PERVASIVE", buf, buflen);
883 flag_write(flags, RTNH_F_ONLINK, "ONLINK", buf, buflen);
884 flag_write(flags, RTNH_F_OFFLOAD, "OFFLOAD", buf, buflen);
885 flag_write(flags, RTNH_F_LINKDOWN, "LINKDOWN", buf, buflen);
886 flag_write(flags, RTNH_F_UNRESOLVED, "UNRESOLVED", buf, buflen);
887
888 return (bufp);
889 }
890
891 /*
892 * Netlink abstractions.
893 */
894 static void nllink_pdr_dump(struct rtattr *rta, size_t msglen)
895 {
896 size_t plen;
897 uint32_t u32v;
898
899 next_rta:
900 /* Check the header for valid length and for outbound access. */
901 if (RTA_OK(rta, msglen) == 0)
902 return;
903
904 plen = RTA_PAYLOAD(rta);
905 zlog_debug(" linkinfo [len=%d (payload=%zu) type=(%d) %s]",
906 rta->rta_len, plen, rta->rta_type,
907 ifla_pdr_type2str(rta->rta_type));
908 switch (rta->rta_type) {
909 case IFLA_PROTO_DOWN_REASON_MASK:
910 case IFLA_PROTO_DOWN_REASON_VALUE:
911 if (plen < sizeof(uint32_t)) {
912 zlog_debug(" invalid length");
913 break;
914 }
915
916 u32v = *(uint32_t *)RTA_DATA(rta);
917 zlog_debug(" %u", u32v);
918 break;
919
920 default:
921 /* NOTHING: unhandled. */
922 break;
923 }
924
925 /* Get next pointer and start iteration again. */
926 rta = RTA_NEXT(rta, msglen);
927 goto next_rta;
928 }
929
930 static void nllink_linkinfo_dump(struct rtattr *rta, size_t msglen)
931 {
932 size_t plen;
933 char dbuf[128];
934
935 next_rta:
936 /* Check the header for valid length and for outbound access. */
937 if (RTA_OK(rta, msglen) == 0)
938 return;
939
940 plen = RTA_PAYLOAD(rta);
941 zlog_debug(" linkinfo [len=%d (payload=%zu) type=(%d) %s]",
942 rta->rta_len, plen, rta->rta_type,
943 ifla_info_type2str(rta->rta_type));
944 switch (rta->rta_type) {
945 case IFLA_INFO_KIND:
946 if (plen == 0) {
947 zlog_debug(" invalid length");
948 break;
949 }
950
951 snprintf(dbuf, sizeof(dbuf), "%s", (char *)RTA_DATA(rta));
952 zlog_debug(" %s", dbuf);
953 break;
954 case IFLA_INFO_SLAVE_KIND:
955 if (plen == 0) {
956 zlog_debug(" invalid length");
957 break;
958 }
959
960 snprintf(dbuf, sizeof(dbuf), "%s", (char *)RTA_DATA(rta));
961 zlog_debug(" %s", dbuf);
962 break;
963
964 default:
965 /* NOTHING: unhandled. */
966 break;
967 }
968
969 /* Get next pointer and start iteration again. */
970 rta = RTA_NEXT(rta, msglen);
971 goto next_rta;
972 }
973
974 static void nllink_dump(struct ifinfomsg *ifi, size_t msglen)
975 {
976 uint8_t *datap;
977 struct rtattr *rta;
978 size_t plen, it;
979 uint32_t u32v;
980 uint8_t u8v;
981 char bytestr[16];
982 char dbuf[128];
983 unsigned short rta_type;
984
985 /* Get the first attribute and go from there. */
986 rta = IFLA_RTA(ifi);
987 next_rta:
988 /* Check the header for valid length and for outbound access. */
989 if (RTA_OK(rta, msglen) == 0)
990 return;
991
992 plen = RTA_PAYLOAD(rta);
993 rta_type = rta->rta_type & ~NLA_F_NESTED;
994 zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
995 plen, rta_type, rta_type2str(rta_type));
996 switch (rta_type) {
997 case IFLA_IFALIAS:
998 if (plen == 0) {
999 zlog_debug(" invalid length");
1000 break;
1001 }
1002
1003 snprintf(dbuf, sizeof(dbuf), "%s", (char *)RTA_DATA(rta));
1004 zlog_debug(" %s", dbuf);
1005 break;
1006
1007 case IFLA_MTU:
1008 case IFLA_TXQLEN:
1009 case IFLA_NUM_TX_QUEUES:
1010 case IFLA_NUM_RX_QUEUES:
1011 case IFLA_GROUP:
1012 case IFLA_PROMISCUITY:
1013 #ifdef IFLA_GSO_MAX_SEGS
1014 case IFLA_GSO_MAX_SEGS:
1015 #endif /* IFLA_GSO_MAX_SEGS */
1016 #ifdef IFLA_GSO_MAX_SIZE
1017 case IFLA_GSO_MAX_SIZE:
1018 #endif /* IFLA_GSO_MAX_SIZE */
1019 case IFLA_CARRIER_CHANGES:
1020 case IFLA_MASTER:
1021 case IFLA_LINK:
1022 if (plen < sizeof(uint32_t)) {
1023 zlog_debug(" invalid length");
1024 break;
1025 }
1026
1027 u32v = *(uint32_t *)RTA_DATA(rta);
1028 zlog_debug(" %u", u32v);
1029 break;
1030
1031 case IFLA_PROTO_DOWN:
1032 if (plen < sizeof(uint8_t)) {
1033 zlog_debug(" invalid length");
1034 break;
1035 }
1036
1037 u8v = *(uint8_t *)RTA_DATA(rta);
1038 zlog_debug(" %u", u8v);
1039 break;
1040 case IFLA_ADDRESS:
1041 datap = RTA_DATA(rta);
1042 dbuf[0] = 0;
1043 for (it = 0; it < plen; it++) {
1044 snprintf(bytestr, sizeof(bytestr), "%02X:", *datap);
1045 strlcat(dbuf, bytestr, sizeof(dbuf));
1046 datap++;
1047 }
1048 /* Remove trailing ':'. */
1049 if (dbuf[0])
1050 dbuf[strlen(dbuf) - 1] = 0;
1051
1052 zlog_debug(" %s", dbuf[0] ? dbuf : "<empty>");
1053 break;
1054
1055 case IFLA_LINKINFO:
1056 nllink_linkinfo_dump(RTA_DATA(rta), plen);
1057 break;
1058
1059 case IFLA_PROTO_DOWN_REASON:
1060 nllink_pdr_dump(RTA_DATA(rta), plen);
1061 break;
1062
1063 default:
1064 /* NOTHING: unhandled. */
1065 break;
1066 }
1067
1068 /* Get next pointer and start iteration again. */
1069 rta = RTA_NEXT(rta, msglen);
1070 goto next_rta;
1071 }
1072
1073 static void nlroute_dump(struct rtmsg *rtm, size_t msglen)
1074 {
1075 struct rta_mfc_stats *mfc_stats;
1076 struct rtattr *rta;
1077 size_t plen;
1078 uint32_t u32v;
1079 uint64_t u64v;
1080
1081 /* Get the first attribute and go from there. */
1082 rta = RTM_RTA(rtm);
1083 next_rta:
1084 /* Check the header for valid length and for outbound access. */
1085 if (RTA_OK(rta, msglen) == 0)
1086 return;
1087
1088 plen = RTA_PAYLOAD(rta);
1089 zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
1090 plen, rta->rta_type & NLA_TYPE_MASK,
1091 rtm_rta2str(rta->rta_type & NLA_TYPE_MASK));
1092 switch (rta->rta_type & NLA_TYPE_MASK) {
1093 case RTA_IIF:
1094 case RTA_OIF:
1095 case RTA_PRIORITY:
1096 case RTA_TABLE:
1097 case RTA_NH_ID:
1098 u32v = *(uint32_t *)RTA_DATA(rta);
1099 zlog_debug(" %u", u32v);
1100 break;
1101
1102 case RTA_EXPIRES:
1103 u64v = *(uint64_t *)RTA_DATA(rta);
1104 zlog_debug(" %" PRIu64, u64v);
1105 break;
1106
1107 case RTA_GATEWAY:
1108 case RTA_DST:
1109 case RTA_SRC:
1110 case RTA_PREFSRC:
1111 switch (plen) {
1112 case sizeof(struct in_addr):
1113 zlog_debug(" %pI4",
1114 (struct in_addr *)RTA_DATA(rta));
1115 break;
1116 case sizeof(struct in6_addr):
1117 zlog_debug(" %pI6",
1118 (struct in6_addr *)RTA_DATA(rta));
1119 break;
1120 default:
1121 break;
1122 }
1123 break;
1124
1125 case RTA_MFC_STATS:
1126 mfc_stats = (struct rta_mfc_stats *)RTA_DATA(rta);
1127 zlog_debug(" pkts=%ju bytes=%ju wrong_if=%ju",
1128 (uintmax_t)mfc_stats->mfcs_packets,
1129 (uintmax_t)mfc_stats->mfcs_bytes,
1130 (uintmax_t)mfc_stats->mfcs_wrong_if);
1131 break;
1132
1133 default:
1134 /* NOTHING: unhandled. */
1135 break;
1136 }
1137
1138 /* Get next pointer and start iteration again. */
1139 rta = RTA_NEXT(rta, msglen);
1140 goto next_rta;
1141 }
1142
1143 static void nlneigh_dump(struct ndmsg *ndm, size_t msglen)
1144 {
1145 struct rtattr *rta;
1146 uint8_t *datap;
1147 size_t plen, it;
1148 uint16_t vid;
1149 char bytestr[16];
1150 char dbuf[128];
1151 unsigned short rta_type;
1152
1153 #ifndef NDA_RTA
1154 #define NDA_RTA(ndm) \
1155 /* struct ndmsg *ndm; */ \
1156 ((struct rtattr *)(((uint8_t *)(ndm)) \
1157 + NLMSG_ALIGN(sizeof(struct ndmsg))))
1158 #endif /* NDA_RTA */
1159
1160 /* Get the first attribute and go from there. */
1161 rta = NDA_RTA(ndm);
1162 next_rta:
1163 /* Check the header for valid length and for outbound access. */
1164 if (RTA_OK(rta, msglen) == 0)
1165 return;
1166
1167 plen = RTA_PAYLOAD(rta);
1168 rta_type = rta->rta_type & ~NLA_F_NESTED;
1169 zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
1170 plen, rta->rta_type, neigh_rta2str(rta_type));
1171 switch (rta_type) {
1172 case NDA_LLADDR:
1173 datap = RTA_DATA(rta);
1174 dbuf[0] = 0;
1175 for (it = 0; it < plen; it++) {
1176 snprintf(bytestr, sizeof(bytestr), "%02X:", *datap);
1177 strlcat(dbuf, bytestr, sizeof(dbuf));
1178 datap++;
1179 }
1180 /* Remove trailing ':'. */
1181 if (dbuf[0])
1182 dbuf[strlen(dbuf) - 1] = 0;
1183
1184 zlog_debug(" %s", dbuf[0] ? dbuf : "<empty>");
1185 break;
1186
1187 case NDA_DST:
1188 switch (plen) {
1189 case sizeof(struct in_addr):
1190 zlog_debug(" %pI4",
1191 (struct in_addr *)RTA_DATA(rta));
1192 break;
1193 case sizeof(struct in6_addr):
1194 zlog_debug(" %pI6",
1195 (struct in6_addr *)RTA_DATA(rta));
1196 break;
1197 default:
1198 break;
1199 }
1200 break;
1201
1202 case NDA_VLAN:
1203 vid = *(uint16_t *)RTA_DATA(rta);
1204 zlog_debug(" %d", vid);
1205 break;
1206
1207 default:
1208 /* NOTHING: unhandled. */
1209 break;
1210 }
1211
1212 /* Get next pointer and start iteration again. */
1213 rta = RTA_NEXT(rta, msglen);
1214 goto next_rta;
1215 }
1216
1217 static void nlifa_dump(struct ifaddrmsg *ifa, size_t msglen)
1218 {
1219 struct rtattr *rta;
1220 size_t plen;
1221 uint32_t u32v;
1222
1223 /* Get the first attribute and go from there. */
1224 rta = IFA_RTA(ifa);
1225 next_rta:
1226 /* Check the header for valid length and for outbound access. */
1227 if (RTA_OK(rta, msglen) == 0)
1228 return;
1229
1230 plen = RTA_PAYLOAD(rta);
1231 zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
1232 plen, rta->rta_type, ifa_rta2str(rta->rta_type));
1233 switch (rta->rta_type) {
1234 case IFA_UNSPEC:
1235 u32v = *(uint32_t *)RTA_DATA(rta);
1236 zlog_debug(" %u", u32v);
1237 break;
1238
1239 case IFA_LABEL:
1240 zlog_debug(" %s", (const char *)RTA_DATA(rta));
1241 break;
1242
1243 case IFA_ADDRESS:
1244 case IFA_LOCAL:
1245 case IFA_BROADCAST:
1246 switch (plen) {
1247 case 4:
1248 zlog_debug(" %pI4",
1249 (struct in_addr *)RTA_DATA(rta));
1250 break;
1251 case 16:
1252 zlog_debug(" %pI6",
1253 (struct in6_addr *)RTA_DATA(rta));
1254 break;
1255 default:
1256 break;
1257 }
1258 break;
1259
1260 default:
1261 /* NOTHING: unhandled. */
1262 break;
1263 }
1264
1265 /* Get next pointer and start iteration again. */
1266 rta = RTA_NEXT(rta, msglen);
1267 goto next_rta;
1268 }
1269
1270 static void nltnl_dump(struct tunnel_msg *tnlm, size_t msglen)
1271 {
1272 struct rtattr *attr;
1273 vni_t vni_start = 0, vni_end = 0;
1274 struct rtattr *ttb[VXLAN_VNIFILTER_ENTRY_MAX + 1];
1275 uint8_t rta_type;
1276
1277 attr = TUNNEL_RTA(tnlm);
1278 next_attr:
1279 /* Check the header for valid length and for outbound access. */
1280 if (RTA_OK(attr, msglen) == 0)
1281 return;
1282
1283 rta_type = attr->rta_type & NLA_TYPE_MASK;
1284
1285 if (rta_type != VXLAN_VNIFILTER_ENTRY) {
1286 attr = RTA_NEXT(attr, msglen);
1287 goto next_attr;
1288 }
1289
1290 memset(ttb, 0, sizeof(ttb));
1291
1292 netlink_parse_rtattr_flags(ttb, VXLAN_VNIFILTER_ENTRY_MAX,
1293 RTA_DATA(attr), RTA_PAYLOAD(attr),
1294 NLA_F_NESTED);
1295
1296 if (ttb[VXLAN_VNIFILTER_ENTRY_START])
1297 vni_start =
1298 *(uint32_t *)RTA_DATA(ttb[VXLAN_VNIFILTER_ENTRY_START]);
1299
1300 if (ttb[VXLAN_VNIFILTER_ENTRY_END])
1301 vni_end = *(uint32_t *)RTA_DATA(ttb[VXLAN_VNIFILTER_ENTRY_END]);
1302 zlog_debug(" vni_start %u, vni_end %u", vni_start, vni_end);
1303
1304 attr = RTA_NEXT(attr, msglen);
1305 goto next_attr;
1306 }
1307
1308 static const char *lwt_type2str(uint16_t type)
1309 {
1310 switch (type) {
1311 case LWTUNNEL_ENCAP_NONE:
1312 return "NONE";
1313 case LWTUNNEL_ENCAP_MPLS:
1314 return "MPLS";
1315 case LWTUNNEL_ENCAP_IP:
1316 return "IPv4";
1317 case LWTUNNEL_ENCAP_ILA:
1318 return "ILA";
1319 case LWTUNNEL_ENCAP_IP6:
1320 return "IPv6";
1321 case LWTUNNEL_ENCAP_SEG6:
1322 return "SEG6";
1323 case LWTUNNEL_ENCAP_BPF:
1324 return "BPF";
1325 case LWTUNNEL_ENCAP_SEG6_LOCAL:
1326 return "SEG6_LOCAL";
1327 default:
1328 return "UNKNOWN";
1329 }
1330 }
1331
1332 static const char *nhg_type2str(uint16_t type)
1333 {
1334 switch (type) {
1335 case NEXTHOP_GRP_TYPE_MPATH:
1336 return "MULTIPATH";
1337 case NEXTHOP_GRP_TYPE_RES:
1338 return "RESILIENT MULTIPATH";
1339 default:
1340 return "UNKNOWN";
1341 }
1342 }
1343
1344 static void nlnh_dump(struct nhmsg *nhm, size_t msglen)
1345 {
1346 struct rtattr *rta;
1347 int ifindex;
1348 size_t plen;
1349 uint16_t u16v;
1350 uint32_t u32v;
1351 unsigned long count, i;
1352 struct nexthop_grp *nhgrp;
1353 unsigned short rta_type;
1354
1355 rta = RTM_NHA(nhm);
1356
1357 next_rta:
1358 /* Check the header for valid length and for outbound access. */
1359 if (RTA_OK(rta, msglen) == 0)
1360 return;
1361
1362 plen = RTA_PAYLOAD(rta);
1363 rta_type = rta->rta_type & ~NLA_F_NESTED;
1364 zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
1365 plen, rta->rta_type, nhm_rta2str(rta_type));
1366 switch (rta_type) {
1367 case NHA_ID:
1368 u32v = *(uint32_t *)RTA_DATA(rta);
1369 zlog_debug(" %u", u32v);
1370 break;
1371 case NHA_GROUP:
1372 nhgrp = (struct nexthop_grp *)RTA_DATA(rta);
1373 count = (RTA_PAYLOAD(rta) / sizeof(*nhgrp));
1374 if (count == 0
1375 || (count * sizeof(*nhgrp)) != RTA_PAYLOAD(rta)) {
1376 zlog_debug(" invalid nexthop group received");
1377 return;
1378 }
1379
1380 for (i = 0; i < count; i++)
1381 zlog_debug(" id %d weight %d", nhgrp[i].id,
1382 nhgrp[i].weight);
1383 break;
1384 case NHA_ENCAP_TYPE:
1385 u16v = *(uint16_t *)RTA_DATA(rta);
1386 zlog_debug(" %s", lwt_type2str(u16v));
1387 break;
1388 case NHA_GROUP_TYPE:
1389 u16v = *(uint16_t *)RTA_DATA(rta);
1390 zlog_debug(" %s", nhg_type2str(u16v));
1391 break;
1392 case NHA_BLACKHOLE:
1393 /* NOTHING */
1394 break;
1395 case NHA_OIF:
1396 ifindex = *(int *)RTA_DATA(rta);
1397 zlog_debug(" %d", ifindex);
1398 break;
1399 case NHA_GATEWAY:
1400 switch (nhm->nh_family) {
1401 case AF_INET:
1402 zlog_debug(" %pI4",
1403 (struct in_addr *)RTA_DATA(rta));
1404 break;
1405 case AF_INET6:
1406 zlog_debug(" %pI6",
1407 (struct in6_addr *)RTA_DATA(rta));
1408 break;
1409
1410 default:
1411 zlog_debug(" invalid family %d", nhm->nh_family);
1412 break;
1413 }
1414 break;
1415 case NHA_ENCAP:
1416 /* TODO: handle MPLS labels. */
1417 zlog_debug(" unparsed MPLS labels");
1418 break;
1419 case NHA_GROUPS:
1420 /* TODO: handle this message. */
1421 zlog_debug(" unparsed GROUPS message");
1422 break;
1423
1424 default:
1425 /* NOTHING: unhandled. */
1426 break;
1427 }
1428
1429 /* Get next pointer and start iteration again. */
1430 rta = RTA_NEXT(rta, msglen);
1431 goto next_rta;
1432 }
1433
1434 static void nlrule_dump(struct fib_rule_hdr *frh, size_t msglen)
1435 {
1436 struct rtattr *rta;
1437 size_t plen;
1438 uint8_t u8v;
1439 uint32_t u32v;
1440 int32_t s32v;
1441 uint64_t u64v;
1442 char dbuf[128];
1443 struct fib_rule_uid_range *u_range;
1444 struct fib_rule_port_range *p_range;
1445
1446 /* Get the first attribute and go from there. */
1447 rta = RTM_RTA(frh);
1448 next_rta:
1449 /* Check the header for valid length and for outbound access. */
1450 if (RTA_OK(rta, msglen) == 0)
1451 return;
1452
1453 plen = RTA_PAYLOAD(rta);
1454 zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
1455 plen, rta->rta_type, frh_rta2str(rta->rta_type));
1456 switch (rta->rta_type) {
1457 case FRA_DST:
1458 case FRA_SRC:
1459 switch (plen) {
1460 case sizeof(struct in_addr):
1461 zlog_debug(" %pI4",
1462 (struct in_addr *)RTA_DATA(rta));
1463 break;
1464 case sizeof(struct in6_addr):
1465 zlog_debug(" %pI6",
1466 (struct in6_addr *)RTA_DATA(rta));
1467 break;
1468 default:
1469 break;
1470 }
1471 break;
1472
1473 case FRA_IIFNAME:
1474 case FRA_OIFNAME:
1475 snprintf(dbuf, sizeof(dbuf), "%s", (char *)RTA_DATA(rta));
1476 zlog_debug(" %s", dbuf);
1477 break;
1478
1479 case FRA_GOTO:
1480 case FRA_UNUSED2:
1481 case FRA_PRIORITY:
1482 case FRA_UNUSED3:
1483 case FRA_UNUSED4:
1484 case FRA_UNUSED5:
1485 case FRA_FWMARK:
1486 case FRA_FLOW:
1487 case FRA_TABLE:
1488 case FRA_FWMASK:
1489 u32v = *(uint32_t *)RTA_DATA(rta);
1490 zlog_debug(" %u", u32v);
1491 break;
1492
1493 case FRA_SUPPRESS_IFGROUP:
1494 case FRA_SUPPRESS_PREFIXLEN:
1495 s32v = *(int32_t *)RTA_DATA(rta);
1496 zlog_debug(" %d", s32v);
1497 break;
1498
1499 case FRA_TUN_ID:
1500 u64v = *(uint64_t *)RTA_DATA(rta);
1501 zlog_debug(" %" PRIu64, u64v);
1502 break;
1503
1504 case FRA_L3MDEV:
1505 case FRA_PROTOCOL:
1506 case FRA_IP_PROTO:
1507 u8v = *(uint8_t *)RTA_DATA(rta);
1508 zlog_debug(" %u", u8v);
1509 break;
1510
1511 case FRA_UID_RANGE:
1512 u_range = (struct fib_rule_uid_range *)RTA_DATA(rta);
1513 if (u_range->start == u_range->end)
1514 zlog_debug(" %u", u_range->start);
1515 else
1516 zlog_debug(" %u-%u", u_range->start, u_range->end);
1517 break;
1518
1519 case FRA_SPORT_RANGE:
1520 case FRA_DPORT_RANGE:
1521 p_range = (struct fib_rule_port_range *)RTA_DATA(rta);
1522 if (p_range->start == p_range->end)
1523 zlog_debug(" %u", p_range->start);
1524 else
1525 zlog_debug(" %u-%u", p_range->start, p_range->end);
1526 break;
1527
1528 case FRA_PAD: /* fallthrough */
1529 default:
1530 /* NOTHING: unhandled. */
1531 break;
1532 }
1533
1534 /* Get next pointer and start iteration again. */
1535 rta = RTA_NEXT(rta, msglen);
1536 goto next_rta;
1537 }
1538
1539 static void nlncm_dump(const struct netconfmsg *ncm, size_t msglen)
1540 {
1541 const struct rtattr *rta;
1542 size_t plen;
1543 uint32_t ival;
1544
1545 rta = (void *)((const char *)ncm +
1546 NLMSG_ALIGN(sizeof(struct netconfmsg)));
1547
1548 next_rta:
1549 /* Check the attr header for valid length. */
1550 if (RTA_OK(rta, msglen) == 0)
1551 return;
1552
1553 plen = RTA_PAYLOAD(rta);
1554
1555 zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
1556 plen, rta->rta_type, ncm_rta2str(rta->rta_type));
1557
1558 switch (rta->rta_type) {
1559 case NETCONFA_IFINDEX:
1560 ival = *(uint32_t *)RTA_DATA(rta);
1561 zlog_debug(" %d", (int32_t)ival);
1562 break;
1563
1564 /* Most attrs are just on/off. */
1565 case NETCONFA_FORWARDING:
1566 case NETCONFA_RP_FILTER:
1567 case NETCONFA_MC_FORWARDING:
1568 case NETCONFA_PROXY_NEIGH:
1569 case NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN:
1570 case NETCONFA_INPUT:
1571 case NETCONFA_BC_FORWARDING:
1572 ival = *(uint32_t *)RTA_DATA(rta);
1573 dump_on_off(ival, " ");
1574 break;
1575 default:
1576 /* NOTHING: unhandled. */
1577 break;
1578 }
1579
1580 /* Get next pointer and start iteration again. */
1581 rta = RTA_NEXT(rta, msglen);
1582 goto next_rta;
1583 }
1584
1585 void nl_dump(void *msg, size_t msglen)
1586 {
1587 struct nlmsghdr *nlmsg = msg;
1588 struct nlmsgerr *nlmsgerr;
1589 struct rtgenmsg *rtgen;
1590 struct ifaddrmsg *ifa;
1591 struct ndmsg *ndm;
1592 struct rtmsg *rtm;
1593 struct nhmsg *nhm;
1594 struct netconfmsg *ncm;
1595 struct ifinfomsg *ifi;
1596 struct tunnel_msg *tnlm;
1597 struct fib_rule_hdr *frh;
1598 char fbuf[128];
1599 char ibuf[128];
1600
1601 next_header:
1602 zlog_debug(
1603 "nlmsghdr [len=%u type=(%d) %s flags=(0x%04x) {%s} seq=%u pid=%u]",
1604 nlmsg->nlmsg_len, nlmsg->nlmsg_type,
1605 nlmsg_type2str(nlmsg->nlmsg_type), nlmsg->nlmsg_flags,
1606 nlmsg_flags2str(nlmsg->nlmsg_flags, fbuf, sizeof(fbuf)),
1607 nlmsg->nlmsg_seq, nlmsg->nlmsg_pid);
1608
1609 switch (nlmsg->nlmsg_type) {
1610 /* Generic. */
1611 case NLMSG_NOOP:
1612 break;
1613 case NLMSG_ERROR:
1614 nlmsgerr = NLMSG_DATA(nlmsg);
1615 zlog_debug(" nlmsgerr [error=(%d) %s]", nlmsgerr->error,
1616 strerror(-nlmsgerr->error));
1617 break;
1618 case NLMSG_DONE:
1619 return;
1620 case NLMSG_OVERRUN:
1621 break;
1622
1623 /* RTM. */
1624 case RTM_NEWLINK:
1625 case RTM_DELLINK:
1626 case RTM_SETLINK:
1627 ifi = NLMSG_DATA(nlmsg);
1628 zlog_debug(
1629 " ifinfomsg [family=%d type=(%d) %s index=%d flags=0x%04x {%s}]",
1630 ifi->ifi_family, ifi->ifi_type,
1631 ifi_type2str(ifi->ifi_type), ifi->ifi_index,
1632 ifi->ifi_flags,
1633 if_flags2str(ifi->ifi_flags, ibuf, sizeof(ibuf)));
1634 nllink_dump(ifi, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
1635 break;
1636 case RTM_GETLINK:
1637 rtgen = NLMSG_DATA(nlmsg);
1638 zlog_debug(" rtgen [family=(%d) %s]", rtgen->rtgen_family,
1639 af_type2str(rtgen->rtgen_family));
1640 break;
1641
1642 case RTM_NEWROUTE:
1643 case RTM_DELROUTE:
1644 case RTM_GETROUTE:
1645 rtm = NLMSG_DATA(nlmsg);
1646 zlog_debug(
1647 " rtmsg [family=(%d) %s dstlen=%d srclen=%d tos=%d table=%d protocol=(%d) %s scope=(%d) %s type=(%d) %s flags=0x%04x {%s}]",
1648 rtm->rtm_family, af_type2str(rtm->rtm_family),
1649 rtm->rtm_dst_len, rtm->rtm_src_len, rtm->rtm_tos,
1650 rtm->rtm_table, rtm->rtm_protocol,
1651 rtm_protocol2str(rtm->rtm_protocol), rtm->rtm_scope,
1652 rtm_scope2str(rtm->rtm_scope), rtm->rtm_type,
1653 rtm_type2str(rtm->rtm_type), rtm->rtm_flags,
1654 rtm_flags2str(rtm->rtm_flags, fbuf, sizeof(fbuf)));
1655 nlroute_dump(rtm,
1656 nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
1657 break;
1658
1659 case RTM_NEWNEIGH:
1660 case RTM_DELNEIGH:
1661 ndm = NLMSG_DATA(nlmsg);
1662 zlog_debug(
1663 " ndm [family=%d (%s) ifindex=%d state=0x%04x {%s} flags=0x%04x {%s} type=%d (%s)]",
1664 ndm->ndm_family, af_type2str(ndm->ndm_family),
1665 ndm->ndm_ifindex, ndm->ndm_state,
1666 neigh_state2str(ndm->ndm_state, ibuf, sizeof(ibuf)),
1667 ndm->ndm_flags,
1668 neigh_flags2str(ndm->ndm_flags, fbuf, sizeof(fbuf)),
1669 ndm->ndm_type, rtm_type2str(ndm->ndm_type));
1670 nlneigh_dump(ndm,
1671 nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ndm)));
1672 break;
1673
1674 case RTM_NEWRULE:
1675 case RTM_DELRULE:
1676 frh = NLMSG_DATA(nlmsg);
1677 zlog_debug(
1678 " frh [family=%d (%s) dst_len=%d src_len=%d tos=%d table=%d res1=%d res2=%d action=%d (%s) flags=0x%x]",
1679 frh->family, af_type2str(frh->family), frh->dst_len,
1680 frh->src_len, frh->tos, frh->table, frh->res1,
1681 frh->res2, frh->action, frh_action2str(frh->action),
1682 frh->flags);
1683 nlrule_dump(frh, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*frh)));
1684 break;
1685
1686
1687 case RTM_NEWADDR:
1688 case RTM_DELADDR:
1689 ifa = NLMSG_DATA(nlmsg);
1690 zlog_debug(
1691 " ifa [family=(%d) %s prefixlen=%d flags=0x%04x {%s} scope=%d index=%u]",
1692 ifa->ifa_family, af_type2str(ifa->ifa_family),
1693 ifa->ifa_prefixlen, ifa->ifa_flags,
1694 if_flags2str(ifa->ifa_flags, fbuf, sizeof(fbuf)),
1695 ifa->ifa_scope, ifa->ifa_index);
1696 nlifa_dump(ifa, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
1697 break;
1698
1699 case RTM_NEWNEXTHOP:
1700 case RTM_DELNEXTHOP:
1701 case RTM_GETNEXTHOP:
1702 nhm = NLMSG_DATA(nlmsg);
1703 zlog_debug(
1704 " nhm [family=(%d) %s scope=(%d) %s protocol=(%d) %s flags=0x%08x {%s}]",
1705 nhm->nh_family, af_type2str(nhm->nh_family),
1706 nhm->nh_scope, rtm_scope2str(nhm->nh_scope),
1707 nhm->nh_protocol, rtm_protocol2str(nhm->nh_protocol),
1708 nhm->nh_flags,
1709 nh_flags2str(nhm->nh_flags, fbuf, sizeof(fbuf)));
1710 nlnh_dump(nhm, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*nhm)));
1711 break;
1712
1713 case RTM_NEWTUNNEL:
1714 case RTM_DELTUNNEL:
1715 case RTM_GETTUNNEL:
1716 tnlm = NLMSG_DATA(nlmsg);
1717 zlog_debug(" tnlm [family=(%d) %s ifindex=%d ", tnlm->family,
1718 af_type2str(tnlm->family), tnlm->ifindex);
1719 nltnl_dump(tnlm,
1720 nlmsg->nlmsg_len -
1721 NLMSG_LENGTH(sizeof(struct tunnel_msg)));
1722 break;
1723
1724
1725 case RTM_NEWNETCONF:
1726 case RTM_DELNETCONF:
1727 ncm = NLMSG_DATA(nlmsg);
1728 zlog_debug(" ncm [family=%s (%d)]",
1729 af_type2str(ncm->ncm_family), ncm->ncm_family);
1730 nlncm_dump(ncm, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ncm)));
1731 break;
1732
1733 default:
1734 break;
1735 }
1736
1737 /*
1738 * Try to get the next header. There should only be more
1739 * messages if this header was flagged as MULTI, otherwise just
1740 * end it here.
1741 */
1742 nlmsg = NLMSG_NEXT(nlmsg, msglen);
1743 if (NLMSG_OK(nlmsg, msglen) == 0)
1744 return;
1745
1746 goto next_header;
1747 }
1748
1749 #endif /* NETLINK_DEBUG */