On 21 May 2015 at 11:42, Maxim Uvarov <maxim.uva...@linaro.org> wrote: > On 05/20/2015 18:24, Ciprian Barbu wrote: >> >> On Fri, May 8, 2015 at 12:57 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 | 427 >>> ++++++++++++++++++++++++++++++++++++++++++++++++ >>> 5 files changed, 437 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..0ed5442 >>> --- /dev/null >>> +++ b/example/ipc/odp_ipc.c >>> @@ -0,0 +1,427 @@ >>> +/* 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); >>> + >>> +/** >>> + * 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); >> >> I had some troubles starting the example, it was like the second >> process started but the main process would die for some reason. I >> tried to debug it with gdb but then it started working. It was around >> this line I think, I could see the message >> Wait for second process set mdata_offset... >> >> Did you see any strange behavior on your side, especially after a fresh >> boot? > > > hm, did not see that but I will check. > >>> + 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 */ >>> + sleep(1); >> >> I don't think the sleep here is doing any good, the thread will >> effectively go to background not doing anything and losing packets. >> What would be useful instead would be to print statistics from time to >> time like odp_l2fwd does, showing the number of packets received by >> master and slave. You could do some logic in this for loop to >> continuously check if the 1 second elapsed and throw the sleep() >> instruction. It doesn't have to be 100% accurate. > > > this thread generates packets and delay should be good here. But perhaps sleep() is not a good API to use. Can't you use an ODP timer? This should ease portability.
> >>> + >>> + /* 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 platfrom shound not have >>> that >>> + * problem. So just wait a little while master process will >>> create >>> + * all ipc objects before connectioning to them. >>> + */ >>> + 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) { >>> + sleep(1); >>> + 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.*/ >>> + sleep(1); >>> + } >>> + } >>> + >>> + 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 == NULL) { >>> + 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 == NULL) { >>> + 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 _______________________________________________ lng-odp mailing list lng-odp@lists.linaro.org https://lists.linaro.org/mailman/listinfo/lng-odp