2 * libnetlink.c RTnetlink service routines.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
18 #include <net/if_arp.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
25 #include <linux/fib_rules.h>
26 #include <linux/if_addrlabel.h>
27 #include <linux/if_bridge.h>
28 #include <linux/nexthop.h>
30 #include "libnetlink.h"
33 #define __aligned(x) __attribute__((aligned(x)))
36 #define SOL_NETLINK 270
40 #define MIN(a, b) ((a) < (b) ? (a) : (b))
43 int rcvbuf
= 1024 * 1024;
46 #include <libmnl/libmnl.h>
48 static const enum mnl_attr_data_type extack_policy
[NLMSGERR_ATTR_MAX
+ 1] = {
49 [NLMSGERR_ATTR_MSG
] = MNL_TYPE_NUL_STRING
,
50 [NLMSGERR_ATTR_OFFS
] = MNL_TYPE_U32
,
53 static int err_attr_cb(const struct nlattr
*attr
, void *data
)
55 const struct nlattr
**tb
= data
;
58 if (mnl_attr_type_valid(attr
, NLMSGERR_ATTR_MAX
) < 0) {
59 fprintf(stderr
, "Invalid extack attribute\n");
63 type
= mnl_attr_get_type(attr
);
64 if (mnl_attr_validate(attr
, extack_policy
[type
]) < 0) {
65 fprintf(stderr
, "extack attribute %d failed validation\n",
74 static void print_ext_ack_msg(bool is_err
, const char *msg
)
76 fprintf(stderr
, "%s: %s", is_err
? "Error" : "Warning", msg
);
77 if (msg
[strlen(msg
) - 1] != '.')
79 fprintf(stderr
, "\n");
82 /* dump netlink extended ack error message */
83 int nl_dump_ext_ack(const struct nlmsghdr
*nlh
, nl_ext_ack_fn_t errfn
)
85 struct nlattr
*tb
[NLMSGERR_ATTR_MAX
+ 1] = {};
86 const struct nlmsgerr
*err
= mnl_nlmsg_get_payload(nlh
);
87 const struct nlmsghdr
*err_nlh
= NULL
;
88 unsigned int hlen
= sizeof(*err
);
89 const char *msg
= NULL
;
92 /* no TLVs, nothing to do here */
93 if (!(nlh
->nlmsg_flags
& NLM_F_ACK_TLVS
))
96 /* if NLM_F_CAPPED is set then the inner err msg was capped */
97 if (!(nlh
->nlmsg_flags
& NLM_F_CAPPED
))
98 hlen
+= mnl_nlmsg_get_payload_len(&err
->msg
);
100 if (mnl_attr_parse(nlh
, hlen
, err_attr_cb
, tb
) != MNL_CB_OK
)
103 if (tb
[NLMSGERR_ATTR_MSG
])
104 msg
= mnl_attr_get_str(tb
[NLMSGERR_ATTR_MSG
]);
106 if (tb
[NLMSGERR_ATTR_OFFS
]) {
107 off
= mnl_attr_get_u32(tb
[NLMSGERR_ATTR_OFFS
]);
109 if (off
> nlh
->nlmsg_len
) {
111 "Invalid offset for NLMSGERR_ATTR_OFFS\n");
113 } else if (!(nlh
->nlmsg_flags
& NLM_F_CAPPED
))
118 return errfn(msg
, off
, err_nlh
);
120 if (msg
&& *msg
!= '\0') {
121 bool is_err
= !!err
->error
;
123 print_ext_ack_msg(is_err
, msg
);
124 return is_err
? 1 : 0;
130 int nl_dump_ext_ack_done(const struct nlmsghdr
*nlh
, int error
)
132 struct nlattr
*tb
[NLMSGERR_ATTR_MAX
+ 1] = {};
133 unsigned int hlen
= sizeof(int);
134 const char *msg
= NULL
;
136 if (mnl_attr_parse(nlh
, hlen
, err_attr_cb
, tb
) != MNL_CB_OK
)
139 if (tb
[NLMSGERR_ATTR_MSG
])
140 msg
= mnl_attr_get_str(tb
[NLMSGERR_ATTR_MSG
]);
142 if (msg
&& *msg
!= '\0') {
143 bool is_err
= !!error
;
145 print_ext_ack_msg(is_err
, msg
);
146 return is_err
? 1 : 0;
152 #warning "libmnl required for error support"
154 /* No extended error ack without libmnl */
155 int nl_dump_ext_ack(const struct nlmsghdr
*nlh
, nl_ext_ack_fn_t errfn
)
160 int nl_dump_ext_ack_done(const struct nlmsghdr
*nlh
, int error
)
166 /* Older kernels may not support strict dump and filtering */
167 void rtnl_set_strict_dump(struct rtnl_handle
*rth
)
171 if (setsockopt(rth
->fd
, SOL_NETLINK
, NETLINK_GET_STRICT_CHK
,
172 &one
, sizeof(one
)) < 0)
175 rth
->flags
|= RTNL_HANDLE_F_STRICT_CHK
;
178 int rtnl_add_nl_group(struct rtnl_handle
*rth
, unsigned int group
)
180 return setsockopt(rth
->fd
, SOL_NETLINK
, NETLINK_ADD_MEMBERSHIP
,
181 &group
, sizeof(group
));
184 void rtnl_close(struct rtnl_handle
*rth
)
192 int rtnl_open_byproto(struct rtnl_handle
*rth
, unsigned int subscriptions
,
199 memset(rth
, 0, sizeof(*rth
));
201 rth
->proto
= protocol
;
202 rth
->fd
= socket(AF_NETLINK
, SOCK_RAW
| SOCK_CLOEXEC
, protocol
);
204 perror("Cannot open netlink socket");
208 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_SNDBUF
,
209 &sndbuf
, sizeof(sndbuf
)) < 0) {
214 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_RCVBUF
,
215 &rcvbuf
, sizeof(rcvbuf
)) < 0) {
220 /* Older kernels may no support extended ACK reporting */
221 setsockopt(rth
->fd
, SOL_NETLINK
, NETLINK_EXT_ACK
,
224 memset(&rth
->local
, 0, sizeof(rth
->local
));
225 rth
->local
.nl_family
= AF_NETLINK
;
226 rth
->local
.nl_groups
= subscriptions
;
228 if (bind(rth
->fd
, (struct sockaddr
*)&rth
->local
,
229 sizeof(rth
->local
)) < 0) {
230 perror("Cannot bind netlink socket");
233 addr_len
= sizeof(rth
->local
);
234 if (getsockname(rth
->fd
, (struct sockaddr
*)&rth
->local
,
236 perror("Cannot getsockname");
239 if (addr_len
!= sizeof(rth
->local
)) {
240 fprintf(stderr
, "Wrong address length %d\n", addr_len
);
243 if (rth
->local
.nl_family
!= AF_NETLINK
) {
244 fprintf(stderr
, "Wrong address family %d\n",
245 rth
->local
.nl_family
);
248 rth
->seq
= time(NULL
);
252 int rtnl_open(struct rtnl_handle
*rth
, unsigned int subscriptions
)
254 return rtnl_open_byproto(rth
, subscriptions
, NETLINK_ROUTE
);
257 int rtnl_nexthopdump_req(struct rtnl_handle
*rth
, int family
,
258 req_filter_fn_t filter_fn
)
265 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct nhmsg
)),
266 .nlh
.nlmsg_type
= RTM_GETNEXTHOP
,
267 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
268 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
269 .nhm
.nh_family
= family
,
275 err
= filter_fn(&req
.nlh
, sizeof(req
));
280 return send(rth
->fd
, &req
, sizeof(req
), 0);
283 int rtnl_addrdump_req(struct rtnl_handle
*rth
, int family
,
284 req_filter_fn_t filter_fn
)
288 struct ifaddrmsg ifm
;
291 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifaddrmsg
)),
292 .nlh
.nlmsg_type
= RTM_GETADDR
,
293 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
294 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
295 .ifm
.ifa_family
= family
,
301 err
= filter_fn(&req
.nlh
, sizeof(req
));
306 return send(rth
->fd
, &req
, sizeof(req
), 0);
309 int rtnl_addrlbldump_req(struct rtnl_handle
*rth
, int family
)
313 struct ifaddrlblmsg ifal
;
315 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifaddrlblmsg
)),
316 .nlh
.nlmsg_type
= RTM_GETADDRLABEL
,
317 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
318 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
319 .ifal
.ifal_family
= family
,
322 return send(rth
->fd
, &req
, sizeof(req
), 0);
325 int rtnl_routedump_req(struct rtnl_handle
*rth
, int family
,
326 req_filter_fn_t filter_fn
)
333 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
)),
334 .nlh
.nlmsg_type
= RTM_GETROUTE
,
335 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
336 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
337 .rtm
.rtm_family
= family
,
343 err
= filter_fn(&req
.nlh
, sizeof(req
));
348 return send(rth
->fd
, &req
, sizeof(req
), 0);
351 int rtnl_ruledump_req(struct rtnl_handle
*rth
, int family
)
355 struct fib_rule_hdr frh
;
357 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct fib_rule_hdr
)),
358 .nlh
.nlmsg_type
= RTM_GETRULE
,
359 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
360 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
364 return send(rth
->fd
, &req
, sizeof(req
), 0);
367 int rtnl_neighdump_req(struct rtnl_handle
*rth
, int family
,
368 req_filter_fn_t filter_fn
)
375 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ndmsg
)),
376 .nlh
.nlmsg_type
= RTM_GETNEIGH
,
377 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
378 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
379 .ndm
.ndm_family
= family
,
385 err
= filter_fn(&req
.nlh
, sizeof(req
));
390 return send(rth
->fd
, &req
, sizeof(req
), 0);
393 int rtnl_neightbldump_req(struct rtnl_handle
*rth
, int family
)
397 struct ndtmsg ndtmsg
;
399 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ndtmsg
)),
400 .nlh
.nlmsg_type
= RTM_GETNEIGHTBL
,
401 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
402 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
403 .ndtmsg
.ndtm_family
= family
,
406 return send(rth
->fd
, &req
, sizeof(req
), 0);
409 int rtnl_mdbdump_req(struct rtnl_handle
*rth
, int family
)
413 struct br_port_msg bpm
;
415 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct br_port_msg
)),
416 .nlh
.nlmsg_type
= RTM_GETMDB
,
417 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
418 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
419 .bpm
.family
= family
,
422 return send(rth
->fd
, &req
, sizeof(req
), 0);
425 int rtnl_netconfdump_req(struct rtnl_handle
*rth
, int family
)
429 struct netconfmsg ncm
;
430 char buf
[0] __aligned(NLMSG_ALIGNTO
);
432 .nlh
.nlmsg_len
= NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct netconfmsg
))),
433 .nlh
.nlmsg_type
= RTM_GETNETCONF
,
434 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
435 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
436 .ncm
.ncm_family
= family
,
439 return send(rth
->fd
, &req
, sizeof(req
), 0);
442 int rtnl_nsiddump_req_filter_fn(struct rtnl_handle
*rth
, int family
,
443 req_filter_fn_t filter_fn
)
450 .nlh
.nlmsg_len
= NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtgenmsg
))),
451 .nlh
.nlmsg_type
= RTM_GETNSID
,
452 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
453 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
454 .rtm
.rtgen_family
= family
,
461 err
= filter_fn(&req
.nlh
, sizeof(req
));
465 return send(rth
->fd
, &req
, req
.nlh
.nlmsg_len
, 0);
468 static int __rtnl_linkdump_req(struct rtnl_handle
*rth
, int family
)
472 struct ifinfomsg ifm
;
474 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
475 .nlh
.nlmsg_type
= RTM_GETLINK
,
476 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
477 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
478 .ifm
.ifi_family
= family
,
481 return send(rth
->fd
, &req
, sizeof(req
), 0);
484 int rtnl_linkdump_req(struct rtnl_handle
*rth
, int family
)
486 if (family
== AF_UNSPEC
)
487 return rtnl_linkdump_req_filter(rth
, family
, RTEXT_FILTER_VF
);
489 return __rtnl_linkdump_req(rth
, family
);
492 int rtnl_linkdump_req_filter(struct rtnl_handle
*rth
, int family
,
495 if (family
== AF_UNSPEC
|| family
== AF_BRIDGE
) {
498 struct ifinfomsg ifm
;
499 /* attribute has to be NLMSG aligned */
500 struct rtattr ext_req
__aligned(NLMSG_ALIGNTO
);
501 __u32 ext_filter_mask
;
503 .nlh
.nlmsg_len
= sizeof(req
),
504 .nlh
.nlmsg_type
= RTM_GETLINK
,
505 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
506 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
507 .ifm
.ifi_family
= family
,
508 .ext_req
.rta_type
= IFLA_EXT_MASK
,
509 .ext_req
.rta_len
= RTA_LENGTH(sizeof(__u32
)),
510 .ext_filter_mask
= filt_mask
,
513 return send(rth
->fd
, &req
, sizeof(req
), 0);
516 return __rtnl_linkdump_req(rth
, family
);
519 int rtnl_linkdump_req_filter_fn(struct rtnl_handle
*rth
, int family
,
520 req_filter_fn_t filter_fn
)
522 if (family
== AF_UNSPEC
|| family
== AF_PACKET
) {
525 struct ifinfomsg ifm
;
528 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
529 .nlh
.nlmsg_type
= RTM_GETLINK
,
530 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
531 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
532 .ifm
.ifi_family
= family
,
539 err
= filter_fn(&req
.nlh
, sizeof(req
));
543 return send(rth
->fd
, &req
, req
.nlh
.nlmsg_len
, 0);
546 return __rtnl_linkdump_req(rth
, family
);
549 int rtnl_fdb_linkdump_req_filter_fn(struct rtnl_handle
*rth
,
550 req_filter_fn_t filter_fn
)
554 struct ifinfomsg ifm
;
557 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
558 .nlh
.nlmsg_type
= RTM_GETNEIGH
,
559 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
560 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
561 .ifm
.ifi_family
= PF_BRIDGE
,
565 err
= filter_fn(&req
.nlh
, sizeof(req
));
569 return send(rth
->fd
, &req
, sizeof(req
), 0);
572 int rtnl_statsdump_req_filter(struct rtnl_handle
*rth
, int fam
, __u32 filt_mask
)
576 struct if_stats_msg ifsm
;
579 memset(&req
, 0, sizeof(req
));
580 req
.nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct if_stats_msg
));
581 req
.nlh
.nlmsg_type
= RTM_GETSTATS
;
582 req
.nlh
.nlmsg_flags
= NLM_F_DUMP
|NLM_F_REQUEST
;
583 req
.nlh
.nlmsg_pid
= 0;
584 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
585 req
.ifsm
.family
= fam
;
586 req
.ifsm
.filter_mask
= filt_mask
;
588 return send(rth
->fd
, &req
, sizeof(req
), 0);
591 int rtnl_send(struct rtnl_handle
*rth
, const void *buf
, int len
)
593 return send(rth
->fd
, buf
, len
, 0);
596 int rtnl_send_check(struct rtnl_handle
*rth
, const void *buf
, int len
)
602 status
= send(rth
->fd
, buf
, len
, 0);
606 /* Check for immediate errors */
607 status
= recv(rth
->fd
, resp
, sizeof(resp
), MSG_DONTWAIT
|MSG_PEEK
);
614 for (h
= (struct nlmsghdr
*)resp
; NLMSG_OK(h
, status
);
615 h
= NLMSG_NEXT(h
, status
)) {
616 if (h
->nlmsg_type
== NLMSG_ERROR
) {
617 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
619 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
620 fprintf(stderr
, "ERROR truncated\n");
630 int rtnl_dump_request(struct rtnl_handle
*rth
, int type
, void *req
, int len
)
632 struct nlmsghdr nlh
= {
633 .nlmsg_len
= NLMSG_LENGTH(len
),
635 .nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
636 .nlmsg_seq
= rth
->dump
= ++rth
->seq
,
638 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
639 struct iovec iov
[2] = {
640 { .iov_base
= &nlh
, .iov_len
= sizeof(nlh
) },
641 { .iov_base
= req
, .iov_len
= len
}
643 struct msghdr msg
= {
645 .msg_namelen
= sizeof(nladdr
),
650 return sendmsg(rth
->fd
, &msg
, 0);
653 int rtnl_dump_request_n(struct rtnl_handle
*rth
, struct nlmsghdr
*n
)
655 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
658 .iov_len
= n
->nlmsg_len
660 struct msghdr msg
= {
662 .msg_namelen
= sizeof(nladdr
),
667 n
->nlmsg_flags
= NLM_F_DUMP
|NLM_F_REQUEST
;
669 n
->nlmsg_seq
= rth
->dump
= ++rth
->seq
;
671 return sendmsg(rth
->fd
, &msg
, 0);
674 static int rtnl_dump_done(struct nlmsghdr
*h
)
676 int len
= *(int *)NLMSG_DATA(h
);
678 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(int))) {
679 fprintf(stderr
, "DONE truncated\n");
684 /* check for any messages returned from kernel */
685 if (nl_dump_ext_ack_done(h
, len
))
695 "Error: Buffer too small for object.\n");
698 perror("RTNETLINK answers");
703 /* check for any messages returned from kernel */
704 nl_dump_ext_ack(h
, NULL
);
709 static void rtnl_dump_error(const struct rtnl_handle
*rth
,
713 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
))) {
714 fprintf(stderr
, "ERROR truncated\n");
716 const struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
719 if (rth
->proto
== NETLINK_SOCK_DIAG
&&
721 errno
== EOPNOTSUPP
))
724 if (!(rth
->flags
& RTNL_HANDLE_F_SUPPRESS_NLERR
))
725 perror("RTNETLINK answers");
729 static int __rtnl_recvmsg(int fd
, struct msghdr
*msg
, int flags
)
734 len
= recvmsg(fd
, msg
, flags
);
735 } while (len
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
738 fprintf(stderr
, "netlink receive error %s (%d)\n",
739 strerror(errno
), errno
);
744 fprintf(stderr
, "EOF on netlink\n");
751 static int rtnl_recvmsg(int fd
, struct msghdr
*msg
, char **answer
)
753 struct iovec
*iov
= msg
->msg_iov
;
757 iov
->iov_base
= NULL
;
760 len
= __rtnl_recvmsg(fd
, msg
, MSG_PEEK
| MSG_TRUNC
);
768 fprintf(stderr
, "malloc error: not enough buffer\n");
775 len
= __rtnl_recvmsg(fd
, msg
, 0);
789 static int rtnl_dump_filter_l(struct rtnl_handle
*rth
,
790 const struct rtnl_dump_filter_arg
*arg
)
792 struct sockaddr_nl nladdr
;
794 struct msghdr msg
= {
796 .msg_namelen
= sizeof(nladdr
),
805 const struct rtnl_dump_filter_arg
*a
;
809 status
= rtnl_recvmsg(rth
->fd
, &msg
, &buf
);
814 fwrite(buf
, 1, NLMSG_ALIGN(status
), rth
->dump_fp
);
816 for (a
= arg
; a
->filter
; a
++) {
817 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
821 while (NLMSG_OK(h
, msglen
)) {
824 h
->nlmsg_flags
&= ~a
->nc_flags
;
826 if (nladdr
.nl_pid
!= 0 ||
827 h
->nlmsg_pid
!= rth
->local
.nl_pid
||
828 h
->nlmsg_seq
!= rth
->dump
)
831 if (h
->nlmsg_flags
& NLM_F_DUMP_INTR
)
834 if (h
->nlmsg_type
== NLMSG_DONE
) {
835 err
= rtnl_dump_done(h
);
842 break; /* process next filter */
845 if (h
->nlmsg_type
== NLMSG_ERROR
) {
846 rtnl_dump_error(rth
, h
);
852 err
= a
->filter(h
, a
->arg1
);
860 h
= NLMSG_NEXT(h
, msglen
);
868 "Dump was interrupted and may be inconsistent.\n");
872 if (msg
.msg_flags
& MSG_TRUNC
) {
873 fprintf(stderr
, "Message truncated\n");
877 fprintf(stderr
, "!!!Remnant of size %d\n", msglen
);
883 int rtnl_dump_filter_nc(struct rtnl_handle
*rth
,
884 rtnl_filter_t filter
,
885 void *arg1
, __u16 nc_flags
)
887 const struct rtnl_dump_filter_arg a
[2] = {
888 { .filter
= filter
, .arg1
= arg1
, .nc_flags
= nc_flags
, },
889 { .filter
= NULL
, .arg1
= NULL
, .nc_flags
= 0, },
892 return rtnl_dump_filter_l(rth
, a
);
895 static void rtnl_talk_error(struct nlmsghdr
*h
, struct nlmsgerr
*err
,
896 nl_ext_ack_fn_t errfn
)
898 if (nl_dump_ext_ack(h
, errfn
))
901 fprintf(stderr
, "RTNETLINK answers: %s\n",
902 strerror(-err
->error
));
906 static int __rtnl_talk_iov(struct rtnl_handle
*rtnl
, struct iovec
*iov
,
907 size_t iovlen
, struct nlmsghdr
**answer
,
908 bool show_rtnl_err
, nl_ext_ack_fn_t errfn
)
910 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
912 struct msghdr msg
= {
914 .msg_namelen
= sizeof(nladdr
),
916 .msg_iovlen
= iovlen
,
918 unsigned int seq
= 0;
923 for (i
= 0; i
< iovlen
; i
++) {
925 h
->nlmsg_seq
= seq
= ++rtnl
->seq
;
927 h
->nlmsg_flags
|= NLM_F_ACK
;
930 status
= sendmsg(rtnl
->fd
, &msg
, 0);
932 perror("Cannot talk to rtnetlink");
936 /* change msg to use the response iov */
942 status
= rtnl_recvmsg(rtnl
->fd
, &msg
, &buf
);
948 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
950 "sender address length == %d\n",
954 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
955 int len
= h
->nlmsg_len
;
956 int l
= len
- sizeof(*h
);
958 if (l
< 0 || len
> status
) {
959 if (msg
.msg_flags
& MSG_TRUNC
) {
960 fprintf(stderr
, "Truncated message\n");
965 "!!!malformed message: len=%d\n",
970 if (nladdr
.nl_pid
!= 0 ||
971 h
->nlmsg_pid
!= rtnl
->local
.nl_pid
||
972 h
->nlmsg_seq
> seq
|| h
->nlmsg_seq
< seq
- iovlen
) {
973 /* Don't forget to skip that message. */
974 status
-= NLMSG_ALIGN(len
);
975 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
979 if (h
->nlmsg_type
== NLMSG_ERROR
) {
980 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
981 int error
= err
->error
;
983 if (l
< sizeof(struct nlmsgerr
)) {
984 fprintf(stderr
, "ERROR truncated\n");
990 /* check messages from kernel */
991 nl_dump_ext_ack(h
, errfn
);
995 if (rtnl
->proto
!= NETLINK_SOCK_DIAG
&&
997 rtnl_talk_error(h
, err
, errfn
);
1001 *answer
= (struct nlmsghdr
*)buf
;
1007 return error
? -i
: 0;
1011 *answer
= (struct nlmsghdr
*)buf
;
1015 fprintf(stderr
, "Unexpected reply!!!\n");
1017 status
-= NLMSG_ALIGN(len
);
1018 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
1022 if (msg
.msg_flags
& MSG_TRUNC
) {
1023 fprintf(stderr
, "Message truncated\n");
1028 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
1034 static int __rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
1035 struct nlmsghdr
**answer
,
1036 bool show_rtnl_err
, nl_ext_ack_fn_t errfn
)
1038 struct iovec iov
= {
1040 .iov_len
= n
->nlmsg_len
1043 return __rtnl_talk_iov(rtnl
, &iov
, 1, answer
, show_rtnl_err
, errfn
);
1046 int rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
1047 struct nlmsghdr
**answer
)
1049 return __rtnl_talk(rtnl
, n
, answer
, true, NULL
);
1052 int rtnl_talk_iov(struct rtnl_handle
*rtnl
, struct iovec
*iovec
, size_t iovlen
,
1053 struct nlmsghdr
**answer
)
1055 return __rtnl_talk_iov(rtnl
, iovec
, iovlen
, answer
, true, NULL
);
1058 int rtnl_talk_suppress_rtnl_errmsg(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
1059 struct nlmsghdr
**answer
)
1061 return __rtnl_talk(rtnl
, n
, answer
, false, NULL
);
1064 int rtnl_listen_all_nsid(struct rtnl_handle
*rth
)
1066 unsigned int on
= 1;
1068 if (setsockopt(rth
->fd
, SOL_NETLINK
, NETLINK_LISTEN_ALL_NSID
, &on
,
1070 perror("NETLINK_LISTEN_ALL_NSID");
1073 rth
->flags
|= RTNL_HANDLE_F_LISTEN_ALL_NSID
;
1077 int rtnl_listen(struct rtnl_handle
*rtnl
,
1078 rtnl_listen_filter_t handler
,
1083 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
1085 struct msghdr msg
= {
1086 .msg_name
= &nladdr
,
1087 .msg_namelen
= sizeof(nladdr
),
1092 char cmsgbuf
[BUFSIZ
];
1094 if (rtnl
->flags
& RTNL_HANDLE_F_LISTEN_ALL_NSID
) {
1095 msg
.msg_control
= &cmsgbuf
;
1096 msg
.msg_controllen
= sizeof(cmsgbuf
);
1101 struct rtnl_ctrl_data ctrl
;
1102 struct cmsghdr
*cmsg
;
1104 iov
.iov_len
= sizeof(buf
);
1105 status
= recvmsg(rtnl
->fd
, &msg
, 0);
1108 if (errno
== EINTR
|| errno
== EAGAIN
)
1110 fprintf(stderr
, "netlink receive error %s (%d)\n",
1111 strerror(errno
), errno
);
1112 if (errno
== ENOBUFS
)
1117 fprintf(stderr
, "EOF on netlink\n");
1120 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
1122 "Sender address length == %d\n",
1127 if (rtnl
->flags
& RTNL_HANDLE_F_LISTEN_ALL_NSID
) {
1128 memset(&ctrl
, 0, sizeof(ctrl
));
1130 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
;
1131 cmsg
= CMSG_NXTHDR(&msg
, cmsg
))
1132 if (cmsg
->cmsg_level
== SOL_NETLINK
&&
1133 cmsg
->cmsg_type
== NETLINK_LISTEN_ALL_NSID
&&
1134 cmsg
->cmsg_len
== CMSG_LEN(sizeof(int))) {
1135 int *data
= (int *)CMSG_DATA(cmsg
);
1141 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
1143 int len
= h
->nlmsg_len
;
1144 int l
= len
- sizeof(*h
);
1146 if (l
< 0 || len
> status
) {
1147 if (msg
.msg_flags
& MSG_TRUNC
) {
1148 fprintf(stderr
, "Truncated message\n");
1152 "!!!malformed message: len=%d\n",
1157 err
= handler(&ctrl
, h
, jarg
);
1161 status
-= NLMSG_ALIGN(len
);
1162 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
1164 if (msg
.msg_flags
& MSG_TRUNC
) {
1165 fprintf(stderr
, "Message truncated\n");
1169 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
1175 int rtnl_from_file(FILE *rtnl
, rtnl_listen_filter_t handler
,
1180 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
1186 status
= fread(&buf
, 1, sizeof(*h
), rtnl
);
1188 if (status
== 0 && feof(rtnl
))
1190 if (status
!= sizeof(*h
)) {
1192 perror("rtnl_from_file: fread");
1194 fprintf(stderr
, "rtnl-from_file: truncated message\n");
1199 l
= len
- sizeof(*h
);
1201 if (l
< 0 || len
> sizeof(buf
)) {
1202 fprintf(stderr
, "!!!malformed message: len=%d @%lu\n",
1207 status
= fread(NLMSG_DATA(h
), 1, NLMSG_ALIGN(l
), rtnl
);
1209 if (status
!= NLMSG_ALIGN(l
)) {
1211 perror("rtnl_from_file: fread");
1213 fprintf(stderr
, "rtnl-from_file: truncated message\n");
1217 err
= handler(NULL
, h
, jarg
);
1223 int addattr(struct nlmsghdr
*n
, int maxlen
, int type
)
1225 return addattr_l(n
, maxlen
, type
, NULL
, 0);
1228 int addattr8(struct nlmsghdr
*n
, int maxlen
, int type
, __u8 data
)
1230 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u8
));
1233 int addattr16(struct nlmsghdr
*n
, int maxlen
, int type
, __u16 data
)
1235 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u16
));
1238 int addattr32(struct nlmsghdr
*n
, int maxlen
, int type
, __u32 data
)
1240 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u32
));
1243 int addattr64(struct nlmsghdr
*n
, int maxlen
, int type
, __u64 data
)
1245 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u64
));
1248 int addattrstrz(struct nlmsghdr
*n
, int maxlen
, int type
, const char *str
)
1250 return addattr_l(n
, maxlen
, type
, str
, strlen(str
)+1);
1253 int addattr_l(struct nlmsghdr
*n
, int maxlen
, int type
, const void *data
,
1256 int len
= RTA_LENGTH(alen
);
1259 if (NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
) > maxlen
) {
1261 "addattr_l ERROR: message exceeded bound of %d\n",
1265 rta
= NLMSG_TAIL(n
);
1266 rta
->rta_type
= type
;
1269 memcpy(RTA_DATA(rta
), data
, alen
);
1270 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);
1274 int addraw_l(struct nlmsghdr
*n
, int maxlen
, const void *data
, int len
)
1276 if (NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
) > maxlen
) {
1278 "addraw_l ERROR: message exceeded bound of %d\n",
1283 memcpy(NLMSG_TAIL(n
), data
, len
);
1284 memset((void *) NLMSG_TAIL(n
) + len
, 0, NLMSG_ALIGN(len
) - len
);
1285 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
);
1289 struct rtattr
*addattr_nest(struct nlmsghdr
*n
, int maxlen
, int type
)
1291 struct rtattr
*nest
= NLMSG_TAIL(n
);
1293 addattr_l(n
, maxlen
, type
, NULL
, 0);
1297 int addattr_nest_end(struct nlmsghdr
*n
, struct rtattr
*nest
)
1299 nest
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)nest
;
1300 return n
->nlmsg_len
;
1303 struct rtattr
*addattr_nest_compat(struct nlmsghdr
*n
, int maxlen
, int type
,
1304 const void *data
, int len
)
1306 struct rtattr
*start
= NLMSG_TAIL(n
);
1308 addattr_l(n
, maxlen
, type
, data
, len
);
1309 addattr_nest(n
, maxlen
, type
);
1313 int addattr_nest_compat_end(struct nlmsghdr
*n
, struct rtattr
*start
)
1315 struct rtattr
*nest
= (void *)start
+ NLMSG_ALIGN(start
->rta_len
);
1317 start
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)start
;
1318 addattr_nest_end(n
, nest
);
1319 return n
->nlmsg_len
;
1322 int rta_addattr32(struct rtattr
*rta
, int maxlen
, int type
, __u32 data
)
1324 int len
= RTA_LENGTH(4);
1325 struct rtattr
*subrta
;
1327 if (RTA_ALIGN(rta
->rta_len
) + len
> maxlen
) {
1329 "rta_addattr32: Error! max allowed bound %d exceeded\n",
1333 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
1334 subrta
->rta_type
= type
;
1335 subrta
->rta_len
= len
;
1336 memcpy(RTA_DATA(subrta
), &data
, 4);
1337 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + len
;
1341 int rta_addattr_l(struct rtattr
*rta
, int maxlen
, int type
,
1342 const void *data
, int alen
)
1344 struct rtattr
*subrta
;
1345 int len
= RTA_LENGTH(alen
);
1347 if (RTA_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
) > maxlen
) {
1349 "rta_addattr_l: Error! max allowed bound %d exceeded\n",
1353 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
1354 subrta
->rta_type
= type
;
1355 subrta
->rta_len
= len
;
1357 memcpy(RTA_DATA(subrta
), data
, alen
);
1358 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
);
1362 int rta_addattr8(struct rtattr
*rta
, int maxlen
, int type
, __u8 data
)
1364 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u8
));
1367 int rta_addattr16(struct rtattr
*rta
, int maxlen
, int type
, __u16 data
)
1369 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u16
));
1372 int rta_addattr64(struct rtattr
*rta
, int maxlen
, int type
, __u64 data
)
1374 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u64
));
1377 struct rtattr
*rta_nest(struct rtattr
*rta
, int maxlen
, int type
)
1379 struct rtattr
*nest
= RTA_TAIL(rta
);
1381 rta_addattr_l(rta
, maxlen
, type
, NULL
, 0);
1382 nest
->rta_type
|= NLA_F_NESTED
;
1387 int rta_nest_end(struct rtattr
*rta
, struct rtattr
*nest
)
1389 nest
->rta_len
= (void *)RTA_TAIL(rta
) - (void *)nest
;
1391 return rta
->rta_len
;
1394 int parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
1396 return parse_rtattr_flags(tb
, max
, rta
, len
, 0);
1399 int parse_rtattr_flags(struct rtattr
*tb
[], int max
, struct rtattr
*rta
,
1400 int len
, unsigned short flags
)
1402 unsigned short type
;
1404 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
1405 while (RTA_OK(rta
, len
)) {
1406 type
= rta
->rta_type
& ~flags
;
1407 if ((type
<= max
) && (!tb
[type
]))
1409 rta
= RTA_NEXT(rta
, len
);
1412 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n",
1417 struct rtattr
*parse_rtattr_one(int type
, struct rtattr
*rta
, int len
)
1419 while (RTA_OK(rta
, len
)) {
1420 if (rta
->rta_type
== type
)
1422 rta
= RTA_NEXT(rta
, len
);
1426 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n",
1431 int __parse_rtattr_nested_compat(struct rtattr
*tb
[], int max
,
1435 if (RTA_PAYLOAD(rta
) < len
)
1437 if (RTA_PAYLOAD(rta
) >= RTA_ALIGN(len
) + sizeof(struct rtattr
)) {
1438 rta
= RTA_DATA(rta
) + RTA_ALIGN(len
);
1439 return parse_rtattr_nested(tb
, max
, rta
);
1441 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
1445 static const char *get_nla_type_str(unsigned int attr
)
1448 #define C(x) case NL_ATTR_TYPE_ ## x: return #x
1469 void nl_print_policy(const struct rtattr
*attr
, FILE *fp
)
1471 const struct rtattr
*pos
;
1473 rtattr_for_each_nested(pos
, attr
) {
1474 const struct rtattr
*attr
;
1476 fprintf(fp
, " policy[%u]:", pos
->rta_type
& ~NLA_F_NESTED
);
1478 rtattr_for_each_nested(attr
, pos
) {
1479 struct rtattr
*tp
[NL_POLICY_TYPE_ATTR_MAX
+ 1];
1481 parse_rtattr_nested(tp
, ARRAY_SIZE(tp
) - 1, attr
);
1483 if (tp
[NL_POLICY_TYPE_ATTR_TYPE
])
1484 fprintf(fp
, "attr[%u]: type=%s",
1485 attr
->rta_type
& ~NLA_F_NESTED
,
1486 get_nla_type_str(rta_getattr_u32(tp
[NL_POLICY_TYPE_ATTR_TYPE
])));
1488 if (tp
[NL_POLICY_TYPE_ATTR_POLICY_IDX
])
1489 fprintf(fp
, " policy:%u",
1490 rta_getattr_u32(tp
[NL_POLICY_TYPE_ATTR_POLICY_IDX
]));
1492 if (tp
[NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE
])
1493 fprintf(fp
, " maxattr:%u",
1494 rta_getattr_u32(tp
[NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE
]));
1496 if (tp
[NL_POLICY_TYPE_ATTR_MIN_VALUE_S
] && tp
[NL_POLICY_TYPE_ATTR_MAX_VALUE_S
])
1497 fprintf(fp
, " range:[%lld,%lld]",
1498 (signed long long)rta_getattr_u64(tp
[NL_POLICY_TYPE_ATTR_MIN_VALUE_S
]),
1499 (signed long long)rta_getattr_u64(tp
[NL_POLICY_TYPE_ATTR_MAX_VALUE_S
]));
1501 if (tp
[NL_POLICY_TYPE_ATTR_MIN_VALUE_U
] && tp
[NL_POLICY_TYPE_ATTR_MAX_VALUE_U
])
1502 fprintf(fp
, " range:[%llu,%llu]",
1503 (unsigned long long)rta_getattr_u64(tp
[NL_POLICY_TYPE_ATTR_MIN_VALUE_U
]),
1504 (unsigned long long)rta_getattr_u64(tp
[NL_POLICY_TYPE_ATTR_MAX_VALUE_U
]));
1506 if (tp
[NL_POLICY_TYPE_ATTR_MIN_LENGTH
])
1507 fprintf(fp
, " min len:%u",
1508 rta_getattr_u32(tp
[NL_POLICY_TYPE_ATTR_MIN_LENGTH
]));
1510 if (tp
[NL_POLICY_TYPE_ATTR_MAX_LENGTH
])
1511 fprintf(fp
, " max len:%u",
1512 rta_getattr_u32(tp
[NL_POLICY_TYPE_ATTR_MAX_LENGTH
]));