]>
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
)) < 0) {
60 if (setsockopt(rth
->fd
,SOL_SOCKET
,SO_RCVBUF
,&rcvbuf
,sizeof(rcvbuf
)) < 0) {
65 memset(&rth
->local
, 0, sizeof(rth
->local
));
66 rth
->local
.nl_family
= AF_NETLINK
;
67 rth
->local
.nl_groups
= subscriptions
;
69 if (bind(rth
->fd
, (struct sockaddr
*)&rth
->local
, sizeof(rth
->local
)) < 0) {
70 perror("Cannot bind netlink socket");
73 addr_len
= sizeof(rth
->local
);
74 if (getsockname(rth
->fd
, (struct sockaddr
*)&rth
->local
, &addr_len
) < 0) {
75 perror("Cannot getsockname");
78 if (addr_len
!= sizeof(rth
->local
)) {
79 fprintf(stderr
, "Wrong address length %d\n", addr_len
);
82 if (rth
->local
.nl_family
!= AF_NETLINK
) {
83 fprintf(stderr
, "Wrong address family %d\n", rth
->local
.nl_family
);
86 rth
->seq
= time(NULL
);
90 int rtnl_open(struct rtnl_handle
*rth
, unsigned subscriptions
)
92 return rtnl_open_byproto(rth
, subscriptions
, NETLINK_ROUTE
);
95 int rtnl_wilddump_request(struct rtnl_handle
*rth
, int family
, int type
)
102 memset(&req
, 0, sizeof(req
));
103 req
.nlh
.nlmsg_len
= sizeof(req
);
104 req
.nlh
.nlmsg_type
= type
;
105 req
.nlh
.nlmsg_flags
= NLM_F_ROOT
|NLM_F_MATCH
|NLM_F_REQUEST
;
106 req
.nlh
.nlmsg_pid
= 0;
107 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
108 req
.g
.rtgen_family
= family
;
110 return send(rth
->fd
, (void*)&req
, sizeof(req
), 0);
113 int rtnl_send(struct rtnl_handle
*rth
, const char *buf
, int len
)
115 return send(rth
->fd
, buf
, len
, 0);
118 int rtnl_send_check(struct rtnl_handle
*rth
, const char *buf
, int len
)
124 status
= send(rth
->fd
, buf
, len
, 0);
128 /* Check for immediate errors */
129 status
= recv(rth
->fd
, resp
, sizeof(resp
), MSG_DONTWAIT
|MSG_PEEK
);
136 for (h
= (struct nlmsghdr
*)resp
; NLMSG_OK(h
, (uint32_t)status
);
137 h
= NLMSG_NEXT(h
, status
)) {
138 if (h
->nlmsg_type
== NLMSG_ERROR
) {
139 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
140 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
141 fprintf(stderr
, "ERROR truncated\n");
151 int rtnl_dump_request(struct rtnl_handle
*rth
, int type
, void *req
, int len
)
154 struct sockaddr_nl nladdr
;
155 struct iovec iov
[2] = {
156 { .iov_base
= &nlh
, .iov_len
= sizeof(nlh
) },
157 { .iov_base
= req
, .iov_len
= len
}
159 struct msghdr msg
= {
161 .msg_namelen
= sizeof(nladdr
),
166 memset(&nladdr
, 0, sizeof(nladdr
));
167 nladdr
.nl_family
= AF_NETLINK
;
169 nlh
.nlmsg_len
= NLMSG_LENGTH(len
);
170 nlh
.nlmsg_type
= type
;
171 nlh
.nlmsg_flags
= NLM_F_ROOT
|NLM_F_MATCH
|NLM_F_REQUEST
;
173 nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
175 return sendmsg(rth
->fd
, &msg
, 0);
178 int rtnl_dump_filter_l(struct rtnl_handle
*rth
,
179 const struct rtnl_dump_filter_arg
*arg
)
181 struct sockaddr_nl nladdr
;
183 struct msghdr msg
= {
185 .msg_namelen
= sizeof(nladdr
),
194 const struct rtnl_dump_filter_arg
*a
;
198 iov
.iov_len
= sizeof(buf
);
199 status
= recvmsg(rth
->fd
, &msg
, 0);
202 if (errno
== EINTR
|| errno
== EAGAIN
)
204 fprintf(stderr
, "netlink receive error %s (%d)\n",
205 strerror(errno
), errno
);
210 fprintf(stderr
, "EOF on netlink\n");
214 for (a
= arg
; a
->filter
; a
++) {
215 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
218 while (NLMSG_OK(h
, (uint32_t)msglen
)) {
221 if (nladdr
.nl_pid
!= 0 ||
222 h
->nlmsg_pid
!= rth
->local
.nl_pid
||
223 h
->nlmsg_seq
!= rth
->dump
) {
225 err
= a
->junk(&nladdr
, h
,
233 if (h
->nlmsg_type
== NLMSG_DONE
) {
235 break; /* process next filter */
237 if (h
->nlmsg_type
== NLMSG_ERROR
) {
238 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
239 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
))) {
241 "ERROR truncated\n");
244 perror("RTNETLINK answers");
248 err
= a
->filter(&nladdr
, h
, a
->arg1
);
253 h
= NLMSG_NEXT(h
, msglen
);
260 if (msg
.msg_flags
& MSG_TRUNC
) {
261 fprintf(stderr
, "Message truncated\n");
265 fprintf(stderr
, "!!!Remnant of size %d\n", msglen
);
271 int rtnl_dump_filter(struct rtnl_handle
*rth
,
272 rtnl_filter_t filter
,
277 const struct rtnl_dump_filter_arg a
[2] = {
278 { .filter
= filter
, .arg1
= arg1
, .junk
= junk
, .arg2
= arg2
},
279 { .filter
= NULL
, .arg1
= NULL
, .junk
= NULL
, .arg2
= NULL
}
282 return rtnl_dump_filter_l(rth
, a
);
285 int rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
, pid_t peer
,
286 unsigned groups
, struct nlmsghdr
*answer
,
293 struct sockaddr_nl nladdr
;
295 .iov_base
= (void*) n
,
296 .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", msg
.msg_namelen
);
346 for (h
= (struct nlmsghdr
*)buf
; status
>= (int)sizeof(*h
); ) {
348 int len
= h
->nlmsg_len
;
349 int l
= len
- sizeof(*h
);
351 if (l
<0 || len
>status
) {
352 if (msg
.msg_flags
& MSG_TRUNC
) {
353 fprintf(stderr
, "Truncated message\n");
356 fprintf(stderr
, "!!!malformed message: len=%d\n", len
);
360 if ((int)nladdr
.nl_pid
!= peer
||
361 h
->nlmsg_pid
!= rtnl
->local
.nl_pid
||
362 h
->nlmsg_seq
!= seq
) {
364 err
= junk(&nladdr
, h
, jarg
);
368 /* Don't forget to skip that message. */
369 status
-= NLMSG_ALIGN(len
);
370 h
= (struct nlmsghdr
*)((char*)h
+ NLMSG_ALIGN(len
));
374 if (h
->nlmsg_type
== NLMSG_ERROR
) {
375 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
376 if (l
< (int)sizeof(struct nlmsgerr
)) {
377 fprintf(stderr
, "ERROR truncated\n");
382 memcpy(answer
, h
, h
->nlmsg_len
);
385 perror("RTNETLINK answers");
390 memcpy(answer
, h
, h
->nlmsg_len
);
394 fprintf(stderr
, "Unexpected reply!!!\n");
396 status
-= NLMSG_ALIGN(len
);
397 h
= (struct nlmsghdr
*)((char*)h
+ NLMSG_ALIGN(len
));
399 if (msg
.msg_flags
& MSG_TRUNC
) {
400 fprintf(stderr
, "Message truncated\n");
404 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
410 int rtnl_listen(struct rtnl_handle
*rtnl
,
411 rtnl_filter_t handler
,
416 struct sockaddr_nl nladdr
;
418 struct msghdr msg
= {
420 .msg_namelen
= sizeof(nladdr
),
426 memset(&nladdr
, 0, sizeof(nladdr
));
427 nladdr
.nl_family
= AF_NETLINK
;
429 nladdr
.nl_groups
= 0;
433 iov
.iov_len
= sizeof(buf
);
434 status
= recvmsg(rtnl
->fd
, &msg
, 0);
437 if (errno
== EINTR
|| errno
== EAGAIN
)
439 fprintf(stderr
, "netlink receive error %s (%d)\n",
440 strerror(errno
), errno
);
441 if (errno
== ENOBUFS
)
446 fprintf(stderr
, "EOF on netlink\n");
449 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
450 fprintf(stderr
, "Sender address length == %d\n", msg
.msg_namelen
);
453 for (h
=(struct nlmsghdr
*)buf
; status
>= (int)sizeof(*h
); ) {
455 int len
= h
->nlmsg_len
;
456 int l
= len
- sizeof(*h
);
458 if (l
<0 || len
>status
) {
459 if (msg
.msg_flags
& MSG_TRUNC
) {
460 fprintf(stderr
, "Truncated message\n");
463 fprintf(stderr
, "!!!malformed message: len=%d\n", len
);
467 err
= handler(&nladdr
, h
, jarg
);
471 status
-= NLMSG_ALIGN(len
);
472 h
= (struct nlmsghdr
*)((char*)h
+ NLMSG_ALIGN(len
));
474 if (msg
.msg_flags
& MSG_TRUNC
) {
475 fprintf(stderr
, "Message truncated\n");
479 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
485 int rtnl_from_file(FILE *rtnl
, rtnl_filter_t handler
,
489 struct sockaddr_nl nladdr
;
491 struct nlmsghdr
*h
= (void*)buf
;
493 memset(&nladdr
, 0, sizeof(nladdr
));
494 nladdr
.nl_family
= AF_NETLINK
;
496 nladdr
.nl_groups
= 0;
502 status
= fread(&buf
, 1, sizeof(*h
), rtnl
);
507 perror("rtnl_from_file: fread");
514 l
= len
- sizeof(*h
);
516 if (l
<0 || len
>(int)sizeof(buf
)) {
517 fprintf(stderr
, "!!!malformed message: len=%d @%lu\n",
522 status
= fread(NLMSG_DATA(h
), 1, NLMSG_ALIGN(l
), rtnl
);
525 perror("rtnl_from_file: fread");
529 fprintf(stderr
, "rtnl-from_file: truncated message\n");
533 err
= handler(&nladdr
, h
, jarg
);
539 int addattr32(struct nlmsghdr
*n
, int maxlen
, int type
, __u32 data
)
541 int len
= RTA_LENGTH(4);
543 if ((int)(NLMSG_ALIGN(n
->nlmsg_len
) + len
) > maxlen
) {
544 fprintf(stderr
,"addattr32: Error! max allowed bound %d exceeded\n",maxlen
);
548 rta
->rta_type
= type
;
550 memcpy(RTA_DATA(rta
), &data
, 4);
551 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + len
;
555 int addattr_l(struct nlmsghdr
*n
, int maxlen
, int type
, const void *data
,
558 int len
= RTA_LENGTH(alen
);
561 if ((int)(NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
)) > maxlen
) {
562 fprintf(stderr
, "addattr_l ERROR: message exceeded bound of %d\n",maxlen
);
566 rta
->rta_type
= type
;
570 memcpy(RTA_DATA(rta
), data
, alen
);
574 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);
578 int addraw_l(struct nlmsghdr
*n
, int maxlen
, const void *data
, int len
)
580 if ((int)(NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
)) > maxlen
) {
581 fprintf(stderr
, "addraw_l ERROR: message exceeded bound of %d\n",maxlen
);
585 memcpy(NLMSG_TAIL(n
), data
, len
);
586 memset((uint8_t *) NLMSG_TAIL(n
) + len
, 0, NLMSG_ALIGN(len
) - len
);
587 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
);
591 struct rtattr
*addattr_nest(struct nlmsghdr
*n
, int maxlen
, int type
)
593 struct rtattr
*nest
= NLMSG_TAIL(n
);
595 addattr_l(n
, maxlen
, type
, NULL
, 0);
599 int addattr_nest_end(struct nlmsghdr
*n
, struct rtattr
*nest
)
601 nest
->rta_len
= (uint8_t *)NLMSG_TAIL(n
) - (uint8_t *)nest
;
605 struct rtattr
*addattr_nest_compat(struct nlmsghdr
*n
, int maxlen
, int type
,
606 const void *data
, int len
)
608 struct rtattr
*start
= NLMSG_TAIL(n
);
610 addattr_l(n
, maxlen
, type
, data
, len
);
611 addattr_nest(n
, maxlen
, type
);
615 int addattr_nest_compat_end(struct nlmsghdr
*n
, struct rtattr
*start
)
617 struct rtattr
*nest
= start
+ NLMSG_ALIGN(start
->rta_len
);
619 start
->rta_len
= (uint8_t *)NLMSG_TAIL(n
) - (uint8_t *)start
;
620 addattr_nest_end(n
, nest
);
624 int rta_addattr32(struct rtattr
*rta
, int maxlen
, int type
, __u32 data
)
626 int len
= RTA_LENGTH(4);
627 struct rtattr
*subrta
;
629 if ((int)(RTA_ALIGN(rta
->rta_len
) + len
) > maxlen
) {
630 fprintf(stderr
,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen
);
633 subrta
= (struct rtattr
*)(((char*)rta
) + RTA_ALIGN(rta
->rta_len
));
634 subrta
->rta_type
= type
;
635 subrta
->rta_len
= len
;
636 memcpy(RTA_DATA(subrta
), &data
, 4);
637 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + len
;
641 int rta_addattr_l(struct rtattr
*rta
, int maxlen
, int type
,
642 const void *data
, int alen
)
644 struct rtattr
*subrta
;
645 int len
= RTA_LENGTH(alen
);
647 if ((int)(RTA_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
)) > maxlen
) {
648 fprintf(stderr
,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen
);
651 subrta
= (struct rtattr
*)(((char*)rta
) + RTA_ALIGN(rta
->rta_len
));
652 subrta
->rta_type
= type
;
653 subrta
->rta_len
= len
;
654 memcpy(RTA_DATA(subrta
), data
, alen
);
655 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
);
659 int parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
661 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
662 while (RTA_OK(rta
, len
)) {
663 if ((rta
->rta_type
<= max
) && (!tb
[rta
->rta_type
]))
664 tb
[rta
->rta_type
] = rta
;
665 rta
= RTA_NEXT(rta
,len
);
668 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
, rta
->rta_len
);
672 int parse_rtattr_byindex(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
676 memset(tb
, 0, sizeof(struct rtattr
*) * max
);
677 while (RTA_OK(rta
, len
)) {
678 if (rta
->rta_type
<= max
&& i
< max
)
680 rta
= RTA_NEXT(rta
,len
);
683 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
, rta
->rta_len
);
687 int __parse_rtattr_nested_compat(struct rtattr
*tb
[], int max
, struct rtattr
*rta
,
690 if ((int)RTA_PAYLOAD(rta
) < len
)
692 if (RTA_PAYLOAD(rta
) >= RTA_ALIGN(len
) + sizeof(struct rtattr
)) {
693 rta
= (struct rtattr
*)(uint8_t *)RTA_DATA(rta
)+RTA_ALIGN(len
);
694 return parse_rtattr_nested(tb
, max
, rta
);
696 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
700 #endif /* __linux__ */