]>
git.proxmox.com Git - mirror_frr.git/blob - pimd/mtracebis_netlink.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * libnetlink.c RTnetlink service routines.
5 * 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
);
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
;
189 .iov_len
= sizeof(buf
),
191 struct msghdr msg
= {
193 .msg_namelen
= sizeof(nladdr
),
200 const struct rtnl_dump_filter_arg
*a
;
204 iov
.iov_len
= sizeof(buf
);
205 status
= recvmsg(rth
->fd
, &msg
, 0);
208 if (errno
== EINTR
|| errno
== EAGAIN
)
210 fprintf(stderr
, "netlink receive error %s (%d)\n",
211 strerror(errno
), errno
);
216 fprintf(stderr
, "EOF on netlink\n");
220 for (a
= arg
; a
->filter
; a
++) {
221 struct nlmsghdr
*h
= (struct nlmsghdr
*)iov
.iov_base
;
224 while (NLMSG_OK(h
, (uint32_t)msglen
)) {
227 if (nladdr
.nl_pid
!= 0
228 || h
->nlmsg_pid
!= rth
->local
.nl_pid
229 || h
->nlmsg_seq
!= rth
->dump
) {
231 err
= a
->junk(&nladdr
, h
,
239 if (h
->nlmsg_type
== NLMSG_DONE
) {
241 break; /* process next filter */
243 if (h
->nlmsg_type
== NLMSG_ERROR
) {
244 struct nlmsgerr
*merr
=
245 (struct nlmsgerr
*)NLMSG_DATA(
248 < NLMSG_LENGTH(sizeof(
251 "ERROR truncated\n");
253 errno
= -merr
->error
;
254 perror("RTNETLINK answers");
258 err
= a
->filter(&nladdr
, h
, a
->arg1
);
263 h
= NLMSG_NEXT(h
, msglen
);
270 if (msg
.msg_flags
& MSG_TRUNC
) {
271 fprintf(stderr
, "Message truncated\n");
275 fprintf(stderr
, "!!!Remnant of size %d\n", msglen
);
281 int rtnl_dump_filter(struct rtnl_handle
*rth
, rtnl_filter_t filter
, void *arg1
,
282 rtnl_filter_t junk
, void *arg2
)
284 const struct rtnl_dump_filter_arg a
[2] = {
285 {.filter
= filter
, .arg1
= arg1
, .junk
= junk
, .arg2
= arg2
},
286 {.filter
= NULL
, .arg1
= NULL
, .junk
= NULL
, .arg2
= NULL
}};
288 return rtnl_dump_filter_l(rth
, a
);
291 int rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
, pid_t peer
,
292 unsigned groups
, struct nlmsghdr
*answer
, rtnl_filter_t junk
,
298 struct sockaddr_nl nladdr
;
299 struct iovec iov
= {.iov_base
= (void *)n
, .iov_len
= n
->nlmsg_len
};
300 struct msghdr msg
= {
302 .msg_namelen
= sizeof(nladdr
),
308 memset(&nladdr
, 0, sizeof(nladdr
));
309 nladdr
.nl_family
= AF_NETLINK
;
310 nladdr
.nl_pid
= peer
;
311 nladdr
.nl_groups
= groups
;
313 n
->nlmsg_seq
= seq
= ++rtnl
->seq
;
316 n
->nlmsg_flags
|= NLM_F_ACK
;
318 status
= sendmsg(rtnl
->fd
, &msg
, 0);
321 perror("Cannot talk to rtnetlink");
325 memset(buf
, 0, sizeof(buf
));
330 iov
.iov_len
= sizeof(buf
);
331 status
= recvmsg(rtnl
->fd
, &msg
, 0);
334 if (errno
== EINTR
|| errno
== EAGAIN
)
336 fprintf(stderr
, "netlink receive error %s (%d)\n",
337 strerror(errno
), errno
);
341 fprintf(stderr
, "EOF on netlink\n");
344 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
345 fprintf(stderr
, "sender address length == %d\n",
349 for (h
= (struct nlmsghdr
*)iov
.iov_base
;
350 status
>= (int)sizeof(*h
);) {
352 int len
= h
->nlmsg_len
;
353 int l
= len
- sizeof(*h
);
355 if (l
< 0 || len
> status
) {
356 if (msg
.msg_flags
& MSG_TRUNC
) {
357 fprintf(stderr
, "Truncated message\n");
361 "!!!malformed message: len=%d\n", len
);
365 if ((int)nladdr
.nl_pid
!= peer
366 || h
->nlmsg_pid
!= rtnl
->local
.nl_pid
367 || h
->nlmsg_seq
!= seq
) {
369 err
= junk(&nladdr
, h
, jarg
);
373 /* Don't forget to skip that message. */
374 status
-= NLMSG_ALIGN(len
);
375 h
= (struct nlmsghdr
*)((char *)h
380 if (h
->nlmsg_type
== NLMSG_ERROR
) {
381 struct nlmsgerr
*merr
=
382 (struct nlmsgerr
*)NLMSG_DATA(h
);
383 if (l
< (int)sizeof(struct nlmsgerr
)) {
384 fprintf(stderr
, "ERROR truncated\n");
386 errno
= -merr
->error
;
393 perror("RTNETLINK answers");
398 memcpy(answer
, h
, h
->nlmsg_len
);
402 fprintf(stderr
, "Unexpected reply!!!\n");
404 status
-= NLMSG_ALIGN(len
);
405 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
407 if (msg
.msg_flags
& MSG_TRUNC
) {
408 fprintf(stderr
, "Message truncated\n");
412 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
418 int rtnl_listen(struct rtnl_handle
*rtnl
, rtnl_filter_t handler
, void *jarg
)
422 struct sockaddr_nl nladdr
;
426 .iov_len
= sizeof(buf
),
428 struct msghdr msg
= {
430 .msg_namelen
= sizeof(nladdr
),
435 memset(&nladdr
, 0, sizeof(nladdr
));
436 nladdr
.nl_family
= AF_NETLINK
;
438 nladdr
.nl_groups
= 0;
441 iov
.iov_len
= sizeof(buf
);
442 status
= recvmsg(rtnl
->fd
, &msg
, 0);
445 if (errno
== EINTR
|| errno
== EAGAIN
)
447 fprintf(stderr
, "netlink receive error %s (%d)\n",
448 strerror(errno
), errno
);
449 if (errno
== ENOBUFS
)
454 fprintf(stderr
, "EOF on netlink\n");
457 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
458 fprintf(stderr
, "Sender address length == %d\n",
462 for (h
= (struct nlmsghdr
*)buf
; status
>= (int)sizeof(*h
);) {
464 int len
= h
->nlmsg_len
;
465 int l
= len
- sizeof(*h
);
467 if (l
< 0 || len
> status
) {
468 if (msg
.msg_flags
& MSG_TRUNC
) {
469 fprintf(stderr
, "Truncated message\n");
473 "!!!malformed message: len=%d\n", len
);
477 err
= handler(&nladdr
, h
, jarg
);
481 status
-= NLMSG_ALIGN(len
);
482 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
484 if (msg
.msg_flags
& MSG_TRUNC
) {
485 fprintf(stderr
, "Message truncated\n");
489 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
495 int rtnl_from_file(FILE *rtnl
, rtnl_filter_t handler
, void *jarg
)
497 struct sockaddr_nl nladdr
;
499 struct nlmsghdr
*h
= (void *)buf
;
501 memset(&nladdr
, 0, sizeof(nladdr
));
502 nladdr
.nl_family
= AF_NETLINK
;
504 nladdr
.nl_groups
= 0;
511 arl
= fread(&buf
, 1, rl
, rtnl
);
518 fprintf(stderr
, "%s: header read failed\n",
521 fprintf(stderr
, "%s: truncated header\n",
526 l
= h
->nlmsg_len
> rl
? h
->nlmsg_len
- rl
: 0;
528 if (l
== 0 || (l
+ (size_t)NLMSG_HDRLEN
) > sizeof(buf
)) {
529 fprintf(stderr
, "%s: malformed message: len=%zu @%lu\n",
530 __func__
, (size_t)h
->nlmsg_len
, ftell(rtnl
));
535 arl
= fread(NLMSG_DATA(h
), 1, rl
, rtnl
);
539 fprintf(stderr
, "%s: msg read failed\n",
542 fprintf(stderr
, "%s: truncated message\n",
547 err
= handler(&nladdr
, h
, jarg
);
553 int addattr32(struct nlmsghdr
*n
, int maxlen
, int type
, __u32 data
)
555 int len
= RTA_LENGTH(4);
557 if ((int)(NLMSG_ALIGN(n
->nlmsg_len
) + len
) > maxlen
) {
559 "addattr32: Error! max allowed bound %d exceeded\n",
564 rta
->rta_type
= type
;
566 memcpy(RTA_DATA(rta
), &data
, 4);
567 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + len
;
571 int addattr_l(struct nlmsghdr
*n
, int maxlen
, int type
, const void *data
,
574 int len
= RTA_LENGTH(alen
);
577 if ((int)(NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
)) > maxlen
) {
579 "addattr_l ERROR: message exceeded bound of %d\n",
584 rta
->rta_type
= type
;
588 memcpy(RTA_DATA(rta
), data
, alen
);
592 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);
596 int addraw_l(struct nlmsghdr
*n
, int maxlen
, const void *data
, int len
)
598 if ((int)(NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
)) > maxlen
) {
600 "addraw_l ERROR: message exceeded bound of %d\n",
605 memcpy(NLMSG_TAIL(n
), data
, len
);
606 memset((uint8_t *)NLMSG_TAIL(n
) + len
, 0, NLMSG_ALIGN(len
) - len
);
607 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
);
611 struct rtattr
*addattr_nest(struct nlmsghdr
*n
, int maxlen
, int type
)
613 struct rtattr
*nest
= NLMSG_TAIL(n
);
615 addattr_l(n
, maxlen
, type
, NULL
, 0);
619 int addattr_nest_end(struct nlmsghdr
*n
, struct rtattr
*nest
)
621 nest
->rta_len
= (uint8_t *)NLMSG_TAIL(n
) - (uint8_t *)nest
;
625 struct rtattr
*addattr_nest_compat(struct nlmsghdr
*n
, int maxlen
, int type
,
626 const void *data
, int len
)
628 struct rtattr
*start
= NLMSG_TAIL(n
);
630 addattr_l(n
, maxlen
, type
, data
, len
);
631 addattr_nest(n
, maxlen
, type
);
635 int addattr_nest_compat_end(struct nlmsghdr
*n
, struct rtattr
*start
)
637 struct rtattr
*nest
= start
+ NLMSG_ALIGN(start
->rta_len
);
639 start
->rta_len
= (uint8_t *)NLMSG_TAIL(n
) - (uint8_t *)start
;
640 addattr_nest_end(n
, nest
);
644 int rta_addattr32(struct rtattr
*rta
, int maxlen
, int type
, __u32 data
)
646 int len
= RTA_LENGTH(4);
647 struct rtattr
*subrta
;
649 if ((int)(RTA_ALIGN(rta
->rta_len
) + len
) > maxlen
) {
651 "rta_addattr32: Error! max allowed bound %d exceeded\n",
655 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
656 subrta
->rta_type
= type
;
657 subrta
->rta_len
= len
;
658 memcpy(RTA_DATA(subrta
), &data
, 4);
659 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + len
;
663 int rta_addattr_l(struct rtattr
*rta
, int maxlen
, int type
, const void *data
,
666 struct rtattr
*subrta
;
667 int len
= RTA_LENGTH(alen
);
669 if ((int)(RTA_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
)) > maxlen
) {
671 "rta_addattr_l: Error! max allowed bound %d exceeded\n",
675 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
676 subrta
->rta_type
= type
;
677 subrta
->rta_len
= len
;
678 memcpy(RTA_DATA(subrta
), data
, alen
);
679 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
);
683 int parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
685 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
686 while (RTA_OK(rta
, len
)) {
687 if ((rta
->rta_type
<= max
) && (!tb
[rta
->rta_type
]))
688 tb
[rta
->rta_type
] = rta
;
689 rta
= RTA_NEXT(rta
, len
);
692 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
,
697 int parse_rtattr_byindex(struct rtattr
*tb
[], int max
, struct rtattr
*rta
,
702 memset(tb
, 0, sizeof(struct rtattr
*) * max
);
703 while (RTA_OK(rta
, len
)) {
704 if (rta
->rta_type
<= max
&& i
< max
)
706 rta
= RTA_NEXT(rta
, len
);
709 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
,
714 int __parse_rtattr_nested_compat(struct rtattr
*tb
[], int max
,
715 struct rtattr
*rta
, int len
)
717 if ((int)RTA_PAYLOAD(rta
) < len
)
719 if (RTA_PAYLOAD(rta
) >= RTA_ALIGN(len
) + sizeof(struct rtattr
)) {
720 rta
= (struct rtattr
*)(uint8_t *)RTA_DATA(rta
)
722 return parse_rtattr_nested(tb
, max
, rta
);
724 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
728 #endif /* __linux__ */