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(&params, 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, &params);
>>> +       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

Reply via email to