From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ken-ichirou MATSUZAWA Subject: [libmnl PATCH 4/9] mmap: add helper - nonmin1 Date: Sun, 08 Dec 2013 00:12:18 +0900 Message-ID: <87ob4s8zl9.wl%chamaken@gmail.com> Mime-Version: 1.0 (generated by SEMI 1.14.6 - "Maruoka") Content-Type: message/rfc822 To: Pablo Neira Ayuso , netfilter-devel@vger.kernel.org Return-path: Received: from mail-pb0-f49.google.com ([209.85.160.49]:56097 "EHLO mail-pb0-f49.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754840Ab3LGPMc (ORCPT ); Sat, 7 Dec 2013 10:12:32 -0500 Received: by mail-pb0-f49.google.com with SMTP id jt11so2695836pbb.8 for ; Sat, 07 Dec 2013 07:12:31 -0800 (PST) Sender: netfilter-devel-owner@vger.kernel.org List-ID: * mnl_ring_send Just wraping mnl_socket_sendto * mnl_ring_poll used nl-mmap branch examples * mnl_ring_poll_rxframe wait and get rx frame in single call using mnl_ring_poll below * mnl_ring_discard_frames mark unused to all frame Signed-off-by: Ken-ichirou MATSUZAWA --- include/libmnl/libmnl.h | 6 ++ src/libmnl.map | 4 ++ src/mmap.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+) diff --git a/include/libmnl/libmnl.h b/include/libmnl/libmnl.h index 11abb04..a8991ce 100644 --- a/include/libmnl/libmnl.h +++ b/include/libmnl/libmnl.h @@ -223,6 +223,12 @@ extern int mnl_ring_unmap(struct mnl_ring_socket *nlm); extern struct nl_mmap_hdr *mnl_ring_get_frame(struct mnl_ring_socket *nlm, enum mnl_ring_types type); extern int mnl_ring_advance(struct mnl_ring_socket *nlm, enum mnl_ring_types type); +/* non-minimalistic 1 [nonmin1] */ +extern ssize_t mnl_ring_send(struct mnl_ring_socket *nlm); +extern int mnl_ring_poll(const struct mnl_ring_socket *nlm, int timeout); +extern struct nl_mmap_hdr *mnl_ring_poll_rxframe(struct mnl_ring_socket *nlm); +extern int mnl_ring_discard_frames(struct mnl_ring_socket *nlm, enum mnl_ring_types type); + /* * other declarations */ diff --git a/src/libmnl.map b/src/libmnl.map index 73de08f..2a36a5c 100644 --- a/src/libmnl.map +++ b/src/libmnl.map @@ -78,4 +78,8 @@ LIBMNL_1.2 { mnl_ring_unmap; mnl_ring_get_frame; mnl_ring_advance; + mnl_ring_send; + mnl_ring_poll; + mnl_ring_poll_rxframe; + mnl_ring_discard_frames; } LIBMNL_1.1; diff --git a/src/mmap.c b/src/mmap.c index 348fa89..78fbb1f 100644 --- a/src/mmap.c +++ b/src/mmap.c @@ -225,3 +225,162 @@ EXPORT_SYMBOL(mnl_ring_advance); /** * @} */ + +/** + * mnl_ring_send - sending notification + * \param nlm ring descriptor + * + * Just wraping mnl_socket_sendto + */ +ssize_t mnl_ring_send(struct mnl_ring_socket *nlm) +{ + ssize_t ret; + int err; + socklen_t errlen = sizeof(err); + + ret = mnl_socket_sendto(nlm->sock, NULL, 0); + if (ret < 0) + return ret; + /* + * single frame with multiple message which requires ack may + * cause ENOBUFS. Should we check here? or in mnl_ring_poll() below + */ + if (getsockopt(mnl_socket_get_fd(nlm->sock), SOL_SOCKET, SO_ERROR, &err, &errlen) < 0) + return -1; + if (err) { + errno = err; + return -1; + } + + return ret; +} +EXPORT_SYMBOL(mnl_ring_send); + +/** + * mnl_ring_poll - wait for receiving + * \param nlm ring descriptor + * \timeout timeout sec + * + * This is used nl-mmap branch examples + */ +int mnl_ring_poll(const struct mnl_ring_socket *nlm, int timeout) +{ + int ret, err; + socklen_t errlen = sizeof(err); + struct pollfd pfds[1]; + + pfds[0].fd = mnl_socket_get_fd(nlm->sock); + pfds[0].events = POLLIN | POLLERR; + pfds[0].revents = 0; + + while (1) { + ret = poll(pfds, 1, timeout); + if (ret == 0) + return ret; + + if (ret < 0) { + if (errno != EINTR) + return ret; + continue; + } + + /* Check for errors */ + if (pfds[0].revents & POLLERR) { + if (getsockopt(pfds[0].fd, SOL_SOCKET, SO_ERROR, &err, &errlen) < 0) + return -1; + errno = err; + return -1; + } + + if (pfds[0].revents & POLLIN) + return ret; + } +} +EXPORT_SYMBOL(mnl_ring_poll); + +/** + * mnl_ring_poll_rxframe - wait and get rx frame in single call + * \param nlm ring descriptor + * + * Refering /Documentation/networking/netlink_mmap.txt + */ +struct nl_mmap_hdr *mnl_ring_poll_rxframe(struct mnl_ring_socket *nlm) +{ + ssize_t len; + struct nl_mmap_hdr *hdr; + unsigned int started, head; + int ret; + + hdr = mnl_ring_get_frame(nlm, MNL_RING_RX); + if (hdr == NULL) + return NULL; +poll: + while (hdr->nm_status != NL_MMAP_STATUS_VALID && hdr->nm_status != NL_MMAP_STATUS_COPY) { + ret = mnl_ring_poll(nlm, -1); + if (ret < 0) + return NULL; + hdr = mnl_ring_get_frame(nlm, MNL_RING_RX); + } + + started = nlm->rx_ring->head; + while (1) { + if (hdr->nm_status == NL_MMAP_STATUS_VALID) { + /* Regular memory mapped frame */ + + /* Release empty message immediately. May happen + * on error during message construction + */ + if (hdr->nm_len == 0) { + hdr->nm_status = NL_MMAP_STATUS_UNUSED; + head = mnl_ring_advance(nlm, MNL_RING_RX); + if (started == head) + goto poll; + continue; + } + return hdr; + } else if (hdr->nm_status == NL_MMAP_STATUS_COPY) { + /* Frame queued to socket receive queue */ + + /* dirty hack to return nl_mmap_hdr, can I? */ + len = mnl_socket_recvfrom(nlm->sock, hdr + NL_MMAP_HDRLEN, + nlm->rx_ring->frame_size - NL_MMAP_HDRLEN); + if (len <= 0) { + hdr->nm_status = NL_MMAP_STATUS_UNUSED; + goto poll; /* not cotinue? */ + } + return hdr; + } + } +} +EXPORT_SYMBOL(mnl_ring_poll_rxframe); + +/** + * mnl_ring_discard_frames - set NL_MMAP_STATUS_UNUSED all frame + * \param nlm ring descriptor + * \param type ring type either MNL_RING_RX or MNL_RING_TX + * + * This can be implemented by minimalistic functions but + * it seems tedious + */ +int mnl_ring_discard_frames(struct mnl_ring_socket *nlm, enum mnl_ring_types type) +{ + struct mnl_ring *ring; + struct nl_mmap_hdr *hdr; + unsigned int start; + + ring = get_mnl_ring(nlm, type); + if (ring == NULL) { + errno = EBADR; + return -1; + } + + start = ring->head; + do { + hdr = mnl_ring_get_frame(nlm, type); + hdr->nm_status = NL_MMAP_STATUS_UNUSED; + mnl_ring_advance(nlm, type); + } while (ring->head != start); + + return 1; +} +EXPORT_SYMBOL(mnl_ring_discard_frames); -- 1.8.4.rc3