diff options
author | Juha-Matti Tilli <juha-matti.tilli@nokia.com> | 2016-02-29 11:28:52 +0200 |
---|---|---|
committer | Maxim Uvarov <maxim.uvarov@linaro.org> | 2016-03-04 13:24:49 +0300 |
commit | 6aa4e56fec65abe7b96a717b0c7f533b9975172f (patch) | |
tree | e96e7bc60d95d14114d6ee6d2edc6912fad75ed4 /example | |
parent | dcc37e3793202143a515a9ea3be69a61212967c7 (diff) |
example: l2fwd_simple: add single-threaded l2fwd example
The ODP distribution is lacking a simple example how to receive and send
packets. The l2fwd is overly complicated because it supports an arbitrary
number of interfaces, bi-directional operation and an arbitrary number of
threads.
To remedy this situation, add l2fwd_simple which is a single-threaded
unidirectional variant of l2fwd for exactly two interfaces. l2fwd_simple
can be used as an example application when learning how to use ODP. The
focus when developing l2fwd_simple was to reduce the code line count to as
small value as possible, and it turned out it requires 165 lines of code.
For unidirectional traffic in single-threaded use cases, l2fwd_simple
performs actually better than l2fwd with single thread, because
l2fwd_simple does not need to poll two interfaces in a single thread.
Signed-off-by: Juha-Matti Tilli <juha-matti.tilli@nokia.com>
Reviewed-by: Petri Savolainen <petri.savolainen@nokia.com>
Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
Diffstat (limited to 'example')
-rw-r--r-- | example/Makefile.am | 2 | ||||
-rw-r--r-- | example/l2fwd_simple/.gitignore | 1 | ||||
-rw-r--r-- | example/l2fwd_simple/Makefile.am | 10 | ||||
-rw-r--r-- | example/l2fwd_simple/odp_l2fwd_simple.c | 165 | ||||
-rw-r--r-- | example/m4/configure.m4 | 3 |
5 files changed, 179 insertions, 2 deletions
diff --git a/example/Makefile.am b/example/Makefile.am index 39d9b0198..5c97fbb64 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -1 +1 @@ -SUBDIRS = classifier generator ipsec packet time timer +SUBDIRS = classifier generator ipsec packet time timer l2fwd_simple diff --git a/example/l2fwd_simple/.gitignore b/example/l2fwd_simple/.gitignore new file mode 100644 index 000000000..132673244 --- /dev/null +++ b/example/l2fwd_simple/.gitignore @@ -0,0 +1 @@ +odp_l2fwd_simple diff --git a/example/l2fwd_simple/Makefile.am b/example/l2fwd_simple/Makefile.am new file mode 100644 index 000000000..88d2915d5 --- /dev/null +++ b/example/l2fwd_simple/Makefile.am @@ -0,0 +1,10 @@ +include $(top_srcdir)/example/Makefile.inc + +bin_PROGRAMS = odp_l2fwd_simple$(EXEEXT) +odp_l2fwd_simple_LDFLAGS = $(AM_LDFLAGS) -static +odp_l2fwd_simple_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example + +noinst_HEADERS = \ + $(top_srcdir)/example/example_debug.h + +dist_odp_l2fwd_simple_SOURCES = odp_l2fwd_simple.c diff --git a/example/l2fwd_simple/odp_l2fwd_simple.c b/example/l2fwd_simple/odp_l2fwd_simple.c new file mode 100644 index 000000000..11d342f3c --- /dev/null +++ b/example/l2fwd_simple/odp_l2fwd_simple.c @@ -0,0 +1,165 @@ +/* Copyright (c) 2016, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdlib.h> +#include <stdio.h> + +#include <odp_api.h> +#include <odp/helper/linux.h> +#include <odp/helper/eth.h> +#include <odp/helper/ip.h> + +#define POOL_NUM_PKT 8192 +#define POOL_SEG_LEN 1856 +#define MAX_PKT_BURST 32 + +struct { + odp_pktio_t if0, if1; + odp_pktin_queue_t if0in, if1in; + odp_pktout_queue_t if0out, if1out; + odph_ethaddr_t src, dst; +} global; + +static odp_pktio_t create_pktio(const char *name, odp_pool_t pool, + odp_pktin_queue_t *pktin, + odp_pktout_queue_t *pktout) +{ + odp_pktio_param_t pktio_param; + odp_pktin_queue_param_t in_queue_param; + odp_pktout_queue_param_t out_queue_param; + odp_pktio_t pktio; + + odp_pktio_param_init(&pktio_param); + + pktio = odp_pktio_open(name, pool, &pktio_param); + if (pktio == ODP_PKTIO_INVALID) { + printf("Failed to open %s\n", name); + exit(1); + } + + odp_pktin_queue_param_init(&in_queue_param); + odp_pktout_queue_param_init(&out_queue_param); + + in_queue_param.op_mode = ODP_PKTIO_OP_MT_UNSAFE; + + if (odp_pktin_queue_config(pktio, &in_queue_param)) { + printf("Failed to config input queue for %s\n", name); + exit(1); + } + + out_queue_param.op_mode = ODP_PKTIO_OP_MT_UNSAFE; + + if (odp_pktout_queue_config(pktio, &out_queue_param)) { + printf("Failed to config output queue for %s\n", name); + exit(1); + } + + if (odp_pktin_queue(pktio, pktin, 1) != 1) { + printf("pktin queue query failed for %s\n", name); + exit(1); + } + if (odp_pktout_queue(pktio, pktout, 1) != 1) { + printf("pktout queue query failed for %s\n", name); + exit(1); + } + return pktio; +} + +static void *run_worker(void *arg ODP_UNUSED) +{ + odp_packet_t pkt_tbl[MAX_PKT_BURST]; + int pkts, sent, tx_drops, i; + + if (odp_pktio_start(global.if0)) { + printf("unable to start input interface\n"); + exit(1); + } + printf("started input interface\n"); + if (odp_pktio_start(global.if1)) { + printf("unable to start output interface\n"); + exit(1); + } + printf("started output interface\n"); + printf("started all\n"); + + for (;;) { + pkts = odp_pktin_recv(global.if0in, pkt_tbl, MAX_PKT_BURST); + if (odp_unlikely(pkts <= 0)) + continue; + for (i = 0; i < pkts; i++) { + odp_packet_t pkt = pkt_tbl[i]; + odph_ethhdr_t *eth; + + if (odp_unlikely(!odp_packet_has_eth(pkt))) { + printf("warning: packet has no eth header\n"); + return NULL; + } + eth = (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, NULL); + eth->src = global.src; + eth->dst = global.dst; + } + sent = odp_pktout_send(global.if1out, pkt_tbl, pkts); + if (sent < 0) + sent = 0; + tx_drops = pkts - sent; + if (odp_unlikely(tx_drops)) + odp_packet_free_multi(&pkt_tbl[sent], tx_drops); + } + return NULL; +} + +int main(int argc, char **argv) +{ + odp_pool_t pool; + odp_pool_param_t params; + odp_cpumask_t cpumask; + odph_linux_pthread_t thd; + + if (argc != 5 || + odph_eth_addr_parse(&global.dst, argv[3]) != 0 || + odph_eth_addr_parse(&global.src, argv[4]) != 0) { + printf("Usage: odp_l2fwd_simple eth0 eth1 01:02:03:04:05:06" + " 07:08:09:0a:0b:0c\n"); + printf("Where eth0 and eth1 are the used interfaces" + " (must have 2 of them)\n"); + printf("And the hexadecimal numbers are destination MAC address" + " and source MAC address\n"); + exit(1); + } + + if (odp_init_global(NULL, NULL)) { + printf("Error: ODP global init failed.\n"); + exit(1); + } + + if (odp_init_local(ODP_THREAD_CONTROL)) { + printf("Error: ODP local init failed.\n"); + exit(1); + } + + /* Create packet pool */ + odp_pool_param_init(¶ms); + params.pkt.seg_len = POOL_SEG_LEN; + params.pkt.len = POOL_SEG_LEN; + params.pkt.num = POOL_NUM_PKT; + params.type = ODP_POOL_PACKET; + + pool = odp_pool_create("packet pool", ¶ms); + + if (pool == ODP_POOL_INVALID) { + printf("Error: packet pool create failed.\n"); + exit(1); + } + + global.if0 = create_pktio(argv[1], pool, &global.if0in, &global.if0out); + global.if1 = create_pktio(argv[2], pool, &global.if1in, &global.if1out); + + odp_cpumask_default_worker(&cpumask, 1); + odph_linux_pthread_create(&thd, &cpumask, run_worker, NULL, + ODP_THREAD_WORKER); + odph_linux_pthread_join(&thd, 1); + return 0; +} diff --git a/example/m4/configure.m4 b/example/m4/configure.m4 index bc90f820c..1710a31b8 100644 --- a/example/m4/configure.m4 +++ b/example/m4/configure.m4 @@ -4,4 +4,5 @@ AC_CONFIG_FILES([example/classifier/Makefile example/Makefile example/packet/Makefile example/time/Makefile - example/timer/Makefile]) + example/timer/Makefile + example/l2fwd_simple/Makefile]) |