]>
git.proxmox.com Git - mirror_iproute2.git/blob - lib/libnetlink.c
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>
26 #include "libnetlink.h"
28 int rcvbuf
= 1024 * 1024;
30 void rtnl_close(struct rtnl_handle
*rth
)
38 int rtnl_open_byproto(struct rtnl_handle
*rth
, unsigned subscriptions
,
44 memset(rth
, 0, sizeof(*rth
));
46 rth
->proto
= protocol
;
47 rth
->fd
= socket(AF_NETLINK
, SOCK_RAW
| SOCK_CLOEXEC
, protocol
);
49 perror("Cannot open netlink socket");
53 if (setsockopt(rth
->fd
,SOL_SOCKET
,SO_SNDBUF
,&sndbuf
,sizeof(sndbuf
)) < 0) {
58 if (setsockopt(rth
->fd
,SOL_SOCKET
,SO_RCVBUF
,&rcvbuf
,sizeof(rcvbuf
)) < 0) {
63 memset(&rth
->local
, 0, sizeof(rth
->local
));
64 rth
->local
.nl_family
= AF_NETLINK
;
65 rth
->local
.nl_groups
= subscriptions
;
67 if (bind(rth
->fd
, (struct sockaddr
*)&rth
->local
, sizeof(rth
->local
)) < 0) {
68 perror("Cannot bind netlink socket");
71 addr_len
= sizeof(rth
->local
);
72 if (getsockname(rth
->fd
, (struct sockaddr
*)&rth
->local
, &addr_len
) < 0) {
73 perror("Cannot getsockname");
76 if (addr_len
!= sizeof(rth
->local
)) {
77 fprintf(stderr
, "Wrong address length %d\n", addr_len
);
80 if (rth
->local
.nl_family
!= AF_NETLINK
) {
81 fprintf(stderr
, "Wrong address family %d\n", rth
->local
.nl_family
);
84 rth
->seq
= time(NULL
);
88 int rtnl_open(struct rtnl_handle
*rth
, unsigned subscriptions
)
90 return rtnl_open_byproto(rth
, subscriptions
, NETLINK_ROUTE
);
93 int rtnl_wilddump_request(struct rtnl_handle
*rth
, int family
, int type
)
95 return rtnl_wilddump_req_filter(rth
, family
, type
, RTEXT_FILTER_VF
);
98 int rtnl_wilddump_req_filter(struct rtnl_handle
*rth
, int family
, int type
,
103 struct ifinfomsg ifm
;
104 /* attribute has to be NLMSG aligned */
105 struct rtattr ext_req
__attribute__ ((aligned(NLMSG_ALIGNTO
)));
106 __u32 ext_filter_mask
;
109 memset(&req
, 0, sizeof(req
));
110 req
.nlh
.nlmsg_len
= sizeof(req
);
111 req
.nlh
.nlmsg_type
= type
;
112 req
.nlh
.nlmsg_flags
= NLM_F_DUMP
|NLM_F_REQUEST
;
113 req
.nlh
.nlmsg_pid
= 0;
114 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
115 req
.ifm
.ifi_family
= family
;
117 req
.ext_req
.rta_type
= IFLA_EXT_MASK
;
118 req
.ext_req
.rta_len
= RTA_LENGTH(sizeof(__u32
));
119 req
.ext_filter_mask
= filt_mask
;
121 return send(rth
->fd
, (void*)&req
, sizeof(req
), 0);
124 int rtnl_send(struct rtnl_handle
*rth
, const void *buf
, int len
)
126 return send(rth
->fd
, buf
, len
, 0);
129 int rtnl_send_check(struct rtnl_handle
*rth
, const void *buf
, int len
)
135 status
= send(rth
->fd
, buf
, len
, 0);
139 /* Check for immediate errors */
140 status
= recv(rth
->fd
, resp
, sizeof(resp
), MSG_DONTWAIT
|MSG_PEEK
);
147 for (h
= (struct nlmsghdr
*)resp
; NLMSG_OK(h
, status
);
148 h
= NLMSG_NEXT(h
, status
)) {
149 if (h
->nlmsg_type
== NLMSG_ERROR
) {
150 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
151 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
152 fprintf(stderr
, "ERROR truncated\n");
162 int rtnl_dump_request(struct rtnl_handle
*rth
, int type
, void *req
, int len
)
165 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
166 struct iovec iov
[2] = {
167 { .iov_base
= &nlh
, .iov_len
= sizeof(nlh
) },
168 { .iov_base
= req
, .iov_len
= len
}
170 struct msghdr msg
= {
172 .msg_namelen
= sizeof(nladdr
),
177 nlh
.nlmsg_len
= NLMSG_LENGTH(len
);
178 nlh
.nlmsg_type
= type
;
179 nlh
.nlmsg_flags
= NLM_F_DUMP
|NLM_F_REQUEST
;
181 nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
183 return sendmsg(rth
->fd
, &msg
, 0);
186 int rtnl_dump_filter_l(struct rtnl_handle
*rth
,
187 const struct rtnl_dump_filter_arg
*arg
)
189 struct sockaddr_nl nladdr
;
191 struct msghdr msg
= {
193 .msg_namelen
= sizeof(nladdr
),
203 const struct rtnl_dump_filter_arg
*a
;
207 iov
.iov_len
= sizeof(buf
);
208 status
= recvmsg(rth
->fd
, &msg
, 0);
211 if (errno
== EINTR
|| errno
== EAGAIN
)
213 fprintf(stderr
, "netlink receive error %s (%d)\n",
214 strerror(errno
), errno
);
219 fprintf(stderr
, "EOF on netlink\n");
223 for (a
= arg
; a
->filter
; a
++) {
224 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
227 while (NLMSG_OK(h
, msglen
)) {
230 if (nladdr
.nl_pid
!= 0 ||
231 h
->nlmsg_pid
!= rth
->local
.nl_pid
||
232 h
->nlmsg_seq
!= rth
->dump
)
235 if (h
->nlmsg_flags
& NLM_F_DUMP_INTR
)
238 if (h
->nlmsg_type
== NLMSG_DONE
) {
240 break; /* process next filter */
242 if (h
->nlmsg_type
== NLMSG_ERROR
) {
243 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
244 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
))) {
246 "ERROR truncated\n");
249 if (rth
->proto
== NETLINK_SOCK_DIAG
&&
253 perror("RTNETLINK answers");
257 err
= a
->filter(&nladdr
, h
, a
->arg1
);
262 h
= NLMSG_NEXT(h
, msglen
);
269 "Dump was interrupted and may be inconsistent.\n");
273 if (msg
.msg_flags
& MSG_TRUNC
) {
274 fprintf(stderr
, "Message truncated\n");
278 fprintf(stderr
, "!!!Remnant of size %d\n", msglen
);
284 int rtnl_dump_filter(struct rtnl_handle
*rth
,
285 rtnl_filter_t filter
,
288 const struct rtnl_dump_filter_arg a
[2] = {
289 { .filter
= filter
, .arg1
= arg1
, },
290 { .filter
= NULL
, .arg1
= NULL
, },
293 return rtnl_dump_filter_l(rth
, a
);
296 int rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
, pid_t peer
,
297 unsigned groups
, struct nlmsghdr
*answer
)
302 struct sockaddr_nl nladdr
;
304 .iov_base
= (void*) n
,
305 .iov_len
= n
->nlmsg_len
307 struct msghdr msg
= {
309 .msg_namelen
= sizeof(nladdr
),
315 memset(&nladdr
, 0, sizeof(nladdr
));
316 nladdr
.nl_family
= AF_NETLINK
;
317 nladdr
.nl_pid
= peer
;
318 nladdr
.nl_groups
= groups
;
320 n
->nlmsg_seq
= seq
= ++rtnl
->seq
;
323 n
->nlmsg_flags
|= NLM_F_ACK
;
325 status
= sendmsg(rtnl
->fd
, &msg
, 0);
328 perror("Cannot talk to rtnetlink");
332 memset(buf
,0,sizeof(buf
));
337 iov
.iov_len
= sizeof(buf
);
338 status
= recvmsg(rtnl
->fd
, &msg
, 0);
341 if (errno
== EINTR
|| errno
== EAGAIN
)
343 fprintf(stderr
, "netlink receive error %s (%d)\n",
344 strerror(errno
), errno
);
348 fprintf(stderr
, "EOF on netlink\n");
351 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
352 fprintf(stderr
, "sender address length == %d\n", msg
.msg_namelen
);
355 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
356 int len
= h
->nlmsg_len
;
357 int l
= len
- sizeof(*h
);
359 if (l
< 0 || len
>status
) {
360 if (msg
.msg_flags
& MSG_TRUNC
) {
361 fprintf(stderr
, "Truncated message\n");
364 fprintf(stderr
, "!!!malformed message: len=%d\n", len
);
368 if (nladdr
.nl_pid
!= peer
||
369 h
->nlmsg_pid
!= rtnl
->local
.nl_pid
||
370 h
->nlmsg_seq
!= seq
) {
371 /* Don't forget to skip that message. */
372 status
-= NLMSG_ALIGN(len
);
373 h
= (struct nlmsghdr
*)((char*)h
+ NLMSG_ALIGN(len
));
377 if (h
->nlmsg_type
== NLMSG_ERROR
) {
378 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
379 if (l
< sizeof(struct nlmsgerr
)) {
380 fprintf(stderr
, "ERROR truncated\n");
384 memcpy(answer
, h
, h
->nlmsg_len
);
388 fprintf(stderr
, "RTNETLINK answers: %s\n", strerror(-err
->error
));
394 memcpy(answer
, h
, h
->nlmsg_len
);
398 fprintf(stderr
, "Unexpected reply!!!\n");
400 status
-= NLMSG_ALIGN(len
);
401 h
= (struct nlmsghdr
*)((char*)h
+ NLMSG_ALIGN(len
));
403 if (msg
.msg_flags
& MSG_TRUNC
) {
404 fprintf(stderr
, "Message truncated\n");
408 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
414 int rtnl_listen(struct rtnl_handle
*rtnl
,
415 rtnl_filter_t handler
,
420 struct sockaddr_nl nladdr
;
422 struct msghdr msg
= {
424 .msg_namelen
= sizeof(nladdr
),
430 memset(&nladdr
, 0, sizeof(nladdr
));
431 nladdr
.nl_family
= AF_NETLINK
;
433 nladdr
.nl_groups
= 0;
437 iov
.iov_len
= sizeof(buf
);
438 status
= recvmsg(rtnl
->fd
, &msg
, 0);
441 if (errno
== EINTR
|| errno
== EAGAIN
)
443 fprintf(stderr
, "netlink receive error %s (%d)\n",
444 strerror(errno
), errno
);
445 if (errno
== ENOBUFS
)
450 fprintf(stderr
, "EOF on netlink\n");
453 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
454 fprintf(stderr
, "Sender address length == %d\n", msg
.msg_namelen
);
457 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
459 int len
= h
->nlmsg_len
;
460 int l
= len
- sizeof(*h
);
462 if (l
<0 || len
>status
) {
463 if (msg
.msg_flags
& MSG_TRUNC
) {
464 fprintf(stderr
, "Truncated message\n");
467 fprintf(stderr
, "!!!malformed message: len=%d\n", len
);
471 err
= handler(&nladdr
, h
, jarg
);
475 status
-= NLMSG_ALIGN(len
);
476 h
= (struct nlmsghdr
*)((char*)h
+ NLMSG_ALIGN(len
));
478 if (msg
.msg_flags
& MSG_TRUNC
) {
479 fprintf(stderr
, "Message truncated\n");
483 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
489 int rtnl_from_file(FILE *rtnl
, rtnl_filter_t handler
,
493 struct sockaddr_nl nladdr
;
495 struct nlmsghdr
*h
= (void*)buf
;
497 memset(&nladdr
, 0, sizeof(nladdr
));
498 nladdr
.nl_family
= AF_NETLINK
;
500 nladdr
.nl_groups
= 0;
506 status
= fread(&buf
, 1, sizeof(*h
), rtnl
);
511 perror("rtnl_from_file: fread");
518 l
= len
- sizeof(*h
);
520 if (l
<0 || len
>sizeof(buf
)) {
521 fprintf(stderr
, "!!!malformed message: len=%d @%lu\n",
526 status
= fread(NLMSG_DATA(h
), 1, NLMSG_ALIGN(l
), rtnl
);
529 perror("rtnl_from_file: fread");
533 fprintf(stderr
, "rtnl-from_file: truncated message\n");
537 err
= handler(&nladdr
, h
, jarg
);
543 int addattr(struct nlmsghdr
*n
, int maxlen
, int type
)
545 return addattr_l(n
, maxlen
, type
, NULL
, 0);
548 int addattr8(struct nlmsghdr
*n
, int maxlen
, int type
, __u8 data
)
550 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u8
));
553 int addattr16(struct nlmsghdr
*n
, int maxlen
, int type
, __u16 data
)
555 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u16
));
558 int addattr32(struct nlmsghdr
*n
, int maxlen
, int type
, __u32 data
)
560 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u32
));
563 int addattr64(struct nlmsghdr
*n
, int maxlen
, int type
, __u64 data
)
565 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u64
));
568 int addattrstrz(struct nlmsghdr
*n
, int maxlen
, int type
, const char *str
)
570 return addattr_l(n
, maxlen
, type
, str
, strlen(str
)+1);
573 int addattr_l(struct nlmsghdr
*n
, int maxlen
, int type
, const void *data
,
576 int len
= RTA_LENGTH(alen
);
579 if (NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
) > maxlen
) {
580 fprintf(stderr
, "addattr_l ERROR: message exceeded bound of %d\n",maxlen
);
584 rta
->rta_type
= type
;
586 memcpy(RTA_DATA(rta
), data
, alen
);
587 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);
591 int addraw_l(struct nlmsghdr
*n
, int maxlen
, const void *data
, int len
)
593 if (NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
) > maxlen
) {
594 fprintf(stderr
, "addraw_l ERROR: message exceeded bound of %d\n",maxlen
);
598 memcpy(NLMSG_TAIL(n
), data
, len
);
599 memset((void *) NLMSG_TAIL(n
) + len
, 0, NLMSG_ALIGN(len
) - len
);
600 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
);
604 struct rtattr
*addattr_nest(struct nlmsghdr
*n
, int maxlen
, int type
)
606 struct rtattr
*nest
= NLMSG_TAIL(n
);
608 addattr_l(n
, maxlen
, type
, NULL
, 0);
612 int addattr_nest_end(struct nlmsghdr
*n
, struct rtattr
*nest
)
614 nest
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)nest
;
618 struct rtattr
*addattr_nest_compat(struct nlmsghdr
*n
, int maxlen
, int type
,
619 const void *data
, int len
)
621 struct rtattr
*start
= NLMSG_TAIL(n
);
623 addattr_l(n
, maxlen
, type
, data
, len
);
624 addattr_nest(n
, maxlen
, type
);
628 int addattr_nest_compat_end(struct nlmsghdr
*n
, struct rtattr
*start
)
630 struct rtattr
*nest
= (void *)start
+ NLMSG_ALIGN(start
->rta_len
);
632 start
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)start
;
633 addattr_nest_end(n
, nest
);
637 int rta_addattr32(struct rtattr
*rta
, int maxlen
, int type
, __u32 data
)
639 int len
= RTA_LENGTH(4);
640 struct rtattr
*subrta
;
642 if (RTA_ALIGN(rta
->rta_len
) + len
> maxlen
) {
643 fprintf(stderr
,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen
);
646 subrta
= (struct rtattr
*)(((char*)rta
) + RTA_ALIGN(rta
->rta_len
));
647 subrta
->rta_type
= type
;
648 subrta
->rta_len
= len
;
649 memcpy(RTA_DATA(subrta
), &data
, 4);
650 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + len
;
654 int rta_addattr_l(struct rtattr
*rta
, int maxlen
, int type
,
655 const void *data
, int alen
)
657 struct rtattr
*subrta
;
658 int len
= RTA_LENGTH(alen
);
660 if (RTA_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
) > maxlen
) {
661 fprintf(stderr
,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen
);
664 subrta
= (struct rtattr
*)(((char*)rta
) + RTA_ALIGN(rta
->rta_len
));
665 subrta
->rta_type
= type
;
666 subrta
->rta_len
= len
;
667 memcpy(RTA_DATA(subrta
), data
, alen
);
668 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
);
672 int parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
674 return parse_rtattr_flags(tb
, max
, rta
, len
, 0);
677 int parse_rtattr_flags(struct rtattr
*tb
[], int max
, struct rtattr
*rta
,
678 int len
, unsigned short flags
)
682 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
683 while (RTA_OK(rta
, len
)) {
684 type
= rta
->rta_type
& ~flags
;
685 if ((type
<= max
) && (!tb
[type
]))
687 rta
= RTA_NEXT(rta
,len
);
690 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
, rta
->rta_len
);
694 int parse_rtattr_byindex(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
698 memset(tb
, 0, sizeof(struct rtattr
*) * max
);
699 while (RTA_OK(rta
, len
)) {
700 if (rta
->rta_type
<= max
&& i
< max
)
702 rta
= RTA_NEXT(rta
,len
);
705 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
, rta
->rta_len
);
709 int __parse_rtattr_nested_compat(struct rtattr
*tb
[], int max
, struct rtattr
*rta
,
712 if (RTA_PAYLOAD(rta
) < len
)
714 if (RTA_PAYLOAD(rta
) >= RTA_ALIGN(len
) + sizeof(struct rtattr
)) {
715 rta
= RTA_DATA(rta
) + RTA_ALIGN(len
);
716 return parse_rtattr_nested(tb
, max
, rta
);
718 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));