On Thu, May 21, 2015 at 6:32 PM, Maxim Uvarov <[email protected]> wrote:
> Simple example app creates one packet i/o to external interface
> and one ipc pktio to other process. Then transfer packet from
> external interface to other process and back thought ipc queue.
>
> Signed-off-by: Maxim Uvarov <[email protected]>
> ---
> configure.ac | 1 +
> example/Makefile.am | 2 +-
> example/ipc/.gitignore | 1 +
> example/ipc/Makefile.am | 7 +
> example/ipc/odp_ipc.c | 445
> ++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 455 insertions(+), 1 deletion(-)
> create mode 100644 example/ipc/.gitignore
> create mode 100644 example/ipc/Makefile.am
> create mode 100644 example/ipc/odp_ipc.c
>
> diff --git a/configure.ac b/configure.ac
> index d20bad2..1ceb922 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -274,6 +274,7 @@ AC_CONFIG_FILES([Makefile
> example/Makefile
> example/classifier/Makefile
> example/generator/Makefile
> + example/ipc/Makefile
> example/ipsec/Makefile
> example/packet/Makefile
> example/timer/Makefile
> diff --git a/example/Makefile.am b/example/Makefile.am
> index 353f397..506963f 100644
> --- a/example/Makefile.am
> +++ b/example/Makefile.am
> @@ -1 +1 @@
> -SUBDIRS = classifier generator ipsec packet timer
> +SUBDIRS = classifier generator ipc ipsec packet timer
> diff --git a/example/ipc/.gitignore b/example/ipc/.gitignore
> new file mode 100644
> index 0000000..963d99d
> --- /dev/null
> +++ b/example/ipc/.gitignore
> @@ -0,0 +1 @@
> +odp_ipc
> diff --git a/example/ipc/Makefile.am b/example/ipc/Makefile.am
> new file mode 100644
> index 0000000..3da9549
> --- /dev/null
> +++ b/example/ipc/Makefile.am
> @@ -0,0 +1,7 @@
> +include $(top_srcdir)/example/Makefile.inc
> +
> +bin_PROGRAMS = odp_ipc
> +odp_ipc_LDFLAGS = $(AM_LDFLAGS) -static
> +odp_ipc_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example
> +
> +dist_odp_ipc_SOURCES = odp_ipc.c
> diff --git a/example/ipc/odp_ipc.c b/example/ipc/odp_ipc.c
> new file mode 100644
> index 0000000..1120467
> --- /dev/null
> +++ b/example/ipc/odp_ipc.c
> @@ -0,0 +1,445 @@
> +/* Copyright (c) 2015, Linaro Limited
> + * All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-3-Clause
> + */
> +
> +/**
> + * @file
> + *
> + * @example odp_ipc.c ODP IPC test application.
> + */
> +
> +#include <stdlib.h>
> +#include <string.h>
> +#include <getopt.h>
> +#include <unistd.h>
> +
> +#include <example_debug.h>
> +
> +#include <odp.h>
> +#include <odp/helper/linux.h>
> +
> +/** @def SHM_PKT_POOL_SIZE
> + * @brief Size of the shared memory block
> + */
> +#define SHM_PKT_POOL_SIZE (512 * 2048)
> +
> +/** @def SHM_PKT_POOL_BUF_SIZE
> + * @brief Buffer size of the packet pool buffer
> + */
> +#define SHM_PKT_POOL_BUF_SIZE 1856
> +
> +/** @def MAX_PKT_BURST
> + * @brief Maximum number of packet bursts
> + */
> +#define MAX_PKT_BURST 16
> +
> +/** Get rid of path in filename - only for unix-type paths using '/' */
> +#define NO_PATH(file_name) (strrchr((file_name), '/') ? \
> + strrchr((file_name), '/') + 1 : (file_name))
> +
> +/** Application argument */
> +static char *pktio_name;
> +
> +/* helper funcs */
> +static void parse_args(int argc, char *argv[]);
> +static void print_info(char *progname);
> +static void usage(char *progname);
> +
> +static void busy_sleep(int sec)
> +{
> + uint64_t start_cycle;
> + uint64_t cycle;
> + uint64_t diff;
> + uint64_t wait;
> +
> + wait = odp_time_ns_to_cycles(sec * ODP_TIME_SEC);
> +
> + start_cycle = odp_time_cycles();
> + while (1) {
> + cycle = odp_time_cycles();
> + diff = odp_time_diff_cycles(start_cycle, cycle);
> + if (wait < diff)
> + break;
> + }
> +}
> +
> +/**
> + * Create a pktio handle.
> + *
> + * @param dev Name of device to open
> + * @param pool Pool to associate with device for packet RX/TX
> + *
> + * @return The handle of the created pktio object.
> + * @retval ODP_PKTIO_INVALID if the create fails.
> + */
> +static odp_pktio_t create_pktio(const char *dev, odp_pool_t pool)
> +{
> + odp_pktio_t pktio;
> + odp_pktio_t ipc_pktio;
> +
> + /* Open a packet IO instance */
> + pktio = odp_pktio_open(dev, pool);
> + if (pktio == ODP_PKTIO_INVALID)
> + EXAMPLE_ABORT("Error: pktio create failed for %s\n", dev);
> +
> + printf("pid: %d, create IPC pktio\n", getpid());
> + ipc_pktio = odp_pktio_open("ipc_pktio", pool);
> + if (ipc_pktio == ODP_PKTIO_INVALID)
> + EXAMPLE_ABORT("Error: ipc pktio create failed.\n");
> +
> + return pktio;
> +}
> +
> +/**
> + * Packet IO loopback worker thread using bursts from/to IO resources
> + *
> + * @param arg thread arguments of type 'thread_args_t *'
> + */
> +static void *pktio_run_loop(odp_pool_t pool)
> +{
> + int thr;
> + odp_pktio_t pktio;
> + int pkts;
> + odp_packet_t pkt_tbl[MAX_PKT_BURST];
> + odp_pktio_t ipc_pktio;
> +
> + thr = odp_thread_id();
> +
> + pktio = odp_pktio_lookup(pktio_name);
> + if (pktio == ODP_PKTIO_INVALID) {
> + EXAMPLE_ERR(" [%02i] Error: lookup of pktio %s failed\n",
> + thr, pktio_name);
> + return NULL;
> + }
> +
> + printf(" [%02i] looked up pktio:%02" PRIu64 ", burst mode\n",
> + thr, odp_pktio_to_u64(pktio));
> +
> + ipc_pktio = odp_pktio_lookup("ipc_pktio");
> + if (pktio == ODP_PKTIO_INVALID) {
> + EXAMPLE_ERR(" [%02i] Error: lookup of pktio %s failed\n",
> + thr, "ipc_pktio");
> + return NULL;
> + }
> + printf(" [%02i] looked up ipc_pktio:%02" PRIu64 ", burst mode\n",
> + thr, odp_pktio_to_u64(ipc_pktio));
> +
> + /* packets loop */
> + for (;;) {
> + int i;
> + time_t tm = time(NULL);
> + char *tm_str = ctime(&tm);
> + int sent;
> +
> + /* 1. emulate that pkts packets were recieved */
> + odp_random_data((uint8_t *)&pkts, sizeof(pkts), 0);
> + pkts = ((pkts & 0xffff) % MAX_PKT_BURST) + 1;
> +
> + for (i = 0; i < pkts; i++) {
> + odp_packet_t pkt;
> +
> + pkt = odp_packet_alloc(pool, SHM_PKT_POOL_BUF_SIZE);
> + if (pkt == ODP_PACKET_INVALID) {
> + pkts = i;
> + printf("unable to alloc packet\n");
> + break;
> + }
> + pkt_tbl[i] = pkt;
> + }
> +
> + /* 2. Copy timestemp to that packets */
> + for (i = 0; i < pkts; i++) {
> + odp_packet_copydata_in(pkt_tbl[i],
> + 0,
> + strlen(tm_str),
> + tm_str);
> + odp_packet_copydata_in(pkt_tbl[i],
> + strlen(tm_str),
> + 1,
> + "\0");
> + }
> + /* 3. Send packets to ipc_pktio */
> + sent = odp_pktio_send(ipc_pktio, pkt_tbl, pkts);
> + if (sent < 0)
> + fprintf(stderr, "error sending to ipc pktio\n");
> + else
> + printf("---main pid %d: ipcsend %d pkts, size %d,
> data: %s\n",
> + getpid(), sent,
> + odp_packet_len(pkt_tbl[0]),
> + tm_str);
> +
> + /* 4. Sleep some time to not overflow debug prints */
> + busy_sleep(1);
This wasn't what I had in mind, this still wastes cycles that could
otherwise be used to process packets. You need to 'merge' the
busy_sleep loop with the main loop. That is, at the beginning of this
for loop you need to check if a second has elapsed since last time you
printed stats. You also need to count how many packets have been
during a one second period. When a second elapses, you print the
stats, reset the counters, update the last timestamp. But you keep
processing packets and update counters.
Think of this example as a performance example, that measures the
throughput of the IPC pktio (that does memcpy's), in a similar way
that odp_l2fwd measures the throughput of forwarding l2 frames.
> +
> + /* 5. Recieve packets back from ipc_pktio, print timestemp and
> + * free that packet
> + */
> + while (1) {
> + pkts = odp_pktio_recv(ipc_pktio, pkt_tbl,
> + MAX_PKT_BURST);
> + if (pkts > 0) {
> + for (i = 0; i < pkts; i++) {
> + uint32_t len;
> + char *b;
> +
> + len = odp_packet_len(pkt_tbl[i]);
> + b = malloc(len);
> + odp_packet_copydata_out(pkt_tbl[i], 0,
> +
> odp_packet_len(pkt_tbl[i]),
> + b);
> + printf("---main pid %d: ipcsrecv:
> size %d, data: %s\n",
> + getpid(),
> + odp_packet_len(pkt_tbl[i]), b);
> + free(b);
> + odp_packet_free(pkt_tbl[i]);
> + }
> + } else {
> + break;
> + }
> + }
> + }
> +
> +/* unreachable */
> + return NULL;
> +}
> +
> +static int ipc_second_process(void)
> +{
> + odp_pktio_t pktio;
> + odp_packet_t pkt_tbl[MAX_PKT_BURST];
> + int i;
> + int pkts;
> +
> + /* linux shared memory can already have objects with names which
> + * second process can try to connect. That might be even interrupted
> + * current application. Might be later I will add magic numbers to
> + * each ipc object in linux-generic. HW platform should not have that
> + * problem. So just wait a little while master process will create
> + * all ipc objects before connecting to them.
> + */
> + busy_sleep(3);
> +
> + /* Do lookup packet I/O in IPC shared memory,
> + * and link it to local pool. */
> + while (1) {
> + pktio = odp_pktio_open("ipc_pktio", ODP_POOL_INVALID);
> + if (pktio == ODP_PKTIO_INVALID) {
> + busy_sleep(1);
This is actually a good place to do regular sleep.
> + printf("%s() pid %d: looking for ipc_pktio\n",
> + __func__, getpid());
> + continue;
> + }
> + break;
> + }
> +
> + for (;;) {
> + pkts = odp_pktio_recv(pktio, pkt_tbl, MAX_PKT_BURST);
> + if (pkts > 0) {
> + for (i = 0; i < pkts; i++) {
> + char *b = malloc(odp_packet_len(pkt_tbl[i]));
> +
> + odp_packet_copydata_out(pkt_tbl[i], 0,
> +
> odp_packet_len(pkt_tbl[i]),
> + b);
> +
> + printf("++++%s: pid %d, got packet %p, size
> %d, data: %s\n",
> + __func__, getpid(),
> + (void *)pkt_tbl[i],
> + odp_packet_len(pkt_tbl[i]), b);
> + free(b);
> +
> + odp_pktio_send(pktio, pkt_tbl, pkts);
> + }
> + } else {
> + /* No need to load cpu in example app.*/
> + busy_sleep(1);
Same here, you need to count how many packets were received within a
one second period.
> + }
> + }
> +
> + EXAMPLE_ERR("Unexpected close.");
> + return 0;
> +}
> +
> +/**
> + * ODP packet example main function
> + */
> +int main(int argc, char *argv[])
> +{
> + odp_pool_t pool;
> + odp_pool_param_t params;
> + int f;
> +
> + /* Parse and store the application arguments */
> + parse_args(argc, argv);
> +
> + /* Use fork() before odp_init_global() to have 2 isolated
> + * processes which need communicate to each other with
> + * shared memory.
> + */
> + f = fork();
> + if (f) {
> + printf("Process one pid: %d\n", getpid());
> + /* Init ODP before calling anything else */
> + if (odp_init_global(NULL, NULL)) {
> + EXAMPLE_ERR("Error: ODP global init failed.\n");
> + exit(EXIT_FAILURE);
> + }
> +
> + /* Init this thread */
> + if (odp_init_local()) {
> + EXAMPLE_ERR("Error: ODP local init failed.\n");
> + exit(EXIT_FAILURE);
> + }
> +
> + ipc_second_process();
> + } else {
> + printf("Process two pid: %d\n", getpid());
> + }
> +
> + /* Init ODP before calling anything else */
> + if (odp_init_global(NULL, NULL)) {
> + EXAMPLE_ERR("Error: ODP global init failed.\n");
> + exit(EXIT_FAILURE);
> + }
> +
> + /* Init this thread */
> + if (odp_init_local()) {
> + EXAMPLE_ERR("Error: ODP local init failed.\n");
> + exit(EXIT_FAILURE);
> + }
> +
> + /* Print both system and application information */
> + print_info(NO_PATH(argv[0]));
> +
> + /* Create packet pool */
> + memset(¶ms, 0, sizeof(params));
> + params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;
> + params.pkt.len = SHM_PKT_POOL_BUF_SIZE;
> + params.pkt.num = SHM_PKT_POOL_SIZE / SHM_PKT_POOL_BUF_SIZE;
> + params.type = ODP_POOL_PACKET;
> +
> + pool = odp_pool_create("packet_pool", ODP_SHM_NULL, ¶ms);
> + if (pool == ODP_POOL_INVALID) {
> + EXAMPLE_ERR("Error: packet pool create failed.\n");
> + exit(EXIT_FAILURE);
> + }
> +
> + odp_pool_print(pool);
> +
> + create_pktio(pktio_name, pool);
> +
> + pktio_run_loop(pool);
> +
> + return 0;
> +}
> +
> +/**
> + * Parse and store the command line arguments
> + *
> + * @param argc argument count
> + * @param argv[] argument vector
> + * @param appl_args Store application arguments here
> + */
> +static void parse_args(int argc, char *argv[])
> +{
> + int opt;
> + int long_index;
> + size_t len;
> + static struct option longopts[] = {
> + {"interface", required_argument, NULL, 'i'}, /* return 'i'
> */
> + {"help", no_argument, NULL, 'h'}, /* return 'h'
> */
> + {NULL, 0, NULL, 0}
> + };
> +
> + while (1) {
> + opt = getopt_long(argc, argv, "i:h",
> + longopts, &long_index);
> +
> + if (opt == -1)
> + break; /* No more options */
> +
> + switch (opt) {
> + case 'i':
> + len = strlen(optarg);
> + if (len == 0) {
> + usage(argv[0]);
> + exit(EXIT_FAILURE);
> + }
> + len += 1; /* add room for '\0' */
> +
> + pktio_name = malloc(len);
> + if (!pktio_name) {
> + usage(argv[0]);
> + exit(EXIT_FAILURE);
> + }
> + strcpy(pktio_name, optarg);
> +
> + break;
> + case 'h':
> + usage(argv[0]);
> + exit(EXIT_SUCCESS);
> + break;
> +
> + default:
> + break;
> + }
> + }
> +
> + if (!pktio_name) {
> + usage(argv[0]);
> + exit(EXIT_FAILURE);
> + }
> +
> + optind = 1; /* reset 'extern optind' from the getopt lib
> */
> +}
> +
> +/**
> + * Print system and application info
> + */
> +static void print_info(char *progname)
> +{
> + printf("\n"
> + "ODP system info\n"
> + "---------------\n"
> + "ODP API version: %s\n"
> + "CPU model: %s\n"
> + "CPU freq (hz): %"PRIu64"\n"
> + "Cache line size: %i\n"
> + "CPU count: %i\n"
> + "\n",
> + odp_version_api_str(), odp_sys_cpu_model_str(),
> odp_sys_cpu_hz(),
> + odp_sys_cache_line_size(), odp_cpu_count());
> +
> + printf("Running ODP appl: \"%s\"\n"
> + "-----------------\n"
> + "Using IF: %s\n",
> + progname, pktio_name);
> + printf("\n\n");
> + fflush(NULL);
> +}
> +
> +/**
> + * Prinf usage information
> + */
> +static void usage(char *progname)
> +{
> + printf("\n"
> + "Usage: %s OPTIONS\n"
> + " E.g. %s -i eth0\n"
> + "\n"
> + "OpenDataPlane example application.\n"
> + "\n"
> + "Mandatory OPTIONS:\n"
> + " -i, --interface Eth interface\n"
> + "\n"
> + "Optional OPTIONS\n"
> + " -h, --help Display help and exit.\n"
> + " environment variables: ODP_PKTIO_DISABLE_SOCKET_MMAP\n"
> + " ODP_PKTIO_DISABLE_SOCKET_MMSG\n"
> + " ODP_PKTIO_DISABLE_SOCKET_BASIC\n"
> + " can be used to advanced pkt I/O selection for
> linux-generic\n"
> + "\n", NO_PATH(progname), NO_PATH(progname)
> + );
> +}
> --
> 1.9.1
>
> _______________________________________________
> lng-odp mailing list
> [email protected]
> https://lists.linaro.org/mailman/listinfo/lng-odp
_______________________________________________
lng-odp mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/lng-odp