]>
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>
24 #include <net/if_arp.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
33 #include "mtracebis_netlink.h"
35 int rcvbuf
= 1024 * 1024;
37 void rtnl_close(struct rtnl_handle
*rth
)
45 int rtnl_open_byproto(struct rtnl_handle
*rth
, unsigned subscriptions
,
51 memset(rth
, 0, sizeof(*rth
));
53 rth
->fd
= socket(AF_NETLINK
, SOCK_RAW
, protocol
);
55 perror("Cannot open netlink socket");
59 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_SNDBUF
, &sndbuf
, sizeof(sndbuf
))
65 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_RCVBUF
, &rcvbuf
, sizeof(rcvbuf
))
71 memset(&rth
->local
, 0, sizeof(rth
->local
));
72 rth
->local
.nl_family
= AF_NETLINK
;
73 rth
->local
.nl_groups
= subscriptions
;
75 if (bind(rth
->fd
, (struct sockaddr
*)&rth
->local
, sizeof(rth
->local
))
77 perror("Cannot bind netlink socket");
80 addr_len
= sizeof(rth
->local
);
81 if (getsockname(rth
->fd
, (struct sockaddr
*)&rth
->local
, &addr_len
)
83 perror("Cannot getsockname");
86 if (addr_len
!= sizeof(rth
->local
)) {
87 fprintf(stderr
, "Wrong address length %d\n", addr_len
);
90 if (rth
->local
.nl_family
!= AF_NETLINK
) {
91 fprintf(stderr
, "Wrong address family %d\n",
92 rth
->local
.nl_family
);
99 int rtnl_open(struct rtnl_handle
*rth
, unsigned subscriptions
)
101 return rtnl_open_byproto(rth
, subscriptions
, NETLINK_ROUTE
);
104 int rtnl_wilddump_request(struct rtnl_handle
*rth
, int family
, int type
)
111 memset(&req
, 0, sizeof(req
));
112 req
.nlh
.nlmsg_len
= sizeof(req
);
113 req
.nlh
.nlmsg_type
= type
;
114 req
.nlh
.nlmsg_flags
= NLM_F_ROOT
| NLM_F_MATCH
| NLM_F_REQUEST
;
115 req
.nlh
.nlmsg_pid
= 0;
116 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
117 req
.g
.rtgen_family
= family
;
119 return send(rth
->fd
, (void *)&req
, sizeof(req
), 0);
122 int rtnl_send(struct rtnl_handle
*rth
, const char *buf
, int len
)
124 return send(rth
->fd
, buf
, len
, 0);
127 int rtnl_send_check(struct rtnl_handle
*rth
, const char *buf
, int len
)
133 status
= send(rth
->fd
, buf
, len
, 0);
137 /* Check for immediate errors */
138 status
= recv(rth
->fd
, resp
, sizeof(resp
), MSG_DONTWAIT
| MSG_PEEK
);
145 for (h
= (struct nlmsghdr
*)resp
; NLMSG_OK(h
, (uint32_t)status
);
146 h
= NLMSG_NEXT(h
, status
)) {
147 if (h
->nlmsg_type
== NLMSG_ERROR
) {
148 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
150 < NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
151 fprintf(stderr
, "ERROR truncated\n");
161 int rtnl_dump_request(struct rtnl_handle
*rth
, int type
, void *req
, int len
)
164 struct sockaddr_nl nladdr
;
165 struct iovec iov
[2] = {{.iov_base
= &nlh
, .iov_len
= sizeof(nlh
)},
166 {.iov_base
= req
, .iov_len
= len
}};
167 struct msghdr msg
= {
169 .msg_namelen
= sizeof(nladdr
),
174 memset(&nladdr
, 0, sizeof(nladdr
));
175 nladdr
.nl_family
= AF_NETLINK
;
177 nlh
.nlmsg_len
= NLMSG_LENGTH(len
);
178 nlh
.nlmsg_type
= type
;
179 nlh
.nlmsg_flags
= NLM_F_ROOT
| NLM_F_MATCH
| 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
;
193 .iov_len
= sizeof(buf
),
195 struct msghdr msg
= {
197 .msg_namelen
= sizeof(nladdr
),
204 const struct rtnl_dump_filter_arg
*a
;
208 iov
.iov_len
= sizeof(buf
);
209 status
= recvmsg(rth
->fd
, &msg
, 0);
212 if (errno
== EINTR
|| errno
== EAGAIN
)
214 fprintf(stderr
, "netlink receive error %s (%d)\n",
215 strerror(errno
), errno
);
220 fprintf(stderr
, "EOF on netlink\n");
224 for (a
= arg
; a
->filter
; a
++) {
225 struct nlmsghdr
*h
= (struct nlmsghdr
*)iov
.iov_base
;
228 while (NLMSG_OK(h
, (uint32_t)msglen
)) {
231 if (nladdr
.nl_pid
!= 0
232 || h
->nlmsg_pid
!= rth
->local
.nl_pid
233 || h
->nlmsg_seq
!= rth
->dump
) {
235 err
= a
->junk(&nladdr
, h
,
243 if (h
->nlmsg_type
== NLMSG_DONE
) {
245 break; /* process next filter */
247 if (h
->nlmsg_type
== NLMSG_ERROR
) {
248 struct nlmsgerr
*merr
=
249 (struct nlmsgerr
*)NLMSG_DATA(
252 < NLMSG_LENGTH(sizeof(
255 "ERROR truncated\n");
257 errno
= -merr
->error
;
258 perror("RTNETLINK answers");
262 err
= a
->filter(&nladdr
, h
, a
->arg1
);
267 h
= NLMSG_NEXT(h
, msglen
);
274 if (msg
.msg_flags
& MSG_TRUNC
) {
275 fprintf(stderr
, "Message truncated\n");
279 fprintf(stderr
, "!!!Remnant of size %d\n", msglen
);
285 int rtnl_dump_filter(struct rtnl_handle
*rth
, rtnl_filter_t filter
, void *arg1
,
286 rtnl_filter_t junk
, void *arg2
)
288 const struct rtnl_dump_filter_arg a
[2] = {
289 {.filter
= filter
, .arg1
= arg1
, .junk
= junk
, .arg2
= arg2
},
290 {.filter
= NULL
, .arg1
= NULL
, .junk
= NULL
, .arg2
= NULL
}};
292 return rtnl_dump_filter_l(rth
, a
);
295 int rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
, pid_t peer
,
296 unsigned groups
, struct nlmsghdr
*answer
, rtnl_filter_t junk
,
302 struct sockaddr_nl nladdr
;
303 struct iovec iov
= {.iov_base
= (void *)n
, .iov_len
= n
->nlmsg_len
};
304 struct msghdr msg
= {
306 .msg_namelen
= sizeof(nladdr
),
312 memset(&nladdr
, 0, sizeof(nladdr
));
313 nladdr
.nl_family
= AF_NETLINK
;
314 nladdr
.nl_pid
= peer
;
315 nladdr
.nl_groups
= groups
;
317 n
->nlmsg_seq
= seq
= ++rtnl
->seq
;
320 n
->nlmsg_flags
|= NLM_F_ACK
;
322 status
= sendmsg(rtnl
->fd
, &msg
, 0);
325 perror("Cannot talk to rtnetlink");
329 memset(buf
, 0, sizeof(buf
));
334 iov
.iov_len
= sizeof(buf
);
335 status
= recvmsg(rtnl
->fd
, &msg
, 0);
338 if (errno
== EINTR
|| errno
== EAGAIN
)
340 fprintf(stderr
, "netlink receive error %s (%d)\n",
341 strerror(errno
), errno
);
345 fprintf(stderr
, "EOF on netlink\n");
348 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
349 fprintf(stderr
, "sender address length == %d\n",
353 for (h
= (struct nlmsghdr
*)iov
.iov_base
;
354 status
>= (int)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");
365 "!!!malformed message: len=%d\n", len
);
369 if ((int)nladdr
.nl_pid
!= peer
370 || h
->nlmsg_pid
!= rtnl
->local
.nl_pid
371 || h
->nlmsg_seq
!= seq
) {
373 err
= junk(&nladdr
, h
, jarg
);
377 /* Don't forget to skip that message. */
378 status
-= NLMSG_ALIGN(len
);
379 h
= (struct nlmsghdr
*)((char *)h
384 if (h
->nlmsg_type
== NLMSG_ERROR
) {
385 struct nlmsgerr
*merr
=
386 (struct nlmsgerr
*)NLMSG_DATA(h
);
387 if (l
< (int)sizeof(struct nlmsgerr
)) {
388 fprintf(stderr
, "ERROR truncated\n");
390 errno
= -merr
->error
;
397 perror("RTNETLINK answers");
402 memcpy(answer
, h
, h
->nlmsg_len
);
406 fprintf(stderr
, "Unexpected reply!!!\n");
408 status
-= NLMSG_ALIGN(len
);
409 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
411 if (msg
.msg_flags
& MSG_TRUNC
) {
412 fprintf(stderr
, "Message truncated\n");
416 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
422 int rtnl_listen(struct rtnl_handle
*rtnl
, rtnl_filter_t handler
, void *jarg
)
426 struct sockaddr_nl nladdr
;
430 .iov_len
= sizeof(buf
),
432 struct msghdr msg
= {
434 .msg_namelen
= sizeof(nladdr
),
439 memset(&nladdr
, 0, sizeof(nladdr
));
440 nladdr
.nl_family
= AF_NETLINK
;
442 nladdr
.nl_groups
= 0;
445 iov
.iov_len
= sizeof(buf
);
446 status
= recvmsg(rtnl
->fd
, &msg
, 0);
449 if (errno
== EINTR
|| errno
== EAGAIN
)
451 fprintf(stderr
, "netlink receive error %s (%d)\n",
452 strerror(errno
), errno
);
453 if (errno
== ENOBUFS
)
458 fprintf(stderr
, "EOF on netlink\n");
461 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
462 fprintf(stderr
, "Sender address length == %d\n",
466 for (h
= (struct nlmsghdr
*)buf
; status
>= (int)sizeof(*h
);) {
468 int len
= h
->nlmsg_len
;
469 int l
= len
- sizeof(*h
);
471 if (l
< 0 || len
> status
) {
472 if (msg
.msg_flags
& MSG_TRUNC
) {
473 fprintf(stderr
, "Truncated message\n");
477 "!!!malformed message: len=%d\n", len
);
481 err
= handler(&nladdr
, h
, jarg
);
485 status
-= NLMSG_ALIGN(len
);
486 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
488 if (msg
.msg_flags
& MSG_TRUNC
) {
489 fprintf(stderr
, "Message truncated\n");
493 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
499 int rtnl_from_file(FILE *rtnl
, rtnl_filter_t handler
, void *jarg
)
501 struct sockaddr_nl nladdr
;
503 struct nlmsghdr
*h
= (void *)buf
;
505 memset(&nladdr
, 0, sizeof(nladdr
));
506 nladdr
.nl_family
= AF_NETLINK
;
508 nladdr
.nl_groups
= 0;
515 arl
= fread(&buf
, 1, rl
, rtnl
);
522 fprintf(stderr
, "%s: header read failed\n",
525 fprintf(stderr
, "%s: truncated header\n",
530 l
= h
->nlmsg_len
> rl
? h
->nlmsg_len
- rl
: 0;
532 if (l
== 0 || (l
+ (size_t)NLMSG_HDRLEN
) > sizeof(buf
)) {
533 fprintf(stderr
, "%s: malformed message: len=%zu @%lu\n",
534 __func__
, (size_t)h
->nlmsg_len
, ftell(rtnl
));
539 arl
= fread(NLMSG_DATA(h
), 1, rl
, rtnl
);
543 fprintf(stderr
, "%s: msg read failed\n",
546 fprintf(stderr
, "%s: truncated message\n",
551 err
= handler(&nladdr
, h
, jarg
);
557 int addattr32(struct nlmsghdr
*n
, int maxlen
, int type
, __u32 data
)
559 int len
= RTA_LENGTH(4);
561 if ((int)(NLMSG_ALIGN(n
->nlmsg_len
) + len
) > maxlen
) {
563 "addattr32: Error! max allowed bound %d exceeded\n",
568 rta
->rta_type
= type
;
570 memcpy(RTA_DATA(rta
), &data
, 4);
571 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + len
;
575 int addattr_l(struct nlmsghdr
*n
, int maxlen
, int type
, const void *data
,
578 int len
= RTA_LENGTH(alen
);
581 if ((int)(NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
)) > maxlen
) {
583 "addattr_l ERROR: message exceeded bound of %d\n",
588 rta
->rta_type
= type
;
592 memcpy(RTA_DATA(rta
), data
, alen
);
596 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);
600 int addraw_l(struct nlmsghdr
*n
, int maxlen
, const void *data
, int len
)
602 if ((int)(NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
)) > maxlen
) {
604 "addraw_l ERROR: message exceeded bound of %d\n",
609 memcpy(NLMSG_TAIL(n
), data
, len
);
610 memset((uint8_t *)NLMSG_TAIL(n
) + len
, 0, NLMSG_ALIGN(len
) - len
);
611 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
);
615 struct rtattr
*addattr_nest(struct nlmsghdr
*n
, int maxlen
, int type
)
617 struct rtattr
*nest
= NLMSG_TAIL(n
);
619 addattr_l(n
, maxlen
, type
, NULL
, 0);
623 int addattr_nest_end(struct nlmsghdr
*n
, struct rtattr
*nest
)
625 nest
->rta_len
= (uint8_t *)NLMSG_TAIL(n
) - (uint8_t *)nest
;
629 struct rtattr
*addattr_nest_compat(struct nlmsghdr
*n
, int maxlen
, int type
,
630 const void *data
, int len
)
632 struct rtattr
*start
= NLMSG_TAIL(n
);
634 addattr_l(n
, maxlen
, type
, data
, len
);
635 addattr_nest(n
, maxlen
, type
);
639 int addattr_nest_compat_end(struct nlmsghdr
*n
, struct rtattr
*start
)
641 struct rtattr
*nest
= start
+ NLMSG_ALIGN(start
->rta_len
);
643 start
->rta_len
= (uint8_t *)NLMSG_TAIL(n
) - (uint8_t *)start
;
644 addattr_nest_end(n
, nest
);
648 int rta_addattr32(struct rtattr
*rta
, int maxlen
, int type
, __u32 data
)
650 int len
= RTA_LENGTH(4);
651 struct rtattr
*subrta
;
653 if ((int)(RTA_ALIGN(rta
->rta_len
) + len
) > maxlen
) {
655 "rta_addattr32: Error! max allowed bound %d exceeded\n",
659 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
660 subrta
->rta_type
= type
;
661 subrta
->rta_len
= len
;
662 memcpy(RTA_DATA(subrta
), &data
, 4);
663 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + len
;
667 int rta_addattr_l(struct rtattr
*rta
, int maxlen
, int type
, const void *data
,
670 struct rtattr
*subrta
;
671 int len
= RTA_LENGTH(alen
);
673 if ((int)(RTA_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
)) > maxlen
) {
675 "rta_addattr_l: Error! max allowed bound %d exceeded\n",
679 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
680 subrta
->rta_type
= type
;
681 subrta
->rta_len
= len
;
682 memcpy(RTA_DATA(subrta
), data
, alen
);
683 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
);
687 int parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
689 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
690 while (RTA_OK(rta
, len
)) {
691 if ((rta
->rta_type
<= max
) && (!tb
[rta
->rta_type
]))
692 tb
[rta
->rta_type
] = rta
;
693 rta
= RTA_NEXT(rta
, len
);
696 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
,
701 int parse_rtattr_byindex(struct rtattr
*tb
[], int max
, struct rtattr
*rta
,
706 memset(tb
, 0, sizeof(struct rtattr
*) * max
);
707 while (RTA_OK(rta
, len
)) {
708 if (rta
->rta_type
<= max
&& i
< max
)
710 rta
= RTA_NEXT(rta
, len
);
713 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
,
718 int __parse_rtattr_nested_compat(struct rtattr
*tb
[], int max
,
719 struct rtattr
*rta
, int len
)
721 if ((int)RTA_PAYLOAD(rta
) < len
)
723 if (RTA_PAYLOAD(rta
) >= RTA_ALIGN(len
) + sizeof(struct rtattr
)) {
724 rta
= (struct rtattr
*)(uint8_t *)RTA_DATA(rta
)
726 return parse_rtattr_nested(tb
, max
, rta
);
728 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
732 #endif /* __linux__ */