Patchwork [libmnl,4/9] mmap: add helper - nonmin1

login
register
mail settings
Submitter Ken-ichirou MATSUZAWA
Date Dec. 7, 2013, 3:12 p.m.
Message ID <87ob4s8zl9.wl%chamaken@gmail.com>
Download mbox | patch
Permalink /patch/298691/
State Superseded
Headers show

Comments

Ken-ichirou MATSUZAWA - Dec. 7, 2013, 3:12 p.m.
* 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 <chamas@h4.dion.ne.jp>

---
 include/libmnl/libmnl.h |   6 ++
 src/libmnl.map          |   4 ++
 src/mmap.c              | 159 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 169 insertions(+)

Patch

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);