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>
29 #include "libnetlink.h"
31 #define __aligned(x) __attribute__((aligned(x)))
34 #define SOL_NETLINK 270
38 #define MIN(a, b) ((a) < (b) ? (a) : (b))
41 int rcvbuf
= 1024 * 1024;
44 #include <libmnl/libmnl.h>
46 static const enum mnl_attr_data_type extack_policy
[NLMSGERR_ATTR_MAX
+ 1] = {
47 [NLMSGERR_ATTR_MSG
] = MNL_TYPE_NUL_STRING
,
48 [NLMSGERR_ATTR_OFFS
] = MNL_TYPE_U32
,
51 static int err_attr_cb(const struct nlattr
*attr
, void *data
)
53 const struct nlattr
**tb
= data
;
56 if (mnl_attr_type_valid(attr
, NLMSGERR_ATTR_MAX
) < 0) {
57 fprintf(stderr
, "Invalid extack attribute\n");
61 type
= mnl_attr_get_type(attr
);
62 if (mnl_attr_validate(attr
, extack_policy
[type
]) < 0) {
63 fprintf(stderr
, "extack attribute %d failed validation\n",
72 static void print_ext_ack_msg(bool is_err
, const char *msg
)
74 fprintf(stderr
, "%s: %s", is_err
? "Error" : "Warning", msg
);
75 if (msg
[strlen(msg
) - 1] != '.')
77 fprintf(stderr
, "\n");
80 /* dump netlink extended ack error message */
81 int nl_dump_ext_ack(const struct nlmsghdr
*nlh
, nl_ext_ack_fn_t errfn
)
83 struct nlattr
*tb
[NLMSGERR_ATTR_MAX
+ 1] = {};
84 const struct nlmsgerr
*err
= mnl_nlmsg_get_payload(nlh
);
85 const struct nlmsghdr
*err_nlh
= NULL
;
86 unsigned int hlen
= sizeof(*err
);
87 const char *msg
= NULL
;
90 /* no TLVs, nothing to do here */
91 if (!(nlh
->nlmsg_flags
& NLM_F_ACK_TLVS
))
94 /* if NLM_F_CAPPED is set then the inner err msg was capped */
95 if (!(nlh
->nlmsg_flags
& NLM_F_CAPPED
))
96 hlen
+= mnl_nlmsg_get_payload_len(&err
->msg
);
98 if (mnl_attr_parse(nlh
, hlen
, err_attr_cb
, tb
) != MNL_CB_OK
)
101 if (tb
[NLMSGERR_ATTR_MSG
])
102 msg
= mnl_attr_get_str(tb
[NLMSGERR_ATTR_MSG
]);
104 if (tb
[NLMSGERR_ATTR_OFFS
]) {
105 off
= mnl_attr_get_u32(tb
[NLMSGERR_ATTR_OFFS
]);
107 if (off
> nlh
->nlmsg_len
) {
109 "Invalid offset for NLMSGERR_ATTR_OFFS\n");
111 } else if (!(nlh
->nlmsg_flags
& NLM_F_CAPPED
))
116 return errfn(msg
, off
, err_nlh
);
118 if (msg
&& *msg
!= '\0') {
119 bool is_err
= !!err
->error
;
121 print_ext_ack_msg(is_err
, msg
);
122 return is_err
? 1 : 0;
128 static int nl_dump_ext_ack_done(const struct nlmsghdr
*nlh
, int error
)
130 struct nlattr
*tb
[NLMSGERR_ATTR_MAX
+ 1] = {};
131 unsigned int hlen
= sizeof(int);
132 const char *msg
= NULL
;
134 if (mnl_attr_parse(nlh
, hlen
, err_attr_cb
, tb
) != MNL_CB_OK
)
137 if (tb
[NLMSGERR_ATTR_MSG
])
138 msg
= mnl_attr_get_str(tb
[NLMSGERR_ATTR_MSG
]);
140 if (msg
&& *msg
!= '\0') {
141 bool is_err
= !!error
;
143 print_ext_ack_msg(is_err
, msg
);
144 return is_err
? 1 : 0;
150 #warning "libmnl required for error support"
152 /* No extended error ack without libmnl */
153 int nl_dump_ext_ack(const struct nlmsghdr
*nlh
, nl_ext_ack_fn_t errfn
)
158 static int nl_dump_ext_ack_done(const struct nlmsghdr
*nlh
, int error
)
164 /* Older kernels may not support strict dump and filtering */
165 void rtnl_set_strict_dump(struct rtnl_handle
*rth
)
169 setsockopt(rth
->fd
, SOL_NETLINK
, NETLINK_GET_STRICT_CHK
,
173 void rtnl_close(struct rtnl_handle
*rth
)
181 int rtnl_open_byproto(struct rtnl_handle
*rth
, unsigned int subscriptions
,
188 memset(rth
, 0, sizeof(*rth
));
190 rth
->proto
= protocol
;
191 rth
->fd
= socket(AF_NETLINK
, SOCK_RAW
| SOCK_CLOEXEC
, protocol
);
193 perror("Cannot open netlink socket");
197 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_SNDBUF
,
198 &sndbuf
, sizeof(sndbuf
)) < 0) {
203 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_RCVBUF
,
204 &rcvbuf
, sizeof(rcvbuf
)) < 0) {
209 /* Older kernels may no support extended ACK reporting */
210 setsockopt(rth
->fd
, SOL_NETLINK
, NETLINK_EXT_ACK
,
213 memset(&rth
->local
, 0, sizeof(rth
->local
));
214 rth
->local
.nl_family
= AF_NETLINK
;
215 rth
->local
.nl_groups
= subscriptions
;
217 if (bind(rth
->fd
, (struct sockaddr
*)&rth
->local
,
218 sizeof(rth
->local
)) < 0) {
219 perror("Cannot bind netlink socket");
222 addr_len
= sizeof(rth
->local
);
223 if (getsockname(rth
->fd
, (struct sockaddr
*)&rth
->local
,
225 perror("Cannot getsockname");
228 if (addr_len
!= sizeof(rth
->local
)) {
229 fprintf(stderr
, "Wrong address length %d\n", addr_len
);
232 if (rth
->local
.nl_family
!= AF_NETLINK
) {
233 fprintf(stderr
, "Wrong address family %d\n",
234 rth
->local
.nl_family
);
237 rth
->seq
= time(NULL
);
241 int rtnl_open(struct rtnl_handle
*rth
, unsigned int subscriptions
)
243 return rtnl_open_byproto(rth
, subscriptions
, NETLINK_ROUTE
);
246 int rtnl_addrdump_req(struct rtnl_handle
*rth
, int family
,
247 req_filter_fn_t filter_fn
)
251 struct ifaddrmsg ifm
;
254 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifaddrmsg
)),
255 .nlh
.nlmsg_type
= RTM_GETADDR
,
256 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
257 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
258 .ifm
.ifa_family
= family
,
264 err
= filter_fn(&req
.nlh
, sizeof(req
));
269 return send(rth
->fd
, &req
, sizeof(req
), 0);
272 int rtnl_addrlbldump_req(struct rtnl_handle
*rth
, int family
)
276 struct ifaddrlblmsg ifal
;
278 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifaddrlblmsg
)),
279 .nlh
.nlmsg_type
= RTM_GETADDRLABEL
,
280 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
281 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
282 .ifal
.ifal_family
= family
,
285 return send(rth
->fd
, &req
, sizeof(req
), 0);
288 int rtnl_routedump_req(struct rtnl_handle
*rth
, int family
,
289 req_filter_fn_t filter_fn
)
296 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
)),
297 .nlh
.nlmsg_type
= RTM_GETROUTE
,
298 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
299 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
300 .rtm
.rtm_family
= family
,
306 err
= filter_fn(&req
.nlh
, sizeof(req
));
311 return send(rth
->fd
, &req
, sizeof(req
), 0);
314 int rtnl_ruledump_req(struct rtnl_handle
*rth
, int family
)
318 struct fib_rule_hdr frh
;
320 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct fib_rule_hdr
)),
321 .nlh
.nlmsg_type
= RTM_GETRULE
,
322 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
323 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
327 return send(rth
->fd
, &req
, sizeof(req
), 0);
330 int rtnl_neighdump_req(struct rtnl_handle
*rth
, int family
,
331 req_filter_fn_t filter_fn
)
338 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ndmsg
)),
339 .nlh
.nlmsg_type
= RTM_GETNEIGH
,
340 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
341 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
342 .ndm
.ndm_family
= family
,
348 err
= filter_fn(&req
.nlh
, sizeof(req
));
353 return send(rth
->fd
, &req
, sizeof(req
), 0);
356 int rtnl_neightbldump_req(struct rtnl_handle
*rth
, int family
)
360 struct ndtmsg ndtmsg
;
362 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ndtmsg
)),
363 .nlh
.nlmsg_type
= RTM_GETNEIGHTBL
,
364 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
365 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
366 .ndtmsg
.ndtm_family
= family
,
369 return send(rth
->fd
, &req
, sizeof(req
), 0);
372 int rtnl_mdbdump_req(struct rtnl_handle
*rth
, int family
)
376 struct br_port_msg bpm
;
378 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct br_port_msg
)),
379 .nlh
.nlmsg_type
= RTM_GETMDB
,
380 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
381 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
382 .bpm
.family
= family
,
385 return send(rth
->fd
, &req
, sizeof(req
), 0);
388 int rtnl_netconfdump_req(struct rtnl_handle
*rth
, int family
)
392 struct netconfmsg ncm
;
393 char buf
[0] __aligned(NLMSG_ALIGNTO
);
395 .nlh
.nlmsg_len
= NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct netconfmsg
))),
396 .nlh
.nlmsg_type
= RTM_GETNETCONF
,
397 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
398 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
399 .ncm
.ncm_family
= family
,
402 return send(rth
->fd
, &req
, sizeof(req
), 0);
405 int rtnl_nsiddump_req(struct rtnl_handle
*rth
, int family
)
410 char buf
[0] __aligned(NLMSG_ALIGNTO
);
412 .nlh
.nlmsg_len
= NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtgenmsg
))),
413 .nlh
.nlmsg_type
= RTM_GETNSID
,
414 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
415 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
416 .rtm
.rtgen_family
= family
,
419 return send(rth
->fd
, &req
, sizeof(req
), 0);
422 static int __rtnl_linkdump_req(struct rtnl_handle
*rth
, int family
)
426 struct ifinfomsg ifm
;
428 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
429 .nlh
.nlmsg_type
= RTM_GETLINK
,
430 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
431 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
432 .ifm
.ifi_family
= family
,
435 return send(rth
->fd
, &req
, sizeof(req
), 0);
438 int rtnl_linkdump_req(struct rtnl_handle
*rth
, int family
)
440 if (family
== AF_UNSPEC
)
441 return rtnl_linkdump_req_filter(rth
, family
, RTEXT_FILTER_VF
);
443 return __rtnl_linkdump_req(rth
, family
);
446 int rtnl_linkdump_req_filter(struct rtnl_handle
*rth
, int family
,
449 if (family
== AF_UNSPEC
) {
452 struct ifinfomsg ifm
;
453 /* attribute has to be NLMSG aligned */
454 struct rtattr ext_req
__aligned(NLMSG_ALIGNTO
);
455 __u32 ext_filter_mask
;
457 .nlh
.nlmsg_len
= sizeof(req
),
458 .nlh
.nlmsg_type
= RTM_GETLINK
,
459 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
460 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
461 .ifm
.ifi_family
= family
,
462 .ext_req
.rta_type
= IFLA_EXT_MASK
,
463 .ext_req
.rta_len
= RTA_LENGTH(sizeof(__u32
)),
464 .ext_filter_mask
= filt_mask
,
467 return send(rth
->fd
, &req
, sizeof(req
), 0);
470 return __rtnl_linkdump_req(rth
, family
);
473 int rtnl_linkdump_req_filter_fn(struct rtnl_handle
*rth
, int family
,
474 req_filter_fn_t filter_fn
)
476 if (family
== AF_UNSPEC
) {
479 struct ifinfomsg ifm
;
482 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
483 .nlh
.nlmsg_type
= RTM_GETLINK
,
484 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
485 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
486 .ifm
.ifi_family
= family
,
493 err
= filter_fn(&req
.nlh
, sizeof(req
));
497 return send(rth
->fd
, &req
, req
.nlh
.nlmsg_len
, 0);
500 return __rtnl_linkdump_req(rth
, family
);
503 int rtnl_statsdump_req_filter(struct rtnl_handle
*rth
, int fam
, __u32 filt_mask
)
507 struct if_stats_msg ifsm
;
510 memset(&req
, 0, sizeof(req
));
511 req
.nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct if_stats_msg
));
512 req
.nlh
.nlmsg_type
= RTM_GETSTATS
;
513 req
.nlh
.nlmsg_flags
= NLM_F_DUMP
|NLM_F_REQUEST
;
514 req
.nlh
.nlmsg_pid
= 0;
515 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
516 req
.ifsm
.family
= fam
;
517 req
.ifsm
.filter_mask
= filt_mask
;
519 return send(rth
->fd
, &req
, sizeof(req
), 0);
522 int rtnl_send(struct rtnl_handle
*rth
, const void *buf
, int len
)
524 return send(rth
->fd
, buf
, len
, 0);
527 int rtnl_send_check(struct rtnl_handle
*rth
, const void *buf
, int len
)
533 status
= send(rth
->fd
, buf
, len
, 0);
537 /* Check for immediate errors */
538 status
= recv(rth
->fd
, resp
, sizeof(resp
), MSG_DONTWAIT
|MSG_PEEK
);
545 for (h
= (struct nlmsghdr
*)resp
; NLMSG_OK(h
, status
);
546 h
= NLMSG_NEXT(h
, status
)) {
547 if (h
->nlmsg_type
== NLMSG_ERROR
) {
548 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
550 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
551 fprintf(stderr
, "ERROR truncated\n");
561 int rtnl_dump_request(struct rtnl_handle
*rth
, int type
, void *req
, int len
)
563 struct nlmsghdr nlh
= {
564 .nlmsg_len
= NLMSG_LENGTH(len
),
566 .nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
567 .nlmsg_seq
= rth
->dump
= ++rth
->seq
,
569 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
570 struct iovec iov
[2] = {
571 { .iov_base
= &nlh
, .iov_len
= sizeof(nlh
) },
572 { .iov_base
= req
, .iov_len
= len
}
574 struct msghdr msg
= {
576 .msg_namelen
= sizeof(nladdr
),
581 return sendmsg(rth
->fd
, &msg
, 0);
584 int rtnl_dump_request_n(struct rtnl_handle
*rth
, struct nlmsghdr
*n
)
586 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
589 .iov_len
= n
->nlmsg_len
591 struct msghdr msg
= {
593 .msg_namelen
= sizeof(nladdr
),
598 n
->nlmsg_flags
= NLM_F_DUMP
|NLM_F_REQUEST
;
600 n
->nlmsg_seq
= rth
->dump
= ++rth
->seq
;
602 return sendmsg(rth
->fd
, &msg
, 0);
605 static int rtnl_dump_done(struct nlmsghdr
*h
)
607 int len
= *(int *)NLMSG_DATA(h
);
609 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(int))) {
610 fprintf(stderr
, "DONE truncated\n");
615 /* check for any messages returned from kernel */
616 if (nl_dump_ext_ack_done(h
, len
))
626 "Error: Buffer too small for object.\n");
629 perror("RTNETLINK answers");
634 /* check for any messages returned from kernel */
635 nl_dump_ext_ack(h
, NULL
);
640 static void rtnl_dump_error(const struct rtnl_handle
*rth
,
644 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
))) {
645 fprintf(stderr
, "ERROR truncated\n");
647 const struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
650 if (rth
->proto
== NETLINK_SOCK_DIAG
&&
652 errno
== EOPNOTSUPP
))
655 if (!(rth
->flags
& RTNL_HANDLE_F_SUPPRESS_NLERR
))
656 perror("RTNETLINK answers");
660 static int __rtnl_recvmsg(int fd
, struct msghdr
*msg
, int flags
)
665 len
= recvmsg(fd
, msg
, flags
);
666 } while (len
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
669 fprintf(stderr
, "netlink receive error %s (%d)\n",
670 strerror(errno
), errno
);
675 fprintf(stderr
, "EOF on netlink\n");
682 static int rtnl_recvmsg(int fd
, struct msghdr
*msg
, char **answer
)
684 struct iovec
*iov
= msg
->msg_iov
;
688 iov
->iov_base
= NULL
;
691 len
= __rtnl_recvmsg(fd
, msg
, MSG_PEEK
| MSG_TRUNC
);
697 fprintf(stderr
, "malloc error: not enough buffer\n");
704 len
= __rtnl_recvmsg(fd
, msg
, 0);
718 static int rtnl_dump_filter_l(struct rtnl_handle
*rth
,
719 const struct rtnl_dump_filter_arg
*arg
)
721 struct sockaddr_nl nladdr
;
723 struct msghdr msg
= {
725 .msg_namelen
= sizeof(nladdr
),
734 const struct rtnl_dump_filter_arg
*a
;
738 status
= rtnl_recvmsg(rth
->fd
, &msg
, &buf
);
743 fwrite(buf
, 1, NLMSG_ALIGN(status
), rth
->dump_fp
);
745 for (a
= arg
; a
->filter
; a
++) {
746 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
750 while (NLMSG_OK(h
, msglen
)) {
753 h
->nlmsg_flags
&= ~a
->nc_flags
;
755 if (nladdr
.nl_pid
!= 0 ||
756 h
->nlmsg_pid
!= rth
->local
.nl_pid
||
757 h
->nlmsg_seq
!= rth
->dump
)
760 if (h
->nlmsg_flags
& NLM_F_DUMP_INTR
)
763 if (h
->nlmsg_type
== NLMSG_DONE
) {
764 err
= rtnl_dump_done(h
);
771 break; /* process next filter */
774 if (h
->nlmsg_type
== NLMSG_ERROR
) {
775 rtnl_dump_error(rth
, h
);
781 err
= a
->filter(h
, a
->arg1
);
789 h
= NLMSG_NEXT(h
, msglen
);
797 "Dump was interrupted and may be inconsistent.\n");
801 if (msg
.msg_flags
& MSG_TRUNC
) {
802 fprintf(stderr
, "Message truncated\n");
806 fprintf(stderr
, "!!!Remnant of size %d\n", msglen
);
812 int rtnl_dump_filter_nc(struct rtnl_handle
*rth
,
813 rtnl_filter_t filter
,
814 void *arg1
, __u16 nc_flags
)
816 const struct rtnl_dump_filter_arg a
[2] = {
817 { .filter
= filter
, .arg1
= arg1
, .nc_flags
= nc_flags
, },
818 { .filter
= NULL
, .arg1
= NULL
, .nc_flags
= 0, },
821 return rtnl_dump_filter_l(rth
, a
);
824 static void rtnl_talk_error(struct nlmsghdr
*h
, struct nlmsgerr
*err
,
825 nl_ext_ack_fn_t errfn
)
827 if (nl_dump_ext_ack(h
, errfn
))
830 fprintf(stderr
, "RTNETLINK answers: %s\n",
831 strerror(-err
->error
));
835 static int __rtnl_talk_iov(struct rtnl_handle
*rtnl
, struct iovec
*iov
,
836 size_t iovlen
, struct nlmsghdr
**answer
,
837 bool show_rtnl_err
, nl_ext_ack_fn_t errfn
)
839 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
841 struct msghdr msg
= {
843 .msg_namelen
= sizeof(nladdr
),
845 .msg_iovlen
= iovlen
,
847 unsigned int seq
= 0;
852 for (i
= 0; i
< iovlen
; i
++) {
854 h
->nlmsg_seq
= seq
= ++rtnl
->seq
;
856 h
->nlmsg_flags
|= NLM_F_ACK
;
859 status
= sendmsg(rtnl
->fd
, &msg
, 0);
861 perror("Cannot talk to rtnetlink");
865 /* change msg to use the response iov */
871 status
= rtnl_recvmsg(rtnl
->fd
, &msg
, &buf
);
877 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
879 "sender address length == %d\n",
883 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
884 int len
= h
->nlmsg_len
;
885 int l
= len
- sizeof(*h
);
887 if (l
< 0 || len
> status
) {
888 if (msg
.msg_flags
& MSG_TRUNC
) {
889 fprintf(stderr
, "Truncated message\n");
894 "!!!malformed message: len=%d\n",
899 if (nladdr
.nl_pid
!= 0 ||
900 h
->nlmsg_pid
!= rtnl
->local
.nl_pid
||
901 h
->nlmsg_seq
> seq
|| h
->nlmsg_seq
< seq
- iovlen
) {
902 /* Don't forget to skip that message. */
903 status
-= NLMSG_ALIGN(len
);
904 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
908 if (h
->nlmsg_type
== NLMSG_ERROR
) {
909 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
910 int error
= err
->error
;
912 if (l
< sizeof(struct nlmsgerr
)) {
913 fprintf(stderr
, "ERROR truncated\n");
919 /* check messages from kernel */
920 nl_dump_ext_ack(h
, errfn
);
924 if (rtnl
->proto
!= NETLINK_SOCK_DIAG
&&
926 rtnl_talk_error(h
, err
, errfn
);
930 *answer
= (struct nlmsghdr
*)buf
;
936 return error
? -i
: 0;
940 *answer
= (struct nlmsghdr
*)buf
;
944 fprintf(stderr
, "Unexpected reply!!!\n");
946 status
-= NLMSG_ALIGN(len
);
947 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
951 if (msg
.msg_flags
& MSG_TRUNC
) {
952 fprintf(stderr
, "Message truncated\n");
957 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
963 static int __rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
964 struct nlmsghdr
**answer
,
965 bool show_rtnl_err
, nl_ext_ack_fn_t errfn
)
969 .iov_len
= n
->nlmsg_len
972 return __rtnl_talk_iov(rtnl
, &iov
, 1, answer
, show_rtnl_err
, errfn
);
975 int rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
976 struct nlmsghdr
**answer
)
978 return __rtnl_talk(rtnl
, n
, answer
, true, NULL
);
981 int rtnl_talk_iov(struct rtnl_handle
*rtnl
, struct iovec
*iovec
, size_t iovlen
,
982 struct nlmsghdr
**answer
)
984 return __rtnl_talk_iov(rtnl
, iovec
, iovlen
, answer
, true, NULL
);
987 int rtnl_talk_suppress_rtnl_errmsg(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
988 struct nlmsghdr
**answer
)
990 return __rtnl_talk(rtnl
, n
, answer
, false, NULL
);
993 int rtnl_listen_all_nsid(struct rtnl_handle
*rth
)
997 if (setsockopt(rth
->fd
, SOL_NETLINK
, NETLINK_LISTEN_ALL_NSID
, &on
,
999 perror("NETLINK_LISTEN_ALL_NSID");
1002 rth
->flags
|= RTNL_HANDLE_F_LISTEN_ALL_NSID
;
1006 int rtnl_listen(struct rtnl_handle
*rtnl
,
1007 rtnl_listen_filter_t handler
,
1012 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
1014 struct msghdr msg
= {
1015 .msg_name
= &nladdr
,
1016 .msg_namelen
= sizeof(nladdr
),
1021 char cmsgbuf
[BUFSIZ
];
1023 if (rtnl
->flags
& RTNL_HANDLE_F_LISTEN_ALL_NSID
) {
1024 msg
.msg_control
= &cmsgbuf
;
1025 msg
.msg_controllen
= sizeof(cmsgbuf
);
1030 struct rtnl_ctrl_data ctrl
;
1031 struct cmsghdr
*cmsg
;
1033 iov
.iov_len
= sizeof(buf
);
1034 status
= recvmsg(rtnl
->fd
, &msg
, 0);
1037 if (errno
== EINTR
|| errno
== EAGAIN
)
1039 fprintf(stderr
, "netlink receive error %s (%d)\n",
1040 strerror(errno
), errno
);
1041 if (errno
== ENOBUFS
)
1046 fprintf(stderr
, "EOF on netlink\n");
1049 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
1051 "Sender address length == %d\n",
1056 if (rtnl
->flags
& RTNL_HANDLE_F_LISTEN_ALL_NSID
) {
1057 memset(&ctrl
, 0, sizeof(ctrl
));
1059 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
;
1060 cmsg
= CMSG_NXTHDR(&msg
, cmsg
))
1061 if (cmsg
->cmsg_level
== SOL_NETLINK
&&
1062 cmsg
->cmsg_type
== NETLINK_LISTEN_ALL_NSID
&&
1063 cmsg
->cmsg_len
== CMSG_LEN(sizeof(int))) {
1064 int *data
= (int *)CMSG_DATA(cmsg
);
1070 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
1072 int len
= h
->nlmsg_len
;
1073 int l
= len
- sizeof(*h
);
1075 if (l
< 0 || len
> status
) {
1076 if (msg
.msg_flags
& MSG_TRUNC
) {
1077 fprintf(stderr
, "Truncated message\n");
1081 "!!!malformed message: len=%d\n",
1086 err
= handler(&ctrl
, h
, jarg
);
1090 status
-= NLMSG_ALIGN(len
);
1091 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
1093 if (msg
.msg_flags
& MSG_TRUNC
) {
1094 fprintf(stderr
, "Message truncated\n");
1098 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
1104 int rtnl_from_file(FILE *rtnl
, rtnl_listen_filter_t handler
,
1109 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
1115 status
= fread(&buf
, 1, sizeof(*h
), rtnl
);
1120 perror("rtnl_from_file: fread");
1127 l
= len
- sizeof(*h
);
1129 if (l
< 0 || len
> sizeof(buf
)) {
1130 fprintf(stderr
, "!!!malformed message: len=%d @%lu\n",
1135 status
= fread(NLMSG_DATA(h
), 1, NLMSG_ALIGN(l
), rtnl
);
1138 perror("rtnl_from_file: fread");
1142 fprintf(stderr
, "rtnl-from_file: truncated message\n");
1146 err
= handler(NULL
, h
, jarg
);
1152 int addattr(struct nlmsghdr
*n
, int maxlen
, int type
)
1154 return addattr_l(n
, maxlen
, type
, NULL
, 0);
1157 int addattr8(struct nlmsghdr
*n
, int maxlen
, int type
, __u8 data
)
1159 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u8
));
1162 int addattr16(struct nlmsghdr
*n
, int maxlen
, int type
, __u16 data
)
1164 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u16
));
1167 int addattr32(struct nlmsghdr
*n
, int maxlen
, int type
, __u32 data
)
1169 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u32
));
1172 int addattr64(struct nlmsghdr
*n
, int maxlen
, int type
, __u64 data
)
1174 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u64
));
1177 int addattrstrz(struct nlmsghdr
*n
, int maxlen
, int type
, const char *str
)
1179 return addattr_l(n
, maxlen
, type
, str
, strlen(str
)+1);
1182 int addattr_l(struct nlmsghdr
*n
, int maxlen
, int type
, const void *data
,
1185 int len
= RTA_LENGTH(alen
);
1188 if (NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
) > maxlen
) {
1190 "addattr_l ERROR: message exceeded bound of %d\n",
1194 rta
= NLMSG_TAIL(n
);
1195 rta
->rta_type
= type
;
1198 memcpy(RTA_DATA(rta
), data
, alen
);
1199 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);
1203 int addraw_l(struct nlmsghdr
*n
, int maxlen
, const void *data
, int len
)
1205 if (NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
) > maxlen
) {
1207 "addraw_l ERROR: message exceeded bound of %d\n",
1212 memcpy(NLMSG_TAIL(n
), data
, len
);
1213 memset((void *) NLMSG_TAIL(n
) + len
, 0, NLMSG_ALIGN(len
) - len
);
1214 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
);
1218 struct rtattr
*addattr_nest(struct nlmsghdr
*n
, int maxlen
, int type
)
1220 struct rtattr
*nest
= NLMSG_TAIL(n
);
1222 addattr_l(n
, maxlen
, type
, NULL
, 0);
1226 int addattr_nest_end(struct nlmsghdr
*n
, struct rtattr
*nest
)
1228 nest
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)nest
;
1229 return n
->nlmsg_len
;
1232 struct rtattr
*addattr_nest_compat(struct nlmsghdr
*n
, int maxlen
, int type
,
1233 const void *data
, int len
)
1235 struct rtattr
*start
= NLMSG_TAIL(n
);
1237 addattr_l(n
, maxlen
, type
, data
, len
);
1238 addattr_nest(n
, maxlen
, type
);
1242 int addattr_nest_compat_end(struct nlmsghdr
*n
, struct rtattr
*start
)
1244 struct rtattr
*nest
= (void *)start
+ NLMSG_ALIGN(start
->rta_len
);
1246 start
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)start
;
1247 addattr_nest_end(n
, nest
);
1248 return n
->nlmsg_len
;
1251 int rta_addattr32(struct rtattr
*rta
, int maxlen
, int type
, __u32 data
)
1253 int len
= RTA_LENGTH(4);
1254 struct rtattr
*subrta
;
1256 if (RTA_ALIGN(rta
->rta_len
) + len
> maxlen
) {
1258 "rta_addattr32: Error! max allowed bound %d exceeded\n",
1262 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
1263 subrta
->rta_type
= type
;
1264 subrta
->rta_len
= len
;
1265 memcpy(RTA_DATA(subrta
), &data
, 4);
1266 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + len
;
1270 int rta_addattr_l(struct rtattr
*rta
, int maxlen
, int type
,
1271 const void *data
, int alen
)
1273 struct rtattr
*subrta
;
1274 int len
= RTA_LENGTH(alen
);
1276 if (RTA_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
) > maxlen
) {
1278 "rta_addattr_l: Error! max allowed bound %d exceeded\n",
1282 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
1283 subrta
->rta_type
= type
;
1284 subrta
->rta_len
= len
;
1286 memcpy(RTA_DATA(subrta
), data
, alen
);
1287 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
);
1291 int rta_addattr8(struct rtattr
*rta
, int maxlen
, int type
, __u8 data
)
1293 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u8
));
1296 int rta_addattr16(struct rtattr
*rta
, int maxlen
, int type
, __u16 data
)
1298 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u16
));
1301 int rta_addattr64(struct rtattr
*rta
, int maxlen
, int type
, __u64 data
)
1303 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u64
));
1306 struct rtattr
*rta_nest(struct rtattr
*rta
, int maxlen
, int type
)
1308 struct rtattr
*nest
= RTA_TAIL(rta
);
1310 rta_addattr_l(rta
, maxlen
, type
, NULL
, 0);
1315 int rta_nest_end(struct rtattr
*rta
, struct rtattr
*nest
)
1317 nest
->rta_len
= (void *)RTA_TAIL(rta
) - (void *)nest
;
1319 return rta
->rta_len
;
1322 int parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
1324 return parse_rtattr_flags(tb
, max
, rta
, len
, 0);
1327 int parse_rtattr_flags(struct rtattr
*tb
[], int max
, struct rtattr
*rta
,
1328 int len
, unsigned short flags
)
1330 unsigned short type
;
1332 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
1333 while (RTA_OK(rta
, len
)) {
1334 type
= rta
->rta_type
& ~flags
;
1335 if ((type
<= max
) && (!tb
[type
]))
1337 rta
= RTA_NEXT(rta
, len
);
1340 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n",
1345 struct rtattr
*parse_rtattr_one(int type
, struct rtattr
*rta
, int len
)
1347 while (RTA_OK(rta
, len
)) {
1348 if (rta
->rta_type
== type
)
1350 rta
= RTA_NEXT(rta
, len
);
1354 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n",
1359 int __parse_rtattr_nested_compat(struct rtattr
*tb
[], int max
,
1363 if (RTA_PAYLOAD(rta
) < len
)
1365 if (RTA_PAYLOAD(rta
) >= RTA_ALIGN(len
) + sizeof(struct rtattr
)) {
1366 rta
= RTA_DATA(rta
) + RTA_ALIGN(len
);
1367 return parse_rtattr_nested(tb
, max
, rta
);
1369 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));