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>
19 #include <net/if_arp.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
27 #include "libnetlink.h"
30 #define SOL_NETLINK 270
34 #define MIN(a, b) ((a) < (b) ? (a) : (b))
37 int rcvbuf
= 1024 * 1024;
39 void rtnl_close(struct rtnl_handle
*rth
)
47 int rtnl_open_byproto(struct rtnl_handle
*rth
, unsigned int subscriptions
,
53 memset(rth
, 0, sizeof(*rth
));
55 rth
->proto
= protocol
;
56 rth
->fd
= socket(AF_NETLINK
, SOCK_RAW
| SOCK_CLOEXEC
, protocol
);
58 perror("Cannot open netlink socket");
62 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_SNDBUF
,
63 &sndbuf
, sizeof(sndbuf
)) < 0) {
68 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_RCVBUF
,
69 &rcvbuf
, sizeof(rcvbuf
)) < 0) {
74 memset(&rth
->local
, 0, sizeof(rth
->local
));
75 rth
->local
.nl_family
= AF_NETLINK
;
76 rth
->local
.nl_groups
= subscriptions
;
78 if (bind(rth
->fd
, (struct sockaddr
*)&rth
->local
,
79 sizeof(rth
->local
)) < 0) {
80 perror("Cannot bind netlink socket");
83 addr_len
= sizeof(rth
->local
);
84 if (getsockname(rth
->fd
, (struct sockaddr
*)&rth
->local
,
86 perror("Cannot getsockname");
89 if (addr_len
!= sizeof(rth
->local
)) {
90 fprintf(stderr
, "Wrong address length %d\n", addr_len
);
93 if (rth
->local
.nl_family
!= AF_NETLINK
) {
94 fprintf(stderr
, "Wrong address family %d\n",
95 rth
->local
.nl_family
);
98 rth
->seq
= time(NULL
);
102 int rtnl_open(struct rtnl_handle
*rth
, unsigned int subscriptions
)
104 return rtnl_open_byproto(rth
, subscriptions
, NETLINK_ROUTE
);
107 int rtnl_wilddump_request(struct rtnl_handle
*rth
, int family
, int type
)
109 return rtnl_wilddump_req_filter(rth
, family
, type
, RTEXT_FILTER_VF
);
112 int rtnl_wilddump_req_filter(struct rtnl_handle
*rth
, int family
, int type
,
117 struct ifinfomsg ifm
;
118 /* attribute has to be NLMSG aligned */
119 struct rtattr ext_req
__attribute__ ((aligned(NLMSG_ALIGNTO
)));
120 __u32 ext_filter_mask
;
122 .nlh
.nlmsg_len
= sizeof(req
),
123 .nlh
.nlmsg_type
= type
,
124 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
125 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
126 .ifm
.ifi_family
= family
,
127 .ext_req
.rta_type
= IFLA_EXT_MASK
,
128 .ext_req
.rta_len
= RTA_LENGTH(sizeof(__u32
)),
129 .ext_filter_mask
= filt_mask
,
132 return send(rth
->fd
, &req
, sizeof(req
), 0);
135 int rtnl_wilddump_req_filter_fn(struct rtnl_handle
*rth
, int family
, int type
,
136 req_filter_fn_t filter_fn
)
140 struct ifinfomsg ifm
;
143 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
144 .nlh
.nlmsg_type
= type
,
145 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
146 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
147 .ifm
.ifi_family
= family
,
154 err
= filter_fn(&req
.nlh
, sizeof(req
));
158 return send(rth
->fd
, &req
, req
.nlh
.nlmsg_len
, 0);
161 int rtnl_wilddump_stats_req_filter(struct rtnl_handle
*rth
, int fam
, int type
,
166 struct if_stats_msg ifsm
;
169 memset(&req
, 0, sizeof(req
));
170 req
.nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct if_stats_msg
));
171 req
.nlh
.nlmsg_type
= type
;
172 req
.nlh
.nlmsg_flags
= NLM_F_DUMP
|NLM_F_REQUEST
;
173 req
.nlh
.nlmsg_pid
= 0;
174 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
175 req
.ifsm
.family
= fam
;
176 req
.ifsm
.filter_mask
= filt_mask
;
178 return send(rth
->fd
, &req
, sizeof(req
), 0);
181 int rtnl_send(struct rtnl_handle
*rth
, const void *buf
, int len
)
183 return send(rth
->fd
, buf
, len
, 0);
186 int rtnl_send_check(struct rtnl_handle
*rth
, const void *buf
, int len
)
192 status
= send(rth
->fd
, buf
, len
, 0);
196 /* Check for immediate errors */
197 status
= recv(rth
->fd
, resp
, sizeof(resp
), MSG_DONTWAIT
|MSG_PEEK
);
204 for (h
= (struct nlmsghdr
*)resp
; NLMSG_OK(h
, status
);
205 h
= NLMSG_NEXT(h
, status
)) {
206 if (h
->nlmsg_type
== NLMSG_ERROR
) {
207 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
209 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
210 fprintf(stderr
, "ERROR truncated\n");
220 int rtnl_dump_request(struct rtnl_handle
*rth
, int type
, void *req
, int len
)
222 struct nlmsghdr nlh
= {
223 .nlmsg_len
= NLMSG_LENGTH(len
),
225 .nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
226 .nlmsg_seq
= rth
->dump
= ++rth
->seq
,
228 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
229 struct iovec iov
[2] = {
230 { .iov_base
= &nlh
, .iov_len
= sizeof(nlh
) },
231 { .iov_base
= req
, .iov_len
= len
}
233 struct msghdr msg
= {
235 .msg_namelen
= sizeof(nladdr
),
240 return sendmsg(rth
->fd
, &msg
, 0);
243 int rtnl_dump_request_n(struct rtnl_handle
*rth
, struct nlmsghdr
*n
)
245 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
248 .iov_len
= n
->nlmsg_len
250 struct msghdr msg
= {
252 .msg_namelen
= sizeof(nladdr
),
257 n
->nlmsg_flags
= NLM_F_DUMP
|NLM_F_REQUEST
;
259 n
->nlmsg_seq
= rth
->dump
= ++rth
->seq
;
261 return sendmsg(rth
->fd
, &msg
, 0);
264 static int rtnl_dump_done(const struct rtnl_handle
*rth
,
267 int len
= *(int *)NLMSG_DATA(h
);
269 if (rth
->proto
== NETLINK_SOCK_DIAG
) {
270 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(int))) {
271 fprintf(stderr
, "DONE truncated\n");
278 if (errno
== ENOENT
|| errno
== EOPNOTSUPP
)
280 perror("RTNETLINK answers");
287 static void rtnl_dump_error(const struct rtnl_handle
*rth
,
291 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
))) {
292 fprintf(stderr
, "ERROR truncated\n");
294 const struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
297 if (rth
->proto
== NETLINK_SOCK_DIAG
&&
299 errno
== EOPNOTSUPP
))
302 perror("RTNETLINK answers");
306 int rtnl_dump_filter_l(struct rtnl_handle
*rth
,
307 const struct rtnl_dump_filter_arg
*arg
)
309 struct sockaddr_nl nladdr
;
311 struct msghdr msg
= {
313 .msg_namelen
= sizeof(nladdr
),
323 const struct rtnl_dump_filter_arg
*a
;
327 iov
.iov_len
= sizeof(buf
);
328 status
= recvmsg(rth
->fd
, &msg
, 0);
331 if (errno
== EINTR
|| errno
== EAGAIN
)
333 fprintf(stderr
, "netlink receive error %s (%d)\n",
334 strerror(errno
), errno
);
339 fprintf(stderr
, "EOF on netlink\n");
344 fwrite(buf
, 1, NLMSG_ALIGN(status
), rth
->dump_fp
);
346 for (a
= arg
; a
->filter
; a
++) {
347 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
351 while (NLMSG_OK(h
, msglen
)) {
354 h
->nlmsg_flags
&= ~a
->nc_flags
;
356 if (nladdr
.nl_pid
!= 0 ||
357 h
->nlmsg_pid
!= rth
->local
.nl_pid
||
358 h
->nlmsg_seq
!= rth
->dump
)
361 if (h
->nlmsg_flags
& NLM_F_DUMP_INTR
)
364 if (h
->nlmsg_type
== NLMSG_DONE
) {
365 err
= rtnl_dump_done(rth
, h
);
370 break; /* process next filter */
373 if (h
->nlmsg_type
== NLMSG_ERROR
) {
374 rtnl_dump_error(rth
, h
);
379 err
= a
->filter(&nladdr
, h
, a
->arg1
);
385 h
= NLMSG_NEXT(h
, msglen
);
392 "Dump was interrupted and may be inconsistent.\n");
396 if (msg
.msg_flags
& MSG_TRUNC
) {
397 fprintf(stderr
, "Message truncated\n");
401 fprintf(stderr
, "!!!Remnant of size %d\n", msglen
);
407 int rtnl_dump_filter_nc(struct rtnl_handle
*rth
,
408 rtnl_filter_t filter
,
409 void *arg1
, __u16 nc_flags
)
411 const struct rtnl_dump_filter_arg a
[2] = {
412 { .filter
= filter
, .arg1
= arg1
, .nc_flags
= nc_flags
, },
413 { .filter
= NULL
, .arg1
= NULL
, .nc_flags
= 0, },
416 return rtnl_dump_filter_l(rth
, a
);
419 static int __rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
420 struct nlmsghdr
*answer
, size_t maxlen
,
426 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
429 .iov_len
= n
->nlmsg_len
431 struct msghdr msg
= {
433 .msg_namelen
= sizeof(nladdr
),
437 char buf
[32768] = {};
439 n
->nlmsg_seq
= seq
= ++rtnl
->seq
;
442 n
->nlmsg_flags
|= NLM_F_ACK
;
444 status
= sendmsg(rtnl
->fd
, &msg
, 0);
446 perror("Cannot talk to rtnetlink");
452 iov
.iov_len
= sizeof(buf
);
453 status
= recvmsg(rtnl
->fd
, &msg
, 0);
456 if (errno
== EINTR
|| errno
== EAGAIN
)
458 fprintf(stderr
, "netlink receive error %s (%d)\n",
459 strerror(errno
), errno
);
463 fprintf(stderr
, "EOF on netlink\n");
466 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
468 "sender address length == %d\n",
472 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
473 int len
= h
->nlmsg_len
;
474 int l
= len
- sizeof(*h
);
476 if (l
< 0 || len
> status
) {
477 if (msg
.msg_flags
& MSG_TRUNC
) {
478 fprintf(stderr
, "Truncated message\n");
482 "!!!malformed message: len=%d\n",
487 if (nladdr
.nl_pid
!= 0 ||
488 h
->nlmsg_pid
!= rtnl
->local
.nl_pid
||
489 h
->nlmsg_seq
!= seq
) {
490 /* Don't forget to skip that message. */
491 status
-= NLMSG_ALIGN(len
);
492 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
496 if (h
->nlmsg_type
== NLMSG_ERROR
) {
497 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
499 if (l
< sizeof(struct nlmsgerr
)) {
500 fprintf(stderr
, "ERROR truncated\n");
501 } else if (!err
->error
) {
504 MIN(maxlen
, h
->nlmsg_len
));
508 if (rtnl
->proto
!= NETLINK_SOCK_DIAG
&& show_rtnl_err
)
510 "RTNETLINK answers: %s\n",
511 strerror(-err
->error
));
518 MIN(maxlen
, h
->nlmsg_len
));
522 fprintf(stderr
, "Unexpected reply!!!\n");
524 status
-= NLMSG_ALIGN(len
);
525 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
528 if (msg
.msg_flags
& MSG_TRUNC
) {
529 fprintf(stderr
, "Message truncated\n");
534 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
540 int rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
541 struct nlmsghdr
*answer
, size_t maxlen
)
543 return __rtnl_talk(rtnl
, n
, answer
, maxlen
, true);
546 int rtnl_talk_suppress_rtnl_errmsg(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
547 struct nlmsghdr
*answer
, size_t maxlen
)
549 return __rtnl_talk(rtnl
, n
, answer
, maxlen
, false);
552 int rtnl_listen_all_nsid(struct rtnl_handle
*rth
)
556 if (setsockopt(rth
->fd
, SOL_NETLINK
, NETLINK_LISTEN_ALL_NSID
, &on
,
558 perror("NETLINK_LISTEN_ALL_NSID");
561 rth
->flags
|= RTNL_HANDLE_F_LISTEN_ALL_NSID
;
565 int rtnl_listen(struct rtnl_handle
*rtnl
,
566 rtnl_listen_filter_t handler
,
571 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
573 struct msghdr msg
= {
575 .msg_namelen
= sizeof(nladdr
),
580 char cmsgbuf
[BUFSIZ
];
582 if (rtnl
->flags
& RTNL_HANDLE_F_LISTEN_ALL_NSID
) {
583 msg
.msg_control
= &cmsgbuf
;
584 msg
.msg_controllen
= sizeof(cmsgbuf
);
589 struct rtnl_ctrl_data ctrl
;
590 struct cmsghdr
*cmsg
;
592 iov
.iov_len
= sizeof(buf
);
593 status
= recvmsg(rtnl
->fd
, &msg
, 0);
596 if (errno
== EINTR
|| errno
== EAGAIN
)
598 fprintf(stderr
, "netlink receive error %s (%d)\n",
599 strerror(errno
), errno
);
600 if (errno
== ENOBUFS
)
605 fprintf(stderr
, "EOF on netlink\n");
608 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
610 "Sender address length == %d\n",
615 if (rtnl
->flags
& RTNL_HANDLE_F_LISTEN_ALL_NSID
) {
616 memset(&ctrl
, 0, sizeof(ctrl
));
618 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
;
619 cmsg
= CMSG_NXTHDR(&msg
, cmsg
))
620 if (cmsg
->cmsg_level
== SOL_NETLINK
&&
621 cmsg
->cmsg_type
== NETLINK_LISTEN_ALL_NSID
&&
622 cmsg
->cmsg_len
== CMSG_LEN(sizeof(int))) {
623 int *data
= (int *)CMSG_DATA(cmsg
);
629 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
631 int len
= h
->nlmsg_len
;
632 int l
= len
- sizeof(*h
);
634 if (l
< 0 || len
> status
) {
635 if (msg
.msg_flags
& MSG_TRUNC
) {
636 fprintf(stderr
, "Truncated message\n");
640 "!!!malformed message: len=%d\n",
645 err
= handler(&nladdr
, &ctrl
, h
, jarg
);
649 status
-= NLMSG_ALIGN(len
);
650 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
652 if (msg
.msg_flags
& MSG_TRUNC
) {
653 fprintf(stderr
, "Message truncated\n");
657 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
663 int rtnl_from_file(FILE *rtnl
, rtnl_listen_filter_t handler
,
667 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
669 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
675 status
= fread(&buf
, 1, sizeof(*h
), rtnl
);
680 perror("rtnl_from_file: fread");
687 l
= len
- sizeof(*h
);
689 if (l
< 0 || len
> sizeof(buf
)) {
690 fprintf(stderr
, "!!!malformed message: len=%d @%lu\n",
695 status
= fread(NLMSG_DATA(h
), 1, NLMSG_ALIGN(l
), rtnl
);
698 perror("rtnl_from_file: fread");
702 fprintf(stderr
, "rtnl-from_file: truncated message\n");
706 err
= handler(&nladdr
, NULL
, h
, jarg
);
712 int addattr(struct nlmsghdr
*n
, int maxlen
, int type
)
714 return addattr_l(n
, maxlen
, type
, NULL
, 0);
717 int addattr8(struct nlmsghdr
*n
, int maxlen
, int type
, __u8 data
)
719 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u8
));
722 int addattr16(struct nlmsghdr
*n
, int maxlen
, int type
, __u16 data
)
724 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u16
));
727 int addattr32(struct nlmsghdr
*n
, int maxlen
, int type
, __u32 data
)
729 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u32
));
732 int addattr64(struct nlmsghdr
*n
, int maxlen
, int type
, __u64 data
)
734 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u64
));
737 int addattrstrz(struct nlmsghdr
*n
, int maxlen
, int type
, const char *str
)
739 return addattr_l(n
, maxlen
, type
, str
, strlen(str
)+1);
742 int addattr_l(struct nlmsghdr
*n
, int maxlen
, int type
, const void *data
,
745 int len
= RTA_LENGTH(alen
);
748 if (NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
) > maxlen
) {
750 "addattr_l ERROR: message exceeded bound of %d\n",
755 rta
->rta_type
= type
;
757 memcpy(RTA_DATA(rta
), data
, alen
);
758 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);
762 int addraw_l(struct nlmsghdr
*n
, int maxlen
, const void *data
, int len
)
764 if (NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
) > maxlen
) {
766 "addraw_l ERROR: message exceeded bound of %d\n",
771 memcpy(NLMSG_TAIL(n
), data
, len
);
772 memset((void *) NLMSG_TAIL(n
) + len
, 0, NLMSG_ALIGN(len
) - len
);
773 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
);
777 struct rtattr
*addattr_nest(struct nlmsghdr
*n
, int maxlen
, int type
)
779 struct rtattr
*nest
= NLMSG_TAIL(n
);
781 addattr_l(n
, maxlen
, type
, NULL
, 0);
785 int addattr_nest_end(struct nlmsghdr
*n
, struct rtattr
*nest
)
787 nest
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)nest
;
791 struct rtattr
*addattr_nest_compat(struct nlmsghdr
*n
, int maxlen
, int type
,
792 const void *data
, int len
)
794 struct rtattr
*start
= NLMSG_TAIL(n
);
796 addattr_l(n
, maxlen
, type
, data
, len
);
797 addattr_nest(n
, maxlen
, type
);
801 int addattr_nest_compat_end(struct nlmsghdr
*n
, struct rtattr
*start
)
803 struct rtattr
*nest
= (void *)start
+ NLMSG_ALIGN(start
->rta_len
);
805 start
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)start
;
806 addattr_nest_end(n
, nest
);
810 int rta_addattr32(struct rtattr
*rta
, int maxlen
, int type
, __u32 data
)
812 int len
= RTA_LENGTH(4);
813 struct rtattr
*subrta
;
815 if (RTA_ALIGN(rta
->rta_len
) + len
> maxlen
) {
817 "rta_addattr32: Error! max allowed bound %d exceeded\n",
821 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
822 subrta
->rta_type
= type
;
823 subrta
->rta_len
= len
;
824 memcpy(RTA_DATA(subrta
), &data
, 4);
825 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + len
;
829 int rta_addattr_l(struct rtattr
*rta
, int maxlen
, int type
,
830 const void *data
, int alen
)
832 struct rtattr
*subrta
;
833 int len
= RTA_LENGTH(alen
);
835 if (RTA_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
) > maxlen
) {
837 "rta_addattr_l: Error! max allowed bound %d exceeded\n",
841 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
842 subrta
->rta_type
= type
;
843 subrta
->rta_len
= len
;
844 memcpy(RTA_DATA(subrta
), data
, alen
);
845 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
);
849 int rta_addattr8(struct rtattr
*rta
, int maxlen
, int type
, __u8 data
)
851 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u8
));
854 int rta_addattr16(struct rtattr
*rta
, int maxlen
, int type
, __u16 data
)
856 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u16
));
859 int rta_addattr64(struct rtattr
*rta
, int maxlen
, int type
, __u64 data
)
861 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u64
));
864 struct rtattr
*rta_nest(struct rtattr
*rta
, int maxlen
, int type
)
866 struct rtattr
*nest
= RTA_TAIL(rta
);
868 rta_addattr_l(rta
, maxlen
, type
, NULL
, 0);
873 int rta_nest_end(struct rtattr
*rta
, struct rtattr
*nest
)
875 nest
->rta_len
= (void *)RTA_TAIL(rta
) - (void *)nest
;
880 int parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
882 return parse_rtattr_flags(tb
, max
, rta
, len
, 0);
885 int parse_rtattr_flags(struct rtattr
*tb
[], int max
, struct rtattr
*rta
,
886 int len
, unsigned short flags
)
890 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
891 while (RTA_OK(rta
, len
)) {
892 type
= rta
->rta_type
& ~flags
;
893 if ((type
<= max
) && (!tb
[type
]))
895 rta
= RTA_NEXT(rta
, len
);
898 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n",
903 int parse_rtattr_byindex(struct rtattr
*tb
[], int max
,
904 struct rtattr
*rta
, int len
)
908 memset(tb
, 0, sizeof(struct rtattr
*) * max
);
909 while (RTA_OK(rta
, len
)) {
910 if (rta
->rta_type
<= max
&& i
< max
)
912 rta
= RTA_NEXT(rta
, len
);
915 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n",
920 struct rtattr
*parse_rtattr_one(int type
, struct rtattr
*rta
, int len
)
922 while (RTA_OK(rta
, len
)) {
923 if (rta
->rta_type
== type
)
925 rta
= RTA_NEXT(rta
, len
);
929 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n",
934 int __parse_rtattr_nested_compat(struct rtattr
*tb
[], int max
,
938 if (RTA_PAYLOAD(rta
) < len
)
940 if (RTA_PAYLOAD(rta
) >= RTA_ALIGN(len
) + sizeof(struct rtattr
)) {
941 rta
= RTA_DATA(rta
) + RTA_ALIGN(len
);
942 return parse_rtattr_nested(tb
, max
, rta
);
944 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));