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>
18 #include <net/if_arp.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
26 #include "libnetlink.h"
29 #define SOL_NETLINK 270
33 #define MIN(a, b) ((a) < (b) ? (a) : (b))
36 int rcvbuf
= 1024 * 1024;
38 void rtnl_close(struct rtnl_handle
*rth
)
46 int rtnl_open_byproto(struct rtnl_handle
*rth
, unsigned subscriptions
,
52 memset(rth
, 0, sizeof(*rth
));
54 rth
->proto
= protocol
;
55 rth
->fd
= socket(AF_NETLINK
, SOCK_RAW
| SOCK_CLOEXEC
, protocol
);
57 perror("Cannot open netlink socket");
61 if (setsockopt(rth
->fd
,SOL_SOCKET
,SO_SNDBUF
,&sndbuf
,sizeof(sndbuf
)) < 0) {
66 if (setsockopt(rth
->fd
,SOL_SOCKET
,SO_RCVBUF
,&rcvbuf
,sizeof(rcvbuf
)) < 0) {
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
)) < 0) {
76 perror("Cannot bind netlink socket");
79 addr_len
= sizeof(rth
->local
);
80 if (getsockname(rth
->fd
, (struct sockaddr
*)&rth
->local
, &addr_len
) < 0) {
81 perror("Cannot getsockname");
84 if (addr_len
!= sizeof(rth
->local
)) {
85 fprintf(stderr
, "Wrong address length %d\n", addr_len
);
88 if (rth
->local
.nl_family
!= AF_NETLINK
) {
89 fprintf(stderr
, "Wrong address family %d\n", rth
->local
.nl_family
);
92 rth
->seq
= time(NULL
);
96 int rtnl_open(struct rtnl_handle
*rth
, unsigned subscriptions
)
98 return rtnl_open_byproto(rth
, subscriptions
, NETLINK_ROUTE
);
101 int rtnl_wilddump_request(struct rtnl_handle
*rth
, int family
, int type
)
103 return rtnl_wilddump_req_filter(rth
, family
, type
, RTEXT_FILTER_VF
);
106 int rtnl_wilddump_req_filter(struct rtnl_handle
*rth
, int family
, int type
,
111 struct ifinfomsg ifm
;
112 /* attribute has to be NLMSG aligned */
113 struct rtattr ext_req
__attribute__ ((aligned(NLMSG_ALIGNTO
)));
114 __u32 ext_filter_mask
;
116 .nlh
.nlmsg_len
= sizeof(req
),
117 .nlh
.nlmsg_type
= type
,
118 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
119 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
120 .ifm
.ifi_family
= family
,
121 .ext_req
.rta_type
= IFLA_EXT_MASK
,
122 .ext_req
.rta_len
= RTA_LENGTH(sizeof(__u32
)),
123 .ext_filter_mask
= filt_mask
,
126 return send(rth
->fd
, (void*)&req
, sizeof(req
), 0);
129 int rtnl_wilddump_req_filter_fn(struct rtnl_handle
*rth
, int family
, int type
,
130 req_filter_fn_t filter_fn
)
134 struct ifinfomsg ifm
;
137 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
138 .nlh
.nlmsg_type
= type
,
139 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
140 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
141 .ifm
.ifi_family
= family
,
148 err
= filter_fn(&req
.nlh
, sizeof(req
));
152 return send(rth
->fd
, (void*)&req
, sizeof(req
), 0);
155 int rtnl_wilddump_stats_req_filter(struct rtnl_handle
*rth
, int fam
, int type
,
160 struct if_stats_msg ifsm
;
163 memset(&req
, 0, sizeof(req
));
164 req
.nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct if_stats_msg
));
165 req
.nlh
.nlmsg_type
= type
;
166 req
.nlh
.nlmsg_flags
= NLM_F_DUMP
|NLM_F_REQUEST
;
167 req
.nlh
.nlmsg_pid
= 0;
168 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
169 req
.ifsm
.family
= fam
;
170 req
.ifsm
.filter_mask
= filt_mask
;
172 return send(rth
->fd
, (void *)&req
, sizeof(req
), 0);
175 int rtnl_send(struct rtnl_handle
*rth
, const void *buf
, int len
)
177 return send(rth
->fd
, buf
, len
, 0);
180 int rtnl_send_check(struct rtnl_handle
*rth
, const void *buf
, int len
)
186 status
= send(rth
->fd
, buf
, len
, 0);
190 /* Check for immediate errors */
191 status
= recv(rth
->fd
, resp
, sizeof(resp
), MSG_DONTWAIT
|MSG_PEEK
);
198 for (h
= (struct nlmsghdr
*)resp
; NLMSG_OK(h
, status
);
199 h
= NLMSG_NEXT(h
, status
)) {
200 if (h
->nlmsg_type
== NLMSG_ERROR
) {
201 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
202 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
203 fprintf(stderr
, "ERROR truncated\n");
213 int rtnl_dump_request(struct rtnl_handle
*rth
, int type
, void *req
, int len
)
215 struct nlmsghdr nlh
= {
216 .nlmsg_len
= NLMSG_LENGTH(len
),
218 .nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
219 .nlmsg_seq
= rth
->dump
= ++rth
->seq
,
221 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
222 struct iovec iov
[2] = {
223 { .iov_base
= &nlh
, .iov_len
= sizeof(nlh
) },
224 { .iov_base
= req
, .iov_len
= len
}
226 struct msghdr msg
= {
228 .msg_namelen
= sizeof(nladdr
),
233 return sendmsg(rth
->fd
, &msg
, 0);
236 int rtnl_dump_request_n(struct rtnl_handle
*rth
, struct nlmsghdr
*n
)
238 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
240 .iov_base
= (void*) n
,
241 .iov_len
= n
->nlmsg_len
243 struct msghdr msg
= {
245 .msg_namelen
= sizeof(nladdr
),
250 n
->nlmsg_flags
= NLM_F_DUMP
|NLM_F_REQUEST
;
252 n
->nlmsg_seq
= rth
->dump
= ++rth
->seq
;
254 return sendmsg(rth
->fd
, &msg
, 0);
257 int rtnl_dump_filter_l(struct rtnl_handle
*rth
,
258 const struct rtnl_dump_filter_arg
*arg
)
260 struct sockaddr_nl nladdr
;
262 struct msghdr msg
= {
264 .msg_namelen
= sizeof(nladdr
),
274 const struct rtnl_dump_filter_arg
*a
;
278 iov
.iov_len
= sizeof(buf
);
279 status
= recvmsg(rth
->fd
, &msg
, 0);
282 if (errno
== EINTR
|| errno
== EAGAIN
)
284 fprintf(stderr
, "netlink receive error %s (%d)\n",
285 strerror(errno
), errno
);
290 fprintf(stderr
, "EOF on netlink\n");
295 fwrite(buf
, 1, NLMSG_ALIGN(status
), rth
->dump_fp
);
297 for (a
= arg
; a
->filter
; a
++) {
298 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
301 while (NLMSG_OK(h
, msglen
)) {
304 h
->nlmsg_flags
&= ~a
->nc_flags
;
306 if (nladdr
.nl_pid
!= 0 ||
307 h
->nlmsg_pid
!= rth
->local
.nl_pid
||
308 h
->nlmsg_seq
!= rth
->dump
)
311 if (h
->nlmsg_flags
& NLM_F_DUMP_INTR
)
314 if (h
->nlmsg_type
== NLMSG_DONE
) {
316 break; /* process next filter */
318 if (h
->nlmsg_type
== NLMSG_ERROR
) {
319 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
320 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
))) {
322 "ERROR truncated\n");
325 if (rth
->proto
== NETLINK_SOCK_DIAG
&&
327 errno
== EOPNOTSUPP
))
330 perror("RTNETLINK answers");
336 err
= a
->filter(&nladdr
, h
, a
->arg1
);
342 h
= NLMSG_NEXT(h
, msglen
);
349 "Dump was interrupted and may be inconsistent.\n");
353 if (msg
.msg_flags
& MSG_TRUNC
) {
354 fprintf(stderr
, "Message truncated\n");
358 fprintf(stderr
, "!!!Remnant of size %d\n", msglen
);
364 int rtnl_dump_filter_nc(struct rtnl_handle
*rth
,
365 rtnl_filter_t filter
,
366 void *arg1
, __u16 nc_flags
)
368 const struct rtnl_dump_filter_arg a
[2] = {
369 { .filter
= filter
, .arg1
= arg1
, .nc_flags
= nc_flags
, },
370 { .filter
= NULL
, .arg1
= NULL
, .nc_flags
= 0, },
373 return rtnl_dump_filter_l(rth
, a
);
376 int rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
377 struct nlmsghdr
*answer
, size_t maxlen
)
382 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
384 .iov_base
= (void*) n
,
385 .iov_len
= n
->nlmsg_len
387 struct msghdr msg
= {
389 .msg_namelen
= sizeof(nladdr
),
393 char buf
[32768] = {};
395 n
->nlmsg_seq
= seq
= ++rtnl
->seq
;
398 n
->nlmsg_flags
|= NLM_F_ACK
;
400 status
= sendmsg(rtnl
->fd
, &msg
, 0);
402 perror("Cannot talk to rtnetlink");
408 iov
.iov_len
= sizeof(buf
);
409 status
= recvmsg(rtnl
->fd
, &msg
, 0);
412 if (errno
== EINTR
|| errno
== EAGAIN
)
414 fprintf(stderr
, "netlink receive error %s (%d)\n",
415 strerror(errno
), errno
);
419 fprintf(stderr
, "EOF on netlink\n");
422 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
423 fprintf(stderr
, "sender address length == %d\n", msg
.msg_namelen
);
426 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
427 int len
= h
->nlmsg_len
;
428 int l
= len
- sizeof(*h
);
430 if (l
< 0 || len
>status
) {
431 if (msg
.msg_flags
& MSG_TRUNC
) {
432 fprintf(stderr
, "Truncated message\n");
435 fprintf(stderr
, "!!!malformed message: len=%d\n", len
);
439 if (nladdr
.nl_pid
!= 0 ||
440 h
->nlmsg_pid
!= rtnl
->local
.nl_pid
||
441 h
->nlmsg_seq
!= seq
) {
442 /* Don't forget to skip that message. */
443 status
-= NLMSG_ALIGN(len
);
444 h
= (struct nlmsghdr
*)((char*)h
+ NLMSG_ALIGN(len
));
448 if (h
->nlmsg_type
== NLMSG_ERROR
) {
449 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
450 if (l
< sizeof(struct nlmsgerr
)) {
451 fprintf(stderr
, "ERROR truncated\n");
452 } else if (!err
->error
) {
455 MIN(maxlen
, h
->nlmsg_len
));
459 if (rtnl
->proto
!= NETLINK_SOCK_DIAG
)
461 "RTNETLINK answers: %s\n",
462 strerror(-err
->error
));
469 MIN(maxlen
, h
->nlmsg_len
));
473 fprintf(stderr
, "Unexpected reply!!!\n");
475 status
-= NLMSG_ALIGN(len
);
476 h
= (struct nlmsghdr
*)((char*)h
+ NLMSG_ALIGN(len
));
479 if (msg
.msg_flags
& MSG_TRUNC
) {
480 fprintf(stderr
, "Message truncated\n");
485 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
491 int rtnl_listen_all_nsid(struct rtnl_handle
*rth
)
495 if (setsockopt(rth
->fd
, SOL_NETLINK
, NETLINK_LISTEN_ALL_NSID
, &on
,
497 perror("NETLINK_LISTEN_ALL_NSID");
500 rth
->flags
|= RTNL_HANDLE_F_LISTEN_ALL_NSID
;
504 int rtnl_listen(struct rtnl_handle
*rtnl
,
505 rtnl_listen_filter_t handler
,
510 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
512 struct msghdr msg
= {
514 .msg_namelen
= sizeof(nladdr
),
519 char cmsgbuf
[BUFSIZ
];
521 if (rtnl
->flags
& RTNL_HANDLE_F_LISTEN_ALL_NSID
) {
522 msg
.msg_control
= &cmsgbuf
;
523 msg
.msg_controllen
= sizeof(cmsgbuf
);
528 struct rtnl_ctrl_data ctrl
;
529 struct cmsghdr
*cmsg
;
531 iov
.iov_len
= sizeof(buf
);
532 status
= recvmsg(rtnl
->fd
, &msg
, 0);
535 if (errno
== EINTR
|| errno
== EAGAIN
)
537 fprintf(stderr
, "netlink receive error %s (%d)\n",
538 strerror(errno
), errno
);
539 if (errno
== ENOBUFS
)
544 fprintf(stderr
, "EOF on netlink\n");
547 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
548 fprintf(stderr
, "Sender address length == %d\n", msg
.msg_namelen
);
552 if (rtnl
->flags
& RTNL_HANDLE_F_LISTEN_ALL_NSID
) {
553 memset(&ctrl
, 0, sizeof(ctrl
));
555 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
;
556 cmsg
= CMSG_NXTHDR(&msg
, cmsg
))
557 if (cmsg
->cmsg_level
== SOL_NETLINK
&&
558 cmsg
->cmsg_type
== NETLINK_LISTEN_ALL_NSID
&&
559 cmsg
->cmsg_len
== CMSG_LEN(sizeof(int))) {
560 int *data
= (int *)CMSG_DATA(cmsg
);
566 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
568 int len
= h
->nlmsg_len
;
569 int l
= len
- sizeof(*h
);
571 if (l
<0 || len
>status
) {
572 if (msg
.msg_flags
& MSG_TRUNC
) {
573 fprintf(stderr
, "Truncated message\n");
576 fprintf(stderr
, "!!!malformed message: len=%d\n", len
);
580 err
= handler(&nladdr
, &ctrl
, h
, jarg
);
584 status
-= NLMSG_ALIGN(len
);
585 h
= (struct nlmsghdr
*)((char*)h
+ NLMSG_ALIGN(len
));
587 if (msg
.msg_flags
& MSG_TRUNC
) {
588 fprintf(stderr
, "Message truncated\n");
592 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
598 int rtnl_from_file(FILE *rtnl
, rtnl_listen_filter_t handler
,
602 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
604 struct nlmsghdr
*h
= (void*)buf
;
610 status
= fread(&buf
, 1, sizeof(*h
), rtnl
);
615 perror("rtnl_from_file: fread");
622 l
= len
- sizeof(*h
);
624 if (l
<0 || len
>sizeof(buf
)) {
625 fprintf(stderr
, "!!!malformed message: len=%d @%lu\n",
630 status
= fread(NLMSG_DATA(h
), 1, NLMSG_ALIGN(l
), rtnl
);
633 perror("rtnl_from_file: fread");
637 fprintf(stderr
, "rtnl-from_file: truncated message\n");
641 err
= handler(&nladdr
, NULL
, h
, jarg
);
647 int addattr(struct nlmsghdr
*n
, int maxlen
, int type
)
649 return addattr_l(n
, maxlen
, type
, NULL
, 0);
652 int addattr8(struct nlmsghdr
*n
, int maxlen
, int type
, __u8 data
)
654 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u8
));
657 int addattr16(struct nlmsghdr
*n
, int maxlen
, int type
, __u16 data
)
659 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u16
));
662 int addattr32(struct nlmsghdr
*n
, int maxlen
, int type
, __u32 data
)
664 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u32
));
667 int addattr64(struct nlmsghdr
*n
, int maxlen
, int type
, __u64 data
)
669 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u64
));
672 int addattrstrz(struct nlmsghdr
*n
, int maxlen
, int type
, const char *str
)
674 return addattr_l(n
, maxlen
, type
, str
, strlen(str
)+1);
677 int addattr_l(struct nlmsghdr
*n
, int maxlen
, int type
, const void *data
,
680 int len
= RTA_LENGTH(alen
);
683 if (NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
) > maxlen
) {
684 fprintf(stderr
, "addattr_l ERROR: message exceeded bound of %d\n",maxlen
);
688 rta
->rta_type
= type
;
690 memcpy(RTA_DATA(rta
), data
, alen
);
691 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);
695 int addraw_l(struct nlmsghdr
*n
, int maxlen
, const void *data
, int len
)
697 if (NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
) > maxlen
) {
698 fprintf(stderr
, "addraw_l ERROR: message exceeded bound of %d\n",maxlen
);
702 memcpy(NLMSG_TAIL(n
), data
, len
);
703 memset((void *) NLMSG_TAIL(n
) + len
, 0, NLMSG_ALIGN(len
) - len
);
704 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
);
708 struct rtattr
*addattr_nest(struct nlmsghdr
*n
, int maxlen
, int type
)
710 struct rtattr
*nest
= NLMSG_TAIL(n
);
712 addattr_l(n
, maxlen
, type
, NULL
, 0);
716 int addattr_nest_end(struct nlmsghdr
*n
, struct rtattr
*nest
)
718 nest
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)nest
;
722 struct rtattr
*addattr_nest_compat(struct nlmsghdr
*n
, int maxlen
, int type
,
723 const void *data
, int len
)
725 struct rtattr
*start
= NLMSG_TAIL(n
);
727 addattr_l(n
, maxlen
, type
, data
, len
);
728 addattr_nest(n
, maxlen
, type
);
732 int addattr_nest_compat_end(struct nlmsghdr
*n
, struct rtattr
*start
)
734 struct rtattr
*nest
= (void *)start
+ NLMSG_ALIGN(start
->rta_len
);
736 start
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)start
;
737 addattr_nest_end(n
, nest
);
741 int rta_addattr32(struct rtattr
*rta
, int maxlen
, int type
, __u32 data
)
743 int len
= RTA_LENGTH(4);
744 struct rtattr
*subrta
;
746 if (RTA_ALIGN(rta
->rta_len
) + len
> maxlen
) {
747 fprintf(stderr
,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen
);
750 subrta
= (struct rtattr
*)(((char*)rta
) + RTA_ALIGN(rta
->rta_len
));
751 subrta
->rta_type
= type
;
752 subrta
->rta_len
= len
;
753 memcpy(RTA_DATA(subrta
), &data
, 4);
754 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + len
;
758 int rta_addattr_l(struct rtattr
*rta
, int maxlen
, int type
,
759 const void *data
, int alen
)
761 struct rtattr
*subrta
;
762 int len
= RTA_LENGTH(alen
);
764 if (RTA_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
) > maxlen
) {
765 fprintf(stderr
,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen
);
768 subrta
= (struct rtattr
*)(((char*)rta
) + RTA_ALIGN(rta
->rta_len
));
769 subrta
->rta_type
= type
;
770 subrta
->rta_len
= len
;
771 memcpy(RTA_DATA(subrta
), data
, alen
);
772 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
);
776 int rta_addattr8(struct rtattr
*rta
, int maxlen
, int type
, __u8 data
)
778 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u8
));
781 int rta_addattr16(struct rtattr
*rta
, int maxlen
, int type
, __u16 data
)
783 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u16
));
786 int rta_addattr64(struct rtattr
*rta
, int maxlen
, int type
, __u64 data
)
788 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u64
));
791 struct rtattr
*rta_nest(struct rtattr
*rta
, int maxlen
, int type
)
793 struct rtattr
*nest
= RTA_TAIL(rta
);
795 rta_addattr_l(rta
, maxlen
, type
, NULL
, 0);
800 int rta_nest_end(struct rtattr
*rta
, struct rtattr
*nest
)
802 nest
->rta_len
= (void *)RTA_TAIL(rta
) - (void *)nest
;
807 int parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
809 return parse_rtattr_flags(tb
, max
, rta
, len
, 0);
812 int parse_rtattr_flags(struct rtattr
*tb
[], int max
, struct rtattr
*rta
,
813 int len
, unsigned short flags
)
817 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
818 while (RTA_OK(rta
, len
)) {
819 type
= rta
->rta_type
& ~flags
;
820 if ((type
<= max
) && (!tb
[type
]))
822 rta
= RTA_NEXT(rta
,len
);
825 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
, rta
->rta_len
);
829 int parse_rtattr_byindex(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
833 memset(tb
, 0, sizeof(struct rtattr
*) * max
);
834 while (RTA_OK(rta
, len
)) {
835 if (rta
->rta_type
<= max
&& i
< max
)
837 rta
= RTA_NEXT(rta
,len
);
840 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
, rta
->rta_len
);
844 struct rtattr
*parse_rtattr_one(int type
, struct rtattr
*rta
, int len
)
846 while (RTA_OK(rta
, len
)) {
847 if (rta
->rta_type
== type
)
849 rta
= RTA_NEXT(rta
, len
);
852 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
, rta
->rta_len
);
856 int __parse_rtattr_nested_compat(struct rtattr
*tb
[], int max
, struct rtattr
*rta
,
859 if (RTA_PAYLOAD(rta
) < len
)
861 if (RTA_PAYLOAD(rta
) >= RTA_ALIGN(len
) + sizeof(struct rtattr
)) {
862 rta
= RTA_DATA(rta
) + RTA_ALIGN(len
);
863 return parse_rtattr_nested(tb
, max
, rta
);
865 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));