[v12,4/5] linux-generic: pktio: add null pktio support

Message ID 1515596425-24694-5-git-send-email-odpbot@yandex.ru
State New
Headers show
Series
  • linux-generic: pktio: add null pktio support
Related show

Commit Message

Github ODP bot Jan. 10, 2018, 3 p.m.
From: Juha-Matti Tilli <juha-matti.tilli@iki.fi>


Sometimes, you may wish to run an application by using a dummy interface
that never receives any packets and that discards transmitted packets.
This is possible with non-looping pcap pktio with no input and output
pcaps. So, the pktio would be just "pcap:". However, you cannot have two
pktios named "pcap:" because there is code to check if the pktio is
already opened. Also, the pcap pktio requires that ODP is compiled with
the pcap library, which it may not be. Also, pcap is always
single-queue and therefore not suitable for modern multi-queue
applications.

Also, recently a patch was provided to ODP to allow interruptible sleep
when receiving packets. This, however, does not work with mixed pcap and
socket/netmap pktio types.

To fix these issues, a new "null" pktio is introduced. It is used by
specifying the interface name to be "null:0", "null:1", or similar. All
packets sent to the null pktio are discarded and no packets are
received. The null pktio fully supports the interruptible sleep
infrastructure, meaning applications can have 0% idle CPU load when one
interface is a null interface and another interface is socket or netmap.

Note this patch depends on the genuinesleep patch. So, do not merge this
patch yet! The patch can, however, be reviewed.

Signed-off-by: Juha-Matti Tilli <juha-matti.tilli@iki.fi>

---
/** Email created from pull request 365 (jmtilli:nullpktio)
 ** https://github.com/Linaro/odp/pull/365
 ** Patch: https://github.com/Linaro/odp/pull/365.patch
 ** Base sha: 49ebafae0edebbc750742d8874ad0a7588286dea
 ** Merge commit sha: b7570030cbadfa847595dcf4adec3ef33cea31c5
 **/
 example/generator/Makefile.am                      |   5 +
 example/generator/generator_run.sh                 |  17 ++
 example/l2fwd_simple/l2fwd_simple_run.sh           |  13 ++
 platform/linux-generic/Makefile.am                 |   2 +
 .../linux-generic/include/odp_packet_io_internal.h |   3 +
 platform/linux-generic/include/odp_packet_null.h   |  16 ++
 platform/linux-generic/pktio/io_ops.c              |   1 +
 platform/linux-generic/pktio/null.c                | 175 +++++++++++++++++++++
 8 files changed, 232 insertions(+)
 create mode 100755 example/generator/generator_run.sh
 create mode 100644 platform/linux-generic/include/odp_packet_null.h
 create mode 100644 platform/linux-generic/pktio/null.c

Patch

diff --git a/example/generator/Makefile.am b/example/generator/Makefile.am
index 7deeef406..63f4ae608 100644
--- a/example/generator/Makefile.am
+++ b/example/generator/Makefile.am
@@ -3,3 +3,8 @@  include $(top_srcdir)/example/Makefile.inc
 bin_PROGRAMS = odp_generator
 
 odp_generator_SOURCES = odp_generator.c
+
+if test_example
+TESTS = generator_run.sh
+endif
+EXTRA_DIST = generator_run.sh
diff --git a/example/generator/generator_run.sh b/example/generator/generator_run.sh
new file mode 100755
index 000000000..2d741a8d1
--- /dev/null
+++ b/example/generator/generator_run.sh
@@ -0,0 +1,17 @@ 
+#!/bin/bash
+#
+# Copyright (c) 2018, Linaro Limited
+# All rights reserved.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+#
+
+./odp_generator${EXEEXT} -w 1 -n 1 -I null:0 -m u
+STATUS=$?
+
+if [ "$STATUS" -ne 0 ]; then
+  echo "Error: status was: $STATUS, expected 0"
+  exit 1
+fi
+
+exit 0
diff --git a/example/l2fwd_simple/l2fwd_simple_run.sh b/example/l2fwd_simple/l2fwd_simple_run.sh
index 089d9f97d..d09bd3cfe 100755
--- a/example/l2fwd_simple/l2fwd_simple_run.sh
+++ b/example/l2fwd_simple/l2fwd_simple_run.sh
@@ -29,4 +29,17 @@  fi
 
 rm -f pcapout.pcap
 
+./odp_l2fwd_simple${EXEEXT} null:0 null:1 \
+	02:00:00:00:00:01 02:00:00:00:00:02 &
+
+sleep 1
+kill -s SIGINT $!
+wait $!
+STATUS=$?
+
+if [ "$STATUS" -ne 255 ]; then
+  echo "Error: status was: $STATUS, expected 255"
+  exit 1
+fi
+
 exit 0
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am
index 7e40448bd..85993737a 100644
--- a/platform/linux-generic/Makefile.am
+++ b/platform/linux-generic/Makefile.am
@@ -154,6 +154,7 @@  noinst_HEADERS = \
 		  include/odp_packet_dpdk.h \
 		  include/odp_packet_socket.h \
 		  include/odp_packet_tap.h \
+		  include/odp_packet_null.h \
 		  include/odp_pkt_queue_internal.h \
 		  include/odp_pool_internal.h \
 		  include/odp_posix_extensions.h \
@@ -211,6 +212,7 @@  __LIB__libodp_linux_la_SOURCES = \
 			   pktio/pktio_common.c \
 			   pktio/loop.c \
 			   pktio/netmap.c \
+			   pktio/null.c \
 			   pktio/dpdk.c \
 			   pktio/socket.c \
 			   pktio/socket_mmap.c \
diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h
index dd47b9367..ad34e964a 100644
--- a/platform/linux-generic/include/odp_packet_io_internal.h
+++ b/platform/linux-generic/include/odp_packet_io_internal.h
@@ -34,6 +34,7 @@  extern "C" {
 #include <odp_packet_socket.h>
 #include <odp_packet_netmap.h>
 #include <odp_packet_tap.h>
+#include <odp_packet_null.h>
 #include <odp_packet_dpdk.h>
 
 #define PKTIO_NAME_LEN 256
@@ -129,6 +130,7 @@  struct pktio_entry {
 #endif
 		pkt_tap_t pkt_tap;		/**< using TAP for IO */
 		_ipc_pktio_t ipc;		/**< IPC pktio data */
+		pkt_null_t pkt_null;		/**< using null for IO */
 	};
 	enum {
 		/* Not allocated */
@@ -271,6 +273,7 @@  extern const pktio_if_ops_t loopback_pktio_ops;
 extern const pktio_if_ops_t pcap_pktio_ops;
 #endif
 extern const pktio_if_ops_t tap_pktio_ops;
+extern const pktio_if_ops_t null_pktio_ops;
 extern const pktio_if_ops_t ipc_pktio_ops;
 extern const pktio_if_ops_t * const pktio_if_ops[];
 
diff --git a/platform/linux-generic/include/odp_packet_null.h b/platform/linux-generic/include/odp_packet_null.h
new file mode 100644
index 000000000..849f87d67
--- /dev/null
+++ b/platform/linux-generic/include/odp_packet_null.h
@@ -0,0 +1,16 @@ 
+/* Copyright (c) 2018, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#ifndef ODP_PACKET_NULL_H_
+#define ODP_PACKET_NULL_H_
+
+#include <odp/api/pool.h>
+
+typedef struct {
+	int promisc;			/**< whether promiscuous mode is on */
+} pkt_null_t;
+
+#endif
diff --git a/platform/linux-generic/pktio/io_ops.c b/platform/linux-generic/pktio/io_ops.c
index 40d7c164b..3bbb5cd49 100644
--- a/platform/linux-generic/pktio/io_ops.c
+++ b/platform/linux-generic/pktio/io_ops.c
@@ -25,6 +25,7 @@  const pktio_if_ops_t * const pktio_if_ops[]  = {
 #endif
 	&ipc_pktio_ops,
 	&tap_pktio_ops,
+	&null_pktio_ops,
 	&sock_mmap_pktio_ops,
 	&sock_mmsg_pktio_ops,
 	NULL
diff --git a/platform/linux-generic/pktio/null.c b/platform/linux-generic/pktio/null.c
new file mode 100644
index 000000000..5a11076cb
--- /dev/null
+++ b/platform/linux-generic/pktio/null.c
@@ -0,0 +1,175 @@ 
+/* Copyright (c) 2018, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include "config.h"
+
+#include <odp_api.h>
+#include <odp_packet_io_internal.h>
+#include <odp_packet_null.h>
+
+static int null_close(pktio_entry_t *pktio_entry ODP_UNUSED)
+{
+	return 0;
+}
+
+static int null_open(odp_pktio_t id ODP_UNUSED,
+		     pktio_entry_t *pktio_entry,
+		     const char *devname, odp_pool_t pool ODP_UNUSED)
+{
+	if (strncmp(devname, "null:", 5) != 0)
+		return -1;
+	pktio_entry->s.pkt_null.promisc = 0;
+	return 0;
+}
+
+static int null_recv(pktio_entry_t *pktio_entry ODP_UNUSED,
+		     int index ODP_UNUSED, odp_packet_t pkt_table[] ODP_UNUSED,
+		     int len ODP_UNUSED)
+{
+	return 0;
+}
+
+static int null_fd_set(pktio_entry_t *pktio_entry ODP_UNUSED,
+		       int index ODP_UNUSED, fd_set *readfds ODP_UNUSED)
+{
+	return 0;
+}
+
+static int null_recv_tmo(pktio_entry_t *pktio_entry ODP_UNUSED,
+			 int index ODP_UNUSED,
+			 odp_packet_t pkt_table[] ODP_UNUSED,
+			 int num ODP_UNUSED, uint64_t usecs)
+{
+	struct timeval timeout;
+	int maxfd = -1;
+	fd_set readfds;
+
+	timeout.tv_sec = usecs / (1000 * 1000);
+	timeout.tv_usec = usecs - timeout.tv_sec * (1000ULL * 1000ULL);
+	FD_ZERO(&readfds);
+
+	select(maxfd + 1, &readfds, NULL, NULL,
+	       usecs == ODP_PKTIN_WAIT ? NULL : &timeout);
+
+	return 0;
+}
+
+static int null_recv_mq_tmo(pktio_entry_t *pktio_entry[] ODP_UNUSED,
+			    int index[] ODP_UNUSED, int num_q ODP_UNUSED,
+			    odp_packet_t pkt_table[] ODP_UNUSED,
+			    int num ODP_UNUSED, unsigned *from ODP_UNUSED,
+			    uint64_t usecs)
+{
+	struct timeval timeout;
+	int maxfd = -1;
+	fd_set readfds;
+
+	timeout.tv_sec = usecs / (1000 * 1000);
+	timeout.tv_usec = usecs - timeout.tv_sec * (1000ULL * 1000ULL);
+
+	FD_ZERO(&readfds);
+
+	select(maxfd + 1, &readfds, NULL, NULL,
+	       usecs == ODP_PKTIN_WAIT ? NULL : &timeout);
+
+	return 0;
+}
+
+static int null_send(pktio_entry_t *pktio_entry ODP_UNUSED,
+		     int index ODP_UNUSED, const odp_packet_t pkt_table[],
+		     int num)
+{
+	odp_packet_free_multi(pkt_table, num);
+
+	return num;
+}
+
+#define PKTIO_NULL_MTU (64 * 1024)
+
+static uint32_t null_mtu_get(pktio_entry_t *pktio_entry ODP_UNUSED)
+{
+	return PKTIO_NULL_MTU;
+}
+
+static const char null_mac[] = {0x02, 0xe9, 0x34, 0x80, 0x73, 0x05};
+
+static int null_mac_addr_get(pktio_entry_t *pktio_entry ODP_UNUSED,
+			     void *mac_addr)
+{
+	memcpy(mac_addr, null_mac, ETH_ALEN);
+	return ETH_ALEN;
+}
+
+static int null_promisc_mode_set(pktio_entry_t *pktio_entry, odp_bool_t enable)
+{
+	pktio_entry->s.pkt_null.promisc = !!enable;
+	return 0;
+}
+
+static int null_promisc_mode_get(pktio_entry_t *pktio_entry)
+{
+	return pktio_entry->s.pkt_null.promisc;
+}
+
+static int null_capability(pktio_entry_t *pktio_entry ODP_UNUSED,
+			   odp_pktio_capability_t *capa)
+{
+	memset(capa, 0, sizeof(odp_pktio_capability_t));
+
+	capa->max_input_queues  = PKTIO_MAX_QUEUES;
+	capa->max_output_queues = PKTIO_MAX_QUEUES;
+	capa->set_op.op.promisc_mode = 1;
+
+	odp_pktio_config_init(&capa->config);
+	capa->config.pktin.bit.ts_all = 1;
+	capa->config.pktin.bit.ts_ptp = 1;
+	return 0;
+}
+
+static int null_inqueues_config(pktio_entry_t *pktio_entry ODP_UNUSED,
+				const odp_pktin_queue_param_t *p ODP_UNUSED)
+{
+	return 0;
+}
+
+static int null_outqueues_config(pktio_entry_t *pktio_entry ODP_UNUSED,
+				 const odp_pktout_queue_param_t *p ODP_UNUSED)
+{
+	return 0;
+}
+
+static int null_init_global(void)
+{
+	ODP_PRINT("PKTIO: initialized null interface.\n");
+	return 0;
+}
+
+const pktio_if_ops_t null_pktio_ops = {
+	.name = "null",
+	.print = NULL,
+	.init_global = null_init_global,
+	.init_local = NULL,
+	.term = NULL,
+	.open = null_open,
+	.close = null_close,
+	.start = NULL,
+	.stop = NULL,
+	.recv = null_recv,
+	.recv_tmo = null_recv_tmo,
+	.recv_mq_tmo = null_recv_mq_tmo,
+	.fd_set = null_fd_set,
+	.send = null_send,
+	.mtu_get = null_mtu_get,
+	.promisc_mode_set = null_promisc_mode_set,
+	.promisc_mode_get = null_promisc_mode_get,
+	.mac_get = null_mac_addr_get,
+	.capability = null_capability,
+	.pktin_ts_res = NULL,
+	.pktin_ts_from_ns = NULL,
+	.config = NULL,
+	.input_queues_config = null_inqueues_config,
+	.output_queues_config = null_outqueues_config,
+};