On 23 April 2015 at 06:37, <bala.manoha...@linaro.org> wrote:

> From: Balasubramanian Manoharan <bala.manoha...@linaro.org>
>
> ODP Classifier example
>
> This programs gets pmr rules as command-line parameter and configures the
> classification engine
> in the system.
>
> This initial version supports the following
> * ODP_PMR_SIP_ADDR pmr term
> * PMR term MATCH and RANGE type
> * Multiple PMR rule can be set on a single pktio interface with different
> queues associated to each PMR rule
> * Automatically configures a default queue and provides statistics for the
> same
> * Prints statistics interms of the number of packets dispatched to each
> queue
>
> Signed-off-by: Balasubramanian Manoharan <bala.manoha...@linaro.org>
>

Reviewed-and-tested-by: Mike Holmes <mike.hol...@linaro.org>


> ---
> v4: Incorporates review comments from Mike and Ola
>  configure.ac                        |   1 +
>  example/Makefile.am                 |   2 +-
>  example/classifier/.gitignore       |   1 +
>  example/classifier/Makefile.am      |  10 +
>  example/classifier/odp_classifier.c | 835
> ++++++++++++++++++++++++++++++++++++
>  5 files changed, 848 insertions(+), 1 deletion(-)
>  create mode 100644 example/classifier/.gitignore
>  create mode 100644 example/classifier/Makefile.am
>  create mode 100644 example/classifier/odp_classifier.c
>
> diff --git a/configure.ac b/configure.ac
> index 78ff245..d20bad2 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -272,6 +272,7 @@ AM_CXXFLAGS="-std=c++11"
>  AC_CONFIG_FILES([Makefile
>                  doc/Makefile
>                  example/Makefile
> +                example/classifier/Makefile
>                  example/generator/Makefile
>                  example/ipsec/Makefile
>                  example/packet/Makefile
> diff --git a/example/Makefile.am b/example/Makefile.am
> index 6bb4f5c..353f397 100644
> --- a/example/Makefile.am
> +++ b/example/Makefile.am
> @@ -1 +1 @@
> -SUBDIRS = generator ipsec packet timer
> +SUBDIRS = classifier generator ipsec packet timer
> diff --git a/example/classifier/.gitignore b/example/classifier/.gitignore
> new file mode 100644
> index 0000000..a356d48
> --- /dev/null
> +++ b/example/classifier/.gitignore
> @@ -0,0 +1 @@
> +odp_classifier
> diff --git a/example/classifier/Makefile.am
> b/example/classifier/Makefile.am
> new file mode 100644
> index 0000000..938f094
> --- /dev/null
> +++ b/example/classifier/Makefile.am
> @@ -0,0 +1,10 @@
> +include $(top_srcdir)/example/Makefile.inc
> +
> +bin_PROGRAMS = odp_classifier
> +odp_classifier_LDFLAGS = $(AM_LDFLAGS) -static
> +odp_classifier_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example
> +
> +noinst_HEADERS = \
> +                 $(top_srcdir)/example/example_debug.h
> +
> +dist_odp_classifier_SOURCES = odp_classifier.c
> diff --git a/example/classifier/odp_classifier.c
> b/example/classifier/odp_classifier.c
> new file mode 100644
> index 0000000..cf53565
> --- /dev/null
> +++ b/example/classifier/odp_classifier.c
> @@ -0,0 +1,835 @@
> +/* Copyright (c) 2015, Linaro Limited
> + * All rights reserved.
> + *
> + * SPDX-License-Identifier:     BSD-3-Clause
> + */
> +
> +#include <stdlib.h>
> +#include <string.h>
> +#include <getopt.h>
> +#include <unistd.h>
> +#include <example_debug.h>
> +
> +#include <odp.h>
> +#include <odp/helper/linux.h>
> +#include <odp/helper/eth.h>
> +#include <odp/helper/ip.h>
> +#include <strings.h>
> +#include <errno.h>
> +#include <stdio.h>
> +
> +/** @def MAX_WORKERS
> + * @brief Maximum number of worker threads
> + */
> +#define MAX_WORKERS            32
> +
> +/** @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_PMR_COUNT
> + * @brief Maximum number of Classification Policy
> + */
> +#define MAX_PMR_COUNT  8
> +
> +/** @def DISPLAY_STRING_LEN
> + * @brief Length of string used to display term value
> + */
> +#define DISPLAY_STRING_LEN     32
> +
> +/** 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))
> +
> +typedef struct {
> +       odp_queue_t queue;      /**< Associated queue handle */
> +       odp_cos_t cos;          /**< Associated cos handle */
> +       odp_pmr_t pmr;          /**< Associated pmr handle */
> +       odp_atomic_u64_t packet_count;  /**< count of received packets */
> +       odp_pmr_term_e term;            /**< odp pmr term value */
> +       char queue_name[ODP_QUEUE_NAME_LEN];    /**< queue name */
> +       odp_pmr_match_type_e match_type;        /**< pmr match type */
> +       int val_sz;     /**< size of the pmr term */
> +       union {
> +               struct {
> +                       uint32_t val;   /**< pmr term value */
> +                       uint32_t mask;  /**< pmr term mask */
> +               } match;
> +               struct  {
> +                       uint32_t val1;  /**< pmr term start range */
> +                       uint32_t val2;  /**< pmr term end range */
> +               } range;
> +       };
> +       char value1[DISPLAY_STRING_LEN];        /**< Display string1 */
> +       char value2[DISPLAY_STRING_LEN];        /**< Display string2 */
> +} global_statistics;
> +
> +typedef struct {
> +       global_statistics stats[MAX_PMR_COUNT];
> +       int policy_count;       /**< global policy count */
> +       int appl_mode;          /**< application mode */
> +       odp_atomic_u64_t total_packets; /**< total received packets */
> +       int cpu_count;          /**< Number of CPUs to use */
> +       uint32_t time;          /**< Number of seconds to run */
> +       char *if_name;          /**< pointer to interface names */
> +} appl_args_t;
> +
> +enum packet_mode {
> +       APPL_MODE_DROP,         /**< Packet is dropped */
> +       APPL_MODE_REPLY         /**< Packet is sent back */
> +};
> +
> +/* helper funcs */
> +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len);
> +static void swap_pkt_addrs(odp_packet_t pkt_tbl[], unsigned len);
> +static void parse_args(int argc, char *argv[], appl_args_t *appl_args);
> +static void print_info(char *progname, appl_args_t *appl_args);
> +static void usage(char *progname);
> +static void configure_cos_queue(odp_pktio_t pktio, appl_args_t *args);
> +static void configure_default_queue(odp_pktio_t pktio, appl_args_t *args);
> +static int convert_str_to_pmr_enum(char *token, odp_pmr_term_e *term);
> +static int parse_pmr_policy(appl_args_t *appl_args, char *argv[], char
> *optarg);
> +
> +static inline
> +void print_cls_statistics(appl_args_t *args)
> +{
> +       int i;
> +       uint32_t timeout;
> +       int infinite = 0;
> +
> +       printf("\n");
> +       for (i = 0; i < 40; i++)
> +               printf("-");
> +       printf("\n");
> +       /* print statistics */
> +       printf("CLASSIFIER EXAMPLE STATISTICS\n");
> +       for (i = 0; i < 40; i++)
> +               printf("-");
> +       printf("\n");
> +       printf("CONFIGURATION\n");
> +       printf("\n");
> +       printf("QUEUE\tMATCH\tVALUE1\t\tVALUE2\n");
> +       for (i = 0; i < 40; i++)
> +               printf("-");
> +       printf("\n");
> +       for (i = 0; i < args->policy_count - 1; i++) {
> +               printf("%s\t", args->stats[i].queue_name);
> +               if (args->stats[i].match_type == ODP_PMR_MASK)
> +                       printf("MATCH\t");
> +               else
> +                       printf("RANGE\t");
> +               printf("%s\t", args->stats[i].value1);
> +               printf("%s\n", args->stats[i].value2);
> +       }
> +       printf("\n");
> +       printf("RECEIVED PACKETS\n");
> +       for (i = 0; i < 40; i++)
> +               printf("-");
> +       printf("\n");
> +       for (i = 0; i < args->policy_count; i++)
> +               printf("%s\t", args->stats[i].queue_name);
> +       printf("Total Packets");
> +       printf("\n");
> +
> +       timeout = args->time;
> +
> +       /* Incase if default value is given for timeout
> +       run the loop infinitely */
> +       if (timeout == 0)
> +               infinite = 1;
> +
> +       for (; timeout > 0 || infinite; timeout--) {
> +               for (i = 0; i < args->policy_count; i++)
> +                       printf("%"PRIu64"\t",
> +                              odp_atomic_load_u64(&args->stats[i]
> +                                                  .packet_count));
> +
> +               printf("\t%"PRIu64"\t", odp_atomic_load_u64(&args->
> +
>  total_packets));
> +
> +               sleep(1);
> +               printf("\r");
> +               fflush(stdout);
> +       }
> +}
> +
> +static inline
> +int parse_ipv4_addr(const char *ipaddress, uint32_t *addr)
> +{
> +       int b[4];
> +       int converted;
> +
> +       converted = sscanf(ipaddress, "%d.%d.%d.%d",
> +                       &b[3], &b[2], &b[1], &b[0]);
> +       if (4 != converted)
> +               return -1;
> +
> +       if ((b[0] > 255) || (b[1] > 255) || (b[2] > 255) || (b[3] > 255))
> +               return -1;
> +
> +       *addr = b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24;
> +
> +       return 0;
> +}
> +
> +static inline
> +int parse_ipv4_mask(const char *str, uint32_t *mask)
> +{
> +       uint32_t b;
> +       sscanf(str, "%x", &b);
> +       *mask = b;
> +       return 0;
> +}
> +
> +/**
> + * Create a pktio handle, optionally associating a default input queue.
> + *
> + * @param dev Device name
> + * @param pool Associated Packet Pool
> + *
> + * @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_queue_t inq_def;
> +       odp_queue_param_t qparam;
> +       char inq_name[ODP_QUEUE_NAME_LEN];
> +       int ret;
> +
> +       /* Open a packet IO instance */
> +       pktio = odp_pktio_open(dev, pool);
> +       if (pktio == ODP_PKTIO_INVALID) {
> +               if (odp_errno() == EPERM)
> +                       EXAMPLE_ERR("Root level permission required\n");
> +
> +               EXAMPLE_ERR("pktio create failed for %s\n", dev);
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       qparam.sched.prio  = ODP_SCHED_PRIO_DEFAULT;
> +       qparam.sched.sync  = ODP_SCHED_SYNC_ATOMIC;
> +       qparam.sched.group = ODP_SCHED_GROUP_DEFAULT;
> +       snprintf(inq_name, sizeof(inq_name), "%" PRIu64 "-pktio_inq_def",
> +                odp_pktio_to_u64(pktio));
> +       inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0';
> +
> +       inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN,
> &qparam);
> +       if (inq_def == ODP_QUEUE_INVALID) {
> +               EXAMPLE_ERR("pktio inq create failed for %s\n", dev);
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       ret = odp_pktio_inq_setdef(pktio, inq_def);
> +       if (ret != 0) {
> +               EXAMPLE_ERR("default input-Q setup for %s\n", dev);
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       printf("  created pktio:%02" PRIu64
> +                       ", dev:%s, queue mode (ATOMIC queues)\n"
> +                       "  \tdefault pktio%02" PRIu64
> +                       "-INPUT queue:%" PRIu64 "\n",
> +                       odp_pktio_to_u64(pktio), dev,
> +                       odp_pktio_to_u64(pktio),
> odp_queue_to_u64(inq_def));
> +
> +       return pktio;
> +}
> +
> +/**
> + * Worker threads to receive the packet
> + *
> + */
> +static void *pktio_receive_thread(void *arg)
> +{
> +       int thr;
> +       odp_queue_t outq_def;
> +       odp_packet_t pkt;
> +       odp_event_t ev;
> +       unsigned long err_cnt = 0;
> +       odp_queue_t queue;
> +       int i;
> +       thr = odp_thread_id();
> +       appl_args_t *appl = (appl_args_t *)arg;
> +       global_statistics *stats;
> +
> +
> +       /* Init this thread */
> +       if (odp_init_local()) {
> +               EXAMPLE_ERR("ODP thread local init failed.\n");
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       /* Loop packets */
> +       for (;;) {
> +               odp_pktio_t pktio_tmp;
> +
> +               /* Use schedule to get buf from any input queue */
> +               ev = odp_schedule(&queue, ODP_SCHED_WAIT);
> +
> +               /* Loop back to receive packets incase of invalid event */
> +               if (odp_unlikely(ev == ODP_EVENT_INVALID))
> +                       continue;
> +
> +               pkt = odp_packet_from_event(ev);
> +
> +               /* Total packets received */
> +               odp_atomic_inc_u64(&appl->total_packets);
> +
> +               /* Drop packets with errors */
> +               if (odp_unlikely(drop_err_pkts(&pkt, 1) == 0)) {
> +                       EXAMPLE_ERR("Drop frame - err_cnt:%lu\n",
> ++err_cnt);
> +                       continue;
> +               }
> +
> +               pktio_tmp = odp_packet_input(pkt);
> +               outq_def = odp_pktio_outq_getdef(pktio_tmp);
> +
> +               if (outq_def == ODP_QUEUE_INVALID) {
> +                       EXAMPLE_ERR("  [%02i] Error: def output-Q query\n",
> +                                   thr);
> +                       return NULL;
> +               }
> +
> +               /* Swap Eth MACs and possibly IP-addrs before sending back
> */
> +               swap_pkt_addrs(&pkt, 1);
> +
> +               for (i = 0; i <  MAX_PMR_COUNT; i++) {
> +                       stats = &appl->stats[i];
> +                       if (queue == stats->queue)
> +                               odp_atomic_inc_u64(&stats->packet_count);
> +               }
> +
> +               if (appl->appl_mode == APPL_MODE_DROP)
> +                       odp_packet_free(pkt);
> +               else
> +                       odp_queue_enq(outq_def, ev);
> +       }
> +
> +       return NULL;
> +}
> +
> +static void configure_default_queue(odp_pktio_t pktio, appl_args_t *args)
> +{
> +       odp_queue_param_t qparam;
> +       odp_cos_t cos_default;
> +       char cos_name[ODP_COS_NAME_LEN];
> +       char queue_name[ODP_QUEUE_NAME_LEN];
> +       odp_queue_t queue_default;
> +       global_statistics *stats = args->stats;
> +       sprintf(cos_name, "Default%s", args->if_name);
> +       cos_default = odp_cos_create(cos_name);
> +
> +       qparam.sched.prio = ODP_SCHED_PRIO_DEFAULT;
> +       qparam.sched.sync = ODP_SCHED_SYNC_NONE;
> +       qparam.sched.group = ODP_SCHED_GROUP_ALL;
> +       sprintf(queue_name, "%s", "DefaultQueue");
> +       queue_default = odp_queue_create(queue_name,
> +                       ODP_QUEUE_TYPE_SCHED, &qparam);
> +
> +       odp_cos_set_queue(cos_default, queue_default);
> +       odp_pktio_default_cos_set(pktio, cos_default);
> +       stats[args->policy_count].cos = cos_default;
> +       /* add default queue to global stats */
> +       stats[args->policy_count].queue = queue_default;
> +       strcpy(stats[args->policy_count].queue_name, "DefaultQueue");
> +       odp_atomic_init_u64(&stats[args->policy_count].packet_count, 0);
> +       args->policy_count++;
> +}
> +
> +static void configure_cos_queue(odp_pktio_t pktio, appl_args_t *args)
> +{
> +       char cos_name[ODP_COS_NAME_LEN];
> +       char queue_name[ODP_QUEUE_NAME_LEN];
> +       int i;
> +       global_statistics *stats;
> +       odp_queue_param_t qparam;
> +
> +       for (i = 0; i < args->policy_count; i++) {
> +               stats = &args->stats[i];
> +               sprintf(cos_name, "CoS%s", stats->queue_name);
> +               stats->cos = odp_cos_create(cos_name);
> +
> +               if (stats->match_type == ODP_PMR_MASK) {
> +                       stats->pmr = odp_pmr_create_match(stats->term,
> +                                       &stats->match.val,
> +                                       &stats->match.mask,
> +                                       stats->val_sz);
> +               } else {
> +                       stats->pmr = odp_pmr_create_range(stats->term,
> +                                       &stats->range.val1,
> +                                       &stats->range.val2,
> +                                       stats->val_sz);
> +               }
> +               qparam.sched.prio = i % odp_schedule_num_prio();
> +               qparam.sched.sync = ODP_SCHED_SYNC_NONE;
> +               qparam.sched.group = ODP_SCHED_GROUP_ALL;
> +
> +               sprintf(queue_name, "%s%d", args->stats[i].queue_name, i);
> +               stats->queue = odp_queue_create(queue_name,
> +                                                ODP_QUEUE_TYPE_SCHED,
> +                                                &qparam);
> +               odp_cos_set_queue(stats->cos, stats->queue);
> +               odp_pktio_pmr_cos(stats->pmr, pktio, stats->cos);
> +
> +               odp_atomic_init_u64(&stats->packet_count, 0);
> +       }
> +}
> +
> +/**
> + * ODP Classifier example main function
> + */
> +int main(int argc, char *argv[])
> +{
> +       odph_linux_pthread_t thread_tbl[MAX_WORKERS];
> +       odp_pool_t pool;
> +       int num_workers;
> +       int i;
> +       int cpu;
> +       odp_cpumask_t cpumask;
> +       char cpumaskstr[ODP_CPUMASK_STR_SIZE];
> +       odp_pool_param_t params;
> +       odp_pktio_t pktio;
> +       appl_args_t *args;
> +       odp_shm_t shm;
> +
> +       /* 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);
> +       }
> +
> +       /* Reserve memory for args from shared mem */
> +       shm = odp_shm_reserve("cls_shm_args", sizeof(appl_args_t),
> +                             ODP_CACHE_LINE_SIZE, 0);
> +
> +       if (shm == ODP_SHM_INVALID) {
> +               EXAMPLE_ERR("Error: shared mem reserve failed.\n");
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       args = odp_shm_addr(shm);
> +
> +       if (args == NULL) {
> +               EXAMPLE_ERR("Error: shared mem alloc failed.\n");
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       memset(args, 0, sizeof(*args));
> +       /* Parse and store the application arguments */
> +       parse_args(argc, argv, args);
> +
> +       /* Print both system and application information */
> +       print_info(NO_PATH(argv[0]), args);
> +
> +       /* Default to system CPU count unless user specified */
> +       num_workers = MAX_WORKERS;
> +       if (args->cpu_count)
> +               num_workers = args->cpu_count;
> +
> +       /*
> +        * By default CPU #0 runs Linux kernel background tasks.
> +        * Start mapping thread from CPU #1
> +        */
> +       num_workers = odph_linux_cpumask_default(&cpumask, num_workers);
> +       (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));
> +
> +       printf("num worker threads: %i\n", num_workers);
> +       printf("first CPU:          %i\n", odp_cpumask_first(&cpumask));
> +       printf("cpu mask:           %s\n", cpumaskstr);
> +
> +       /* 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); */
> +       odp_atomic_init_u64(&args->total_packets, 0);
> +
> +       /* create pktio per interface */
> +       pktio = create_pktio(args->if_name, pool);
> +
> +       configure_cos_queue(pktio, args);
> +
> +       /* configure default Cos and default queue */
> +       configure_default_queue(pktio, args);
> +
> +       /* Create and init worker threads */
> +       memset(thread_tbl, 0, sizeof(thread_tbl));
> +
> +       cpu = odp_cpumask_first(&cpumask);
> +       for (i = 0; i < num_workers; ++i) {
> +               odp_cpumask_t thd_mask;
> +               /*
> +                * Calls odp_thread_create(cpu) for each thread
> +                */
> +               odp_cpumask_zero(&thd_mask);
> +               odp_cpumask_set(&thd_mask, cpu);
> +               odph_linux_pthread_create(&thread_tbl[i], &thd_mask,
> +                                         pktio_receive_thread,
> +                                         args);
> +               cpu = odp_cpumask_next(&cpumask, cpu);
> +       }
> +
> +       print_cls_statistics(args);
> +
> +       for (i = 0; i < args->policy_count; i++) {
> +               odp_cos_destroy(args->stats[i].cos);
> +               odp_queue_destroy(args->stats[i].queue);
> +       }
> +
> +       free(args->if_name);
> +       odp_shm_free(shm);
> +       printf("Exit\n\n");
> +
> +       return 0;
> +}
> +
> +/**
> + * Drop packets which input parsing marked as containing errors.
> + *
> + * Frees packets with error and modifies pkt_tbl[] to only contain
> packets with
> + * no detected errors.
> + *
> + * @param pkt_tbl  Array of packet
> + * @param len      Length of pkt_tbl[]
> + *
> + * @return Number of packets with no detected error
> + */
> +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len)
> +{
> +       odp_packet_t pkt;
> +       unsigned pkt_cnt = len;
> +       unsigned i, j;
> +
> +       for (i = 0, j = 0; i < len; ++i) {
> +               pkt = pkt_tbl[i];
> +
> +               if (odp_unlikely(odp_packet_has_error(pkt))) {
> +                       odp_packet_free(pkt); /* Drop */
> +                       pkt_cnt--;
> +               } else if (odp_unlikely(i != j++)) {
> +                       pkt_tbl[j-1] = pkt;
> +               }
> +       }
> +
> +       return pkt_cnt;
> +}
> +
> +/**
> + * Swap eth src<->dst and IP src<->dst addresses
> + *
> + * @param pkt_tbl  Array of packets
> + * @param len      Length of pkt_tbl[]
> + */
> +static void swap_pkt_addrs(odp_packet_t pkt_tbl[], unsigned len)
> +{
> +       odp_packet_t pkt;
> +       odph_ethhdr_t *eth;
> +       odph_ethaddr_t tmp_addr;
> +       odph_ipv4hdr_t *ip;
> +       uint32be_t ip_tmp_addr; /* tmp ip addr */
> +       unsigned i;
> +
> +       for (i = 0; i < len; ++i) {
> +               pkt = pkt_tbl[i];
> +               if (odp_packet_has_eth(pkt)) {
> +                       eth = (odph_ethhdr_t *)odp_packet_l2_ptr(pkt,
> NULL);
> +
> +                       tmp_addr = eth->dst;
> +                       eth->dst = eth->src;
> +                       eth->src = tmp_addr;
> +
> +                       if (odp_packet_has_ipv4(pkt)) {
> +                               /* IPv4 */
> +                               ip = (odph_ipv4hdr_t *)
> +                                       odp_packet_l3_ptr(pkt, NULL);
> +
> +                               ip_tmp_addr  = ip->src_addr;
> +                               ip->src_addr = ip->dst_addr;
> +                               ip->dst_addr = ip_tmp_addr;
> +                       }
> +               }
> +       }
> +}
> +
> +static int convert_str_to_pmr_enum(char *token, odp_pmr_term_e *term)
> +{
> +       if (0 == strcasecmp(token, "ODP_PMR_SIP_ADDR")) {
> +               *term = ODP_PMR_SIP_ADDR;
> +               return 0;
> +       }
> +       return -1;
> +}
> +
> +
> +static int parse_pmr_policy(appl_args_t *appl_args, char *argv[], char
> *optarg)
> +{
> +       int policy_count;
> +       char *token;
> +       size_t len;
> +       odp_pmr_term_e term;
> +       global_statistics *stats;
> +       char *pmr_str;
> +
> +       policy_count = appl_args->policy_count;
> +       stats = appl_args->stats;
> +
> +       /* last array index is needed for default queue */
> +       if (policy_count >= MAX_PMR_COUNT - 1) {
> +               EXAMPLE_ERR("Maximum allowed PMR reached\n");
> +               return -1;
> +       }
> +
> +       len = strlen(optarg);
> +       len++;
> +       pmr_str = malloc(len);
> +       strcpy(pmr_str, optarg);
> +
> +       /* PMR TERM */
> +       token = strtok(pmr_str, ":");
> +       if (convert_str_to_pmr_enum(token, &term)) {
> +               EXAMPLE_ERR("Invalid ODP_PMR_TERM string\n");
> +               exit(EXIT_FAILURE);
> +       }
> +       stats[policy_count].term = term;
> +       /* PMR RANGE vs MATCH */
> +       token = strtok(NULL, ":");
> +       if (0 == strcasecmp(token, "range")) {
> +               stats[policy_count].match_type = ODP_PMR_RANGE;
> +       } else if (0 == strcasecmp(token, "match")) {
> +               stats[policy_count].match_type = ODP_PMR_MASK;
> +       } else {
> +               usage(argv[0]);
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       /* PMR value */
> +       switch (term)   {
> +       case ODP_PMR_SIP_ADDR:
> +               if (stats[policy_count].match_type == ODP_PMR_MASK) {
> +                       token = strtok(NULL, ":");
> +                       strcpy(stats[policy_count].value1, token);
> +                       parse_ipv4_addr(token,
> &stats[policy_count].match.val);
> +                       token = strtok(NULL, ":");
> +                       strcpy(stats[policy_count].value2, token);
> +                       parse_ipv4_mask(token,
> &stats[policy_count].match.mask);
> +                       stats[policy_count].val_sz = 4;
> +               } else {
> +                       token = strtok(NULL, ":");
> +                       strcpy(stats[policy_count].value1,
> +                              token);
> +                       parse_ipv4_addr(token,
> &stats[policy_count].range.val1);
> +                       token = strtok(NULL, ":");
> +                       strcpy(stats[policy_count].value2, token);
> +                       parse_ipv4_addr(token,
> &stats[policy_count].range.val2);
> +                       stats[policy_count].val_sz = 4;
> +               }
> +       break;
> +       default:
> +               usage(argv[0]);
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       /* Queue Name */
> +       token = strtok(NULL, ":");
> +       strcpy(stats[policy_count].queue_name, token);
> +       appl_args->policy_count++;
> +       free(pmr_str);
> +       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[], appl_args_t *appl_args)
> +{
> +       int opt;
> +       int long_index;
> +       size_t len;
> +       int i;
> +       int interface = 0;
> +       int policy = 0;
> +
> +       static struct option longopts[] = {
> +               {"count", required_argument, NULL, 'c'},
> +               {"interface", required_argument, NULL, 'i'},    /* return
> 'i' */
> +               {"policy", required_argument, NULL, 'p'},       /* return
> 'p' */
> +               {"mode", required_argument, NULL, 'm'},         /* return
> 'm' */
> +               {"time", required_argument, NULL, 't'},         /* return
> 't' */
> +               {"help", no_argument, NULL, 'h'},               /* return
> 'h' */
> +               {NULL, 0, NULL, 0}
> +       };
> +
> +
> +       while (1) {
> +               opt = getopt_long(argc, argv, "+c:t:i:p:m:t:h",
> +                               longopts, &long_index);
> +
> +               if (opt == -1)
> +                       break;  /* No more options */
> +
> +               switch (opt) {
> +               case 'c':
> +                       appl_args->cpu_count = atoi(optarg);
> +                       break;
> +               case 'p':
> +                       if (0 > parse_pmr_policy(appl_args, argv, optarg))
> +                               continue;
> +                       policy = 1;
> +                       break;
> +               case 't':
> +                       appl_args->time = atoi(optarg);
> +                       break;
> +               case 'i':
> +                       len = strlen(optarg);
> +                       if (len == 0) {
> +                               usage(argv[0]);
> +                               exit(EXIT_FAILURE);
> +                       }
> +                       len += 1;       /* add room for '\0' */
> +
> +                       appl_args->if_name = malloc(len);
> +                       if (appl_args->if_name == NULL) {
> +                               usage(argv[0]);
> +                               exit(EXIT_FAILURE);
> +                       }
> +
> +                       strcpy(appl_args->if_name, optarg);
> +                       interface = 1;
> +                       break;
> +
> +               case 'h':
> +                       usage(argv[0]);
> +                       exit(EXIT_SUCCESS);
> +                       break;
> +               case 'm':
> +                       i = atoi(optarg);
> +                       if (i == 0)
> +                               appl_args->appl_mode = APPL_MODE_DROP;
> +                       else
> +                               appl_args->appl_mode = APPL_MODE_REPLY;
> +                       break;
> +
> +               default:
> +                       break;
> +               }
> +       }
> +
> +       if (!interface ||  !policy) {
> +               usage(argv[0]);
> +               exit(EXIT_FAILURE);
> +       }
> +       if (appl_args->if_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, appl_args_t *appl_args)
> +{
> +       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      ",
> +                       progname, appl_args->if_name);
> +       printf("\n\n");
> +       fflush(NULL);
> +}
> +
> +/**
> + * Prinf usage information
> + */
> +static void usage(char *progname)
> +{
> +       printf("\n"
> +                       "OpenDataPlane Classifier example.\n"
> +                       "Usage: %s OPTIONS\n"
> +                       "  E.g. %s -i eth1 -m 0 -p
> \"ODP_PMR_SIP_ADDR:match:10.10.10.5:FFFFFFFF:queue1\" \\\n"
> +                       "\t\t\t-p 
> \"ODP_PMR_SIP_ADDR:MATCH:10.10.10.6:FFFFFFFF:queue2\"
> \\\n"
> +                       "\t\t\t-p
> \"ODP_PMR_SIP_ADDR:MATCH:10.10.10.7:000000FF:queue3\" \\\n"
> +                       "\t\t\t-p \"ODP_PMR_SIP_ADDR:RANGE:10.10.10.10:10
> .10.10.20:queue3\"\n"
> +                       "\n"
> +                       "For the above example configuration the following
> will be the packet distribution\n"
> +                       "queue1\t\tPackets with source ip address
> 10.10.10.5\n"
> +                       "queue2\t\tPackets with source ip address whose
> last 8 bits match 7\n"
> +                       "queue3\t\tPackets with source ip address in the
> range 10.10.10.10 to 10.10.10.20\n"
> +                       "\n"
> +                       "Mandatory OPTIONS:\n"
> +                       "  -i, --interface Eth interface\n"
> +                       "  -p, --policy <odp_pmr_term_e>:<match
> type>:<value1>:<value2>:<queue name>\n"
> +                       "\n"
> +                       "<odp_pmr_term_e>       Packet Matching Rule
> defined with odp_pmr_term_e "
> +                       "for the policy\n"
> +                       "\n"
> +                       "<match type>           PMR Match type.\n"
> +                       "                       MATCH: PMR rule type
> MATCH\n"
> +                       "                       RANGE: PMR rule type
> RANCE\n"
> +                       "\n"
> +                       "<value1>               PMR value1.\n"
> +                       "                       If match type is MATCH is
> the the matching value.\n"
> +                       "                       If match type is RANGE it
> is start range.\n"
> +                       "\n"
> +                       "<value2>               PMR value2.\n"
> +                       "                       If match type is \"MATCH\"
> it is the MASK value\n"
> +                       "                       If match type is \"RANCE\"
> it is end range.\n"
> +                       "\n"
> +                       "Optional OPTIONS\n"
> +                       "  -c, --count <number> CPU count.\n"
> +                       "                       default: CPU core count.\n"
> +                       "\n"
> +                       "  -m, --mode           0: Packet Drop mode.
> Received packets will be dropped\n"
> +                       "                       !0: Packet ICMP mode.
> Received packets will be sent back\n"
> +                       "                       default: Packet Drop
> mode\n"
> +                       "\n"
> +                       " -t, --timeout         !0: Time for which the
> classifier will be run in seconds\n"
> +                       "                       0: Runs in infinite loop\n"
> +                       "                       default: Runs in infinite
> loop\n"
> +                       "\n"
> +                       "  -h, --help           Display help and exit.\n"
> +                       "\n", NO_PATH(progname), NO_PATH(progname)
> +             );
> +}
> --
> 2.0.1.472.g6f92e5f
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> https://lists.linaro.org/mailman/listinfo/lng-odp
>



-- 
Mike Holmes
Technical Manager - Linaro Networking Group
Linaro.org <http://www.linaro.org/> *│ *Open source software for ARM SoCs
_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to