On 05/22/15 13:32, Ciprian Barbu wrote:
On Thu, May 21, 2015 at 6:32 PM, Maxim Uvarov <maxim.uva...@linaro.org> 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 <maxim.uva...@linaro.org> --- 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.
odp_l2fwd is performance demo. While that one is functional example. From my point it was useful to print send bunch of packets each second and get them back. I'm not sure why are you asking to redo that to performance demo. It's not hard to redo it. But it's just the other propose of the this example. busy_sleep() is used to make compatible with odp api and do not use
system sleep(). Maxim.
+ + /* 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 lng-odp@lists.linaro.org https://lists.linaro.org/mailman/listinfo/lng-odp
_______________________________________________ lng-odp mailing list lng-odp@lists.linaro.org https://lists.linaro.org/mailman/listinfo/lng-odp