]>
git.proxmox.com Git - mirror_frr.git/blob - pimd/mtracebis_netlink.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>
20 #include <net/if_arp.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
29 #include "mtracebis_netlink.h"
31 int rcvbuf
= 1024 * 1024;
33 void rtnl_close(struct rtnl_handle
*rth
)
41 int rtnl_open_byproto(struct rtnl_handle
*rth
, unsigned subscriptions
,
47 memset(rth
, 0, sizeof(*rth
));
49 rth
->fd
= socket(AF_NETLINK
, SOCK_RAW
, protocol
);
51 perror("Cannot open netlink socket");
55 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_SNDBUF
, &sndbuf
, sizeof(sndbuf
))
61 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_RCVBUF
, &rcvbuf
, sizeof(rcvbuf
))
67 memset(&rth
->local
, 0, sizeof(rth
->local
));
68 rth
->local
.nl_family
= AF_NETLINK
;
69 rth
->local
.nl_groups
= subscriptions
;
71 if (bind(rth
->fd
, (struct sockaddr
*)&rth
->local
, sizeof(rth
->local
))
73 perror("Cannot bind netlink socket");
76 addr_len
= sizeof(rth
->local
);
77 if (getsockname(rth
->fd
, (struct sockaddr
*)&rth
->local
, &addr_len
)
79 perror("Cannot getsockname");
82 if (addr_len
!= sizeof(rth
->local
)) {
83 fprintf(stderr
, "Wrong address length %d\n", addr_len
);
86 if (rth
->local
.nl_family
!= AF_NETLINK
) {
87 fprintf(stderr
, "Wrong address family %d\n",
88 rth
->local
.nl_family
);
91 rth
->seq
= time(NULL
);
95 int rtnl_open(struct rtnl_handle
*rth
, unsigned subscriptions
)
97 return rtnl_open_byproto(rth
, subscriptions
, NETLINK_ROUTE
);
100 int rtnl_wilddump_request(struct rtnl_handle
*rth
, int family
, int type
)
107 memset(&req
, 0, sizeof(req
));
108 req
.nlh
.nlmsg_len
= sizeof(req
);
109 req
.nlh
.nlmsg_type
= type
;
110 req
.nlh
.nlmsg_flags
= NLM_F_ROOT
| NLM_F_MATCH
| NLM_F_REQUEST
;
111 req
.nlh
.nlmsg_pid
= 0;
112 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
113 req
.g
.rtgen_family
= family
;
115 return send(rth
->fd
, (void *)&req
, sizeof(req
), 0);
118 int rtnl_send(struct rtnl_handle
*rth
, const char *buf
, int len
)
120 return send(rth
->fd
, buf
, len
, 0);
123 int rtnl_send_check(struct rtnl_handle
*rth
, const char *buf
, int len
)
129 status
= send(rth
->fd
, buf
, len
, 0);
133 /* Check for immediate errors */
134 status
= recv(rth
->fd
, resp
, sizeof(resp
), MSG_DONTWAIT
| MSG_PEEK
);
141 for (h
= (struct nlmsghdr
*)resp
; NLMSG_OK(h
, (uint32_t)status
);
142 h
= NLMSG_NEXT(h
, status
)) {
143 if (h
->nlmsg_type
== NLMSG_ERROR
) {
144 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
146 < NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
147 fprintf(stderr
, "ERROR truncated\n");
157 int rtnl_dump_request(struct rtnl_handle
*rth
, int type
, void *req
, int len
)
160 struct sockaddr_nl nladdr
;
161 struct iovec iov
[2] = {{.iov_base
= &nlh
, .iov_len
= sizeof(nlh
)},
162 {.iov_base
= req
, .iov_len
= len
}};
163 struct msghdr msg
= {
165 .msg_namelen
= sizeof(nladdr
),
170 memset(&nladdr
, 0, sizeof(nladdr
));
171 nladdr
.nl_family
= AF_NETLINK
;
173 nlh
.nlmsg_len
= NLMSG_LENGTH(len
);
174 nlh
.nlmsg_type
= type
;
175 nlh
.nlmsg_flags
= NLM_F_ROOT
| NLM_F_MATCH
| NLM_F_REQUEST
;
177 nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
179 return sendmsg(rth
->fd
, &msg
, 0);
182 int rtnl_dump_filter_l(struct rtnl_handle
*rth
,
183 const struct rtnl_dump_filter_arg
*arg
)
185 struct sockaddr_nl nladdr
;
187 struct msghdr msg
= {
189 .msg_namelen
= sizeof(nladdr
),
198 const struct rtnl_dump_filter_arg
*a
;
202 iov
.iov_len
= sizeof(buf
);
203 status
= recvmsg(rth
->fd
, &msg
, 0);
206 if (errno
== EINTR
|| errno
== EAGAIN
)
208 fprintf(stderr
, "netlink receive error %s (%d)\n",
209 strerror(errno
), errno
);
214 fprintf(stderr
, "EOF on netlink\n");
218 for (a
= arg
; a
->filter
; a
++) {
219 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
222 while (NLMSG_OK(h
, (uint32_t)msglen
)) {
225 if (nladdr
.nl_pid
!= 0
226 || h
->nlmsg_pid
!= rth
->local
.nl_pid
227 || h
->nlmsg_seq
!= rth
->dump
) {
229 err
= a
->junk(&nladdr
, h
,
237 if (h
->nlmsg_type
== NLMSG_DONE
) {
239 break; /* process next filter */
241 if (h
->nlmsg_type
== NLMSG_ERROR
) {
242 struct nlmsgerr
*err
=
243 (struct nlmsgerr
*)NLMSG_DATA(
246 < NLMSG_LENGTH(sizeof(
249 "ERROR truncated\n");
252 perror("RTNETLINK answers");
256 err
= a
->filter(&nladdr
, h
, a
->arg1
);
261 h
= NLMSG_NEXT(h
, msglen
);
268 if (msg
.msg_flags
& MSG_TRUNC
) {
269 fprintf(stderr
, "Message truncated\n");
273 fprintf(stderr
, "!!!Remnant of size %d\n", msglen
);
279 int rtnl_dump_filter(struct rtnl_handle
*rth
, rtnl_filter_t filter
, void *arg1
,
280 rtnl_filter_t junk
, void *arg2
)
282 const struct rtnl_dump_filter_arg a
[2] = {
283 {.filter
= filter
, .arg1
= arg1
, .junk
= junk
, .arg2
= arg2
},
284 {.filter
= NULL
, .arg1
= NULL
, .junk
= NULL
, .arg2
= NULL
}};
286 return rtnl_dump_filter_l(rth
, a
);
289 int rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
, pid_t peer
,
290 unsigned groups
, struct nlmsghdr
*answer
, rtnl_filter_t junk
,
296 struct sockaddr_nl nladdr
;
297 struct iovec iov
= {.iov_base
= (void *)n
, .iov_len
= n
->nlmsg_len
};
298 struct msghdr msg
= {
300 .msg_namelen
= sizeof(nladdr
),
306 memset(&nladdr
, 0, sizeof(nladdr
));
307 nladdr
.nl_family
= AF_NETLINK
;
308 nladdr
.nl_pid
= peer
;
309 nladdr
.nl_groups
= groups
;
311 n
->nlmsg_seq
= seq
= ++rtnl
->seq
;
314 n
->nlmsg_flags
|= NLM_F_ACK
;
316 status
= sendmsg(rtnl
->fd
, &msg
, 0);
319 perror("Cannot talk to rtnetlink");
323 memset(buf
, 0, sizeof(buf
));
328 iov
.iov_len
= sizeof(buf
);
329 status
= recvmsg(rtnl
->fd
, &msg
, 0);
332 if (errno
== EINTR
|| errno
== EAGAIN
)
334 fprintf(stderr
, "netlink receive error %s (%d)\n",
335 strerror(errno
), errno
);
339 fprintf(stderr
, "EOF on netlink\n");
342 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
343 fprintf(stderr
, "sender address length == %d\n",
347 for (h
= (struct nlmsghdr
*)buf
; status
>= (int)sizeof(*h
);) {
349 int len
= h
->nlmsg_len
;
350 int l
= len
- sizeof(*h
);
352 if (l
< 0 || len
> status
) {
353 if (msg
.msg_flags
& MSG_TRUNC
) {
354 fprintf(stderr
, "Truncated message\n");
358 "!!!malformed message: len=%d\n", len
);
362 if ((int)nladdr
.nl_pid
!= peer
363 || h
->nlmsg_pid
!= rtnl
->local
.nl_pid
364 || h
->nlmsg_seq
!= seq
) {
366 err
= junk(&nladdr
, h
, jarg
);
370 /* Don't forget to skip that message. */
371 status
-= NLMSG_ALIGN(len
);
372 h
= (struct nlmsghdr
*)((char *)h
377 if (h
->nlmsg_type
== NLMSG_ERROR
) {
378 struct nlmsgerr
*err
=
379 (struct nlmsgerr
*)NLMSG_DATA(h
);
380 if (l
< (int)sizeof(struct nlmsgerr
)) {
381 fprintf(stderr
, "ERROR truncated\n");
390 perror("RTNETLINK answers");
395 memcpy(answer
, h
, h
->nlmsg_len
);
399 fprintf(stderr
, "Unexpected reply!!!\n");
401 status
-= NLMSG_ALIGN(len
);
402 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
404 if (msg
.msg_flags
& MSG_TRUNC
) {
405 fprintf(stderr
, "Message truncated\n");
409 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
415 int rtnl_listen(struct rtnl_handle
*rtnl
, rtnl_filter_t handler
, void *jarg
)
419 struct sockaddr_nl nladdr
;
421 struct msghdr msg
= {
423 .msg_namelen
= sizeof(nladdr
),
429 memset(&nladdr
, 0, sizeof(nladdr
));
430 nladdr
.nl_family
= AF_NETLINK
;
432 nladdr
.nl_groups
= 0;
436 iov
.iov_len
= sizeof(buf
);
437 status
= recvmsg(rtnl
->fd
, &msg
, 0);
440 if (errno
== EINTR
|| errno
== EAGAIN
)
442 fprintf(stderr
, "netlink receive error %s (%d)\n",
443 strerror(errno
), errno
);
444 if (errno
== ENOBUFS
)
449 fprintf(stderr
, "EOF on netlink\n");
452 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
453 fprintf(stderr
, "Sender address length == %d\n",
457 for (h
= (struct nlmsghdr
*)buf
; status
>= (int)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");
468 "!!!malformed message: len=%d\n", len
);
472 err
= handler(&nladdr
, h
, jarg
);
476 status
-= NLMSG_ALIGN(len
);
477 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
479 if (msg
.msg_flags
& MSG_TRUNC
) {
480 fprintf(stderr
, "Message truncated\n");
484 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
490 int rtnl_from_file(FILE *rtnl
, rtnl_filter_t handler
, void *jarg
)
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
> (int)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 addattr32(struct nlmsghdr
*n
, int maxlen
, int type
, __u32 data
)
545 int len
= RTA_LENGTH(4);
547 if ((int)(NLMSG_ALIGN(n
->nlmsg_len
) + len
) > maxlen
) {
549 "addattr32: Error! max allowed bound %d exceeded\n",
554 rta
->rta_type
= type
;
556 memcpy(RTA_DATA(rta
), &data
, 4);
557 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + len
;
561 int addattr_l(struct nlmsghdr
*n
, int maxlen
, int type
, const void *data
,
564 int len
= RTA_LENGTH(alen
);
567 if ((int)(NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
)) > maxlen
) {
569 "addattr_l ERROR: message exceeded bound of %d\n",
574 rta
->rta_type
= type
;
578 memcpy(RTA_DATA(rta
), data
, alen
);
582 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);
586 int addraw_l(struct nlmsghdr
*n
, int maxlen
, const void *data
, int len
)
588 if ((int)(NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
)) > maxlen
) {
590 "addraw_l ERROR: message exceeded bound of %d\n",
595 memcpy(NLMSG_TAIL(n
), data
, len
);
596 memset((uint8_t *)NLMSG_TAIL(n
) + len
, 0, NLMSG_ALIGN(len
) - len
);
597 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
);
601 struct rtattr
*addattr_nest(struct nlmsghdr
*n
, int maxlen
, int type
)
603 struct rtattr
*nest
= NLMSG_TAIL(n
);
605 addattr_l(n
, maxlen
, type
, NULL
, 0);
609 int addattr_nest_end(struct nlmsghdr
*n
, struct rtattr
*nest
)
611 nest
->rta_len
= (uint8_t *)NLMSG_TAIL(n
) - (uint8_t *)nest
;
615 struct rtattr
*addattr_nest_compat(struct nlmsghdr
*n
, int maxlen
, int type
,
616 const void *data
, int len
)
618 struct rtattr
*start
= NLMSG_TAIL(n
);
620 addattr_l(n
, maxlen
, type
, data
, len
);
621 addattr_nest(n
, maxlen
, type
);
625 int addattr_nest_compat_end(struct nlmsghdr
*n
, struct rtattr
*start
)
627 struct rtattr
*nest
= start
+ NLMSG_ALIGN(start
->rta_len
);
629 start
->rta_len
= (uint8_t *)NLMSG_TAIL(n
) - (uint8_t *)start
;
630 addattr_nest_end(n
, nest
);
634 int rta_addattr32(struct rtattr
*rta
, int maxlen
, int type
, __u32 data
)
636 int len
= RTA_LENGTH(4);
637 struct rtattr
*subrta
;
639 if ((int)(RTA_ALIGN(rta
->rta_len
) + len
) > maxlen
) {
641 "rta_addattr32: Error! max allowed bound %d exceeded\n",
645 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
646 subrta
->rta_type
= type
;
647 subrta
->rta_len
= len
;
648 memcpy(RTA_DATA(subrta
), &data
, 4);
649 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + len
;
653 int rta_addattr_l(struct rtattr
*rta
, int maxlen
, int type
, const void *data
,
656 struct rtattr
*subrta
;
657 int len
= RTA_LENGTH(alen
);
659 if ((int)(RTA_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
)) > maxlen
) {
661 "rta_addattr_l: Error! max allowed bound %d exceeded\n",
665 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
666 subrta
->rta_type
= type
;
667 subrta
->rta_len
= len
;
668 memcpy(RTA_DATA(subrta
), data
, alen
);
669 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
);
673 int parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
675 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
676 while (RTA_OK(rta
, len
)) {
677 if ((rta
->rta_type
<= max
) && (!tb
[rta
->rta_type
]))
678 tb
[rta
->rta_type
] = rta
;
679 rta
= RTA_NEXT(rta
, len
);
682 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
,
687 int parse_rtattr_byindex(struct rtattr
*tb
[], int max
, struct rtattr
*rta
,
692 memset(tb
, 0, sizeof(struct rtattr
*) * max
);
693 while (RTA_OK(rta
, len
)) {
694 if (rta
->rta_type
<= max
&& i
< max
)
696 rta
= RTA_NEXT(rta
, len
);
699 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
,
704 int __parse_rtattr_nested_compat(struct rtattr
*tb
[], int max
,
705 struct rtattr
*rta
, int len
)
707 if ((int)RTA_PAYLOAD(rta
) < len
)
709 if (RTA_PAYLOAD(rta
) >= RTA_ALIGN(len
) + sizeof(struct rtattr
)) {
710 rta
= (struct rtattr
*)(uint8_t *)RTA_DATA(rta
)
712 return parse_rtattr_nested(tb
, max
, rta
);
714 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
718 #endif /* __linux__ */