From 3fff3a3d13c76911c7970cb13daf87a6087d506f Mon Sep 17 00:00:00 2001 From: Juha-Matti Tilli Date: Sat, 23 Dec 2017 11:58:32 +0200 Subject: [PATCH 1/2] linux-generic: pktio: add null pktio support 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. Signed-off-by: Juha-Matti Tilli --- 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 + .../include/odp_packet_io_internal.h | 3 + .../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 diff --git a/example/generator/Makefile.am b/example/generator/Makefile.am index 7deeef4067..63f4ae6087 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 0000000000..2d741a8d1b --- /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 089d9f97d6..d09bd3cfe6 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 8585080dfa..4cfc7488c8 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -107,6 +107,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 \ @@ -163,6 +164,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 dd47b9367a..ad34e964ab 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 #include #include +#include #include #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 0000000000..849f87d67c --- /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 + +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 40d7c164b3..3bbb5cd49b 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 0000000000..5a11076cb5 --- /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 +#include +#include + +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, +}; From b97285386a8aa977bc1416d716bfdd0435a0fc34 Mon Sep 17 00:00:00 2001 From: Juha-Matti Tilli Date: Sat, 23 Dec 2017 19:58:05 +0200 Subject: [PATCH 2/2] example: l2fwd_simple: do operations to increase code coverage Do some MTU, promiscuous mode and MAC address related operations in odp_l2fwd_simple to increase code coverage. Signed-off-by: Juha-Matti Tilli --- example/l2fwd_simple/odp_l2fwd_simple.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/example/l2fwd_simple/odp_l2fwd_simple.c b/example/l2fwd_simple/odp_l2fwd_simple.c index ad86617170..c74a523a6c 100644 --- a/example/l2fwd_simple/odp_l2fwd_simple.c +++ b/example/l2fwd_simple/odp_l2fwd_simple.c @@ -145,6 +145,8 @@ int main(int argc, char **argv) odph_odpthread_params_t thr_params; int opt; int long_index; + odph_ethaddr_t correct_src; + uint32_t mtu1, mtu2; static const struct option longopts[] = { {NULL, 0, NULL, 0} }; static const char *shortopts = ""; @@ -204,6 +206,23 @@ int main(int argc, char **argv) global.if1 = create_pktio(argv[optind + 1], pool, &global.if1in, &global.if1out); + /* Do some operations to increase code coverage in tests */ + if (odp_pktio_mac_addr(global.if0, &correct_src, sizeof(correct_src)) + != sizeof(correct_src)) + printf("Warning: can't get MAC address\n"); + else if (memcmp(&correct_src, &global.src, sizeof(correct_src)) != 0) + printf("Warning: src MAC invalid\n"); + + odp_pktio_promisc_mode_set(global.if0, true); + odp_pktio_promisc_mode_set(global.if1, true); + (void)odp_pktio_promisc_mode(global.if0); + (void)odp_pktio_promisc_mode(global.if1); + + mtu1 = odp_pktin_maxlen(global.if0); + mtu2 = odp_pktout_maxlen(global.if1); + if (mtu1 && mtu2 && mtu1 > mtu2) + printf("Warning: input MTU bigger than output MTU\n"); + odp_cpumask_default_worker(&cpumask, MAX_WORKERS); memset(&thr_params, 0, sizeof(thr_params));