diff options
author | Patrick McHardy <kaber@trash.net> | 2012-08-20 13:21:51 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-08-20 13:23:20 +0200 |
commit | 65ec7cfa590700fbab9657727a9b19e8d58158fc (patch) | |
tree | dc5dfeed9b8b07ee22ccbc63dfc7d3cdc26d42a7 | |
parent | 1385fc1bdc6ae8ac3ccb206af2d9dee4a70ba9c8 (diff) | |
download | libmnl-nl-mmap.tar.gz |
examples: rtnl_route_dump: add memory mapped netlink supportnl-mmap
Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r-- | examples/rtnl/rtnl-route-dump.c | 67 |
1 files changed, 61 insertions, 6 deletions
diff --git a/examples/rtnl/rtnl-route-dump.c b/examples/rtnl/rtnl-route-dump.c index a798515..2d8e19b 100644 --- a/examples/rtnl/rtnl-route-dump.c +++ b/examples/rtnl/rtnl-route-dump.c @@ -4,6 +4,8 @@ #include <string.h> #include <unistd.h> #include <time.h> +#include <poll.h> +#include <errno.h> #include <arpa/inet.h> #include <libmnl/libmnl.h> @@ -285,12 +287,34 @@ static int data_cb(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } +static int mnl_socket_poll(struct mnl_socket *nl) +{ + struct pollfd pfds[1]; + + while (1) { + pfds[0].fd = mnl_socket_get_fd(nl); + pfds[0].events = POLLIN | POLLERR; + pfds[0].revents = 0; + + if (poll(pfds, 1, -1) < 0 && errno != -EINTR) + return -1; + + if (pfds[0].revents & POLLIN) + return 0; + if (pfds[0].revents & POLLERR) + return -1; + } +} + int main(int argc, char *argv[]) { struct mnl_socket *nl; char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nl_mmap_hdr *hdr; struct nlmsghdr *nlh; struct rtmsg *rtm; + ssize_t len; + void *ptr; int ret; unsigned int seq, portid; @@ -316,6 +340,11 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } + if (mnl_socket_set_ring(nl, 0, 0) < 0) { + perror("mnl_socket_set_ring"); + exit(EXIT_FAILURE); + } + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { perror("mnl_socket_bind"); exit(EXIT_FAILURE); @@ -327,13 +356,39 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); - while (ret > 0) { - ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL); - if (ret <= MNL_CB_STOP) - break; - ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (1) { + ret = mnl_socket_poll(nl); + if (ret < 0) { + perror("mnl_socket_poll"); + exit(EXIT_FAILURE); + } + + while (1) { + hdr = mnl_socket_get_frame(nl, MNL_RING_RX); + + if (hdr->nm_status == NL_MMAP_STATUS_VALID) { + ptr = (void *)hdr + NL_MMAP_HDRLEN; + len = hdr->nm_len; + if (len == 0) + goto next; + } else if (hdr->nm_status == NL_MMAP_STATUS_COPY) { + len = recv(mnl_socket_get_fd(nl), + buf, sizeof(buf), MSG_DONTWAIT); + if (len <= 0) + break; + ptr = buf; + } else + break; + + ret = mnl_cb_run(ptr, len, seq, portid, data_cb, NULL); + if (ret <= MNL_CB_STOP) + goto end; +next: + hdr->nm_status = NL_MMAP_STATUS_UNUSED; + mnl_socket_advance_ring(nl, MNL_RING_RX); + } } +end: if (ret == -1) { perror("error"); exit(EXIT_FAILURE); |