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? > + 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. > + > + /* 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