On Wed, Dec 10, 2014 at 2:03 PM, Bala Manoharan
<bala.manoha...@linaro.org> wrote:
> On Wed, Dec 10, 2014 at 12:54:38PM +0200, Ciprian Barbu wrote:
>> On Tue, Dec 9, 2014 at 7:53 PM, Bill Fischofer
>> <bill.fischo...@linaro.org> wrote:
>> > If you've already received the packet there's not much point in classifying
>> > it since the output of classification is the queue that the packet should 
>> > be
>> > sent to (and the buffer pool it should be stored in for non-linux-generic
>> > implementations).  In my packet patch I include the odp_packet_parse()
>> > function but it's an internal API for now since it isn't part of the v0.5
>> > external spec.  Parsing would be useful independent of classification.
>>
>> I agree with always parsing packets received from the interface, but
>> for real platforms it's not clear to me if it can be an independent
>> process, like it can be for linux-generic. Looking at the
>> Classification document I see parsing as in integral part of the
>> classifier, if I'm reading it correctly.
>>
>> To be clear, I'm ok to give a go to the patch series as they are, just
>> wanted to get an idea of the differences between linux-generic and
>> other platforms in regards to classification.
>>
>> So please add my Reviewed-by to this patch also.
>>
> If the application wants to use the feature of classification for 
> user-generated packet
> it will have to send the packet through a loop back interface and the 
> classification engine
> can classify the packet and enqueue to correct queue.
> The same will be the used in-case for Encrypted packet which gets de-crypted 
> by the application
> and classification is applied by sending them over a virtual loopback 
> interface.

Ok, that sounds fair. But that's for user-generated packets, the
question was for packets that the application receives with
odp_pktio_recv.

>> >
>> > On Tue, Dec 9, 2014 at 10:47 AM, Ciprian Barbu <ciprian.ba...@linaro.org>
>> > wrote:
>> >>
>> >> I have one question that just came to me. See below.
>> >>
>> >> On Tue, Dec 9, 2014 at 4:23 AM, Bill Fischofer
>> >> <bill.fischo...@linaro.org> wrote:
>> >> >
>> >> >
>> >> > On Mon, Dec 8, 2014 at 6:02 AM, Balasubramanian Manoharan
>> >> > <bala.manoha...@linaro.org> wrote:
>> >> >>
>> >> >> The following features are implemented in this classification
>> >> >> implementation:
>> >> >> * Attaches PMR, PMR_SET to a Pktio entry
>> >> >> * Adds classifier object to pktio entry
>> >> >> * Attaches CoS values for L2 and L3 QoS to a Pktio entry
>> >> >> * Selects ClassOfService for a packet based on PMR, L2 QoS and L3 QoS
>> >> >> values
>> >> >> * Selects a default CoS if packet does not match any of the assigned
>> >> >> rules
>> >> >> * Selects an Error CoS for an Error packet
>> >> >> * Enqueues the packet to the queue associated with the selected CoS
>> >> >>
>> >> >> Signed-off-by: Balasubramanian Manoharan <bala.manoha...@linaro.org>
>> >> >
>> >> >
>> >> > Reviewed-by: Bill Fischofer <bill.fischo...@linaro.org>
>> >> >
>> >> >>
>> >> >> ---
>> >> >> V6: Incorporates review comments from Bill
>> >> >>  helper/include/odph_ip.h                           |   6 +
>> >> >>  platform/linux-generic/include/api/odp.h           |   1 +
>> >> >>  .../include/odp_buffer_pool_internal.h             |   9 +
>> >> >>  .../include/odp_classification_datamodel.h         | 201 +++++
>> >> >>  .../include/odp_classification_inlines.h           | 259 ++++++
>> >> >>  .../include/odp_classification_internal.h          | 173 ++++
>> >> >>  platform/linux-generic/include/odp_internal.h      |   2 +
>> >> >>  .../linux-generic/include/odp_packet_io_internal.h |   2 +
>> >> >>  platform/linux-generic/odp_buffer_pool.c           |  10 -
>> >> >>  platform/linux-generic/odp_classification.c        | 883
>> >> >> +++++++++++++++++++--
>> >> >>  platform/linux-generic/odp_init.c                  |   4 +
>> >> >>  platform/linux-generic/odp_packet_io.c             |  47 +-
>> >> >>  12 files changed, 1498 insertions(+), 99 deletions(-)
>> >> >>  create mode 100644
>> >> >> platform/linux-generic/include/odp_classification_datamodel.h
>> >> >>  create mode 100644
>> >> >> platform/linux-generic/include/odp_classification_inlines.h
>> >> >>  create mode 100644
>> >> >> platform/linux-generic/include/odp_classification_internal.h
>> >> >>
>> >> >> diff --git a/helper/include/odph_ip.h b/helper/include/odph_ip.h
>> >> >> index 2c83c0f..f78724e 100644
>> >> >> --- a/helper/include/odph_ip.h
>> >> >> +++ b/helper/include/odph_ip.h
>> >> >> @@ -35,6 +35,9 @@ extern "C" {
>> >> >>  /** @internal Returns IPv4 header length */
>> >> >>  #define ODPH_IPV4HDR_IHL(ver_ihl) ((ver_ihl) & 0x0f)
>> >> >>
>> >> >> +/** @internal Returns IPv4 DSCP */
>> >> >> +#define ODPH_IPV4HDR_DSCP(tos) (((tos) & 0xfc) >> 2)
>> >> >> +
>> >> >>  /** @internal Returns IPv4 Don't fragment */
>> >> >>  #define ODPH_IPV4HDR_FLAGS_DONT_FRAG(frag_offset)  ((frag_offset) &
>> >> >> 0x4000)
>> >> >>
>> >> >> @@ -47,6 +50,9 @@ extern "C" {
>> >> >>  /** @internal Returns true if IPv4 packet is a fragment */
>> >> >>  #define ODPH_IPV4HDR_IS_FRAGMENT(frag_offset) ((frag_offset) & 0x3fff)
>> >> >>
>> >> >> +/** @internal Returns IPv4 DSCP */
>> >> >> +#define ODPH_IPV6HDR_DSCP(ver_tc_flow) (uint8_t)((((ver_tc_flow) &
>> >> >> 0x0fc00000) >> 22) & 0xff)
>> >> >> +
>> >> >>  /** IPv4 header */
>> >> >>  typedef struct ODP_PACKED {
>> >> >>         uint8_t    ver_ihl;     /**< Version / Header length */
>> >> >> diff --git a/platform/linux-generic/include/api/odp.h
>> >> >> b/platform/linux-generic/include/api/odp.h
>> >> >> index 6e4f69e..b7b1ca9 100644
>> >> >> --- a/platform/linux-generic/include/api/odp.h
>> >> >> +++ b/platform/linux-generic/include/api/odp.h
>> >> >> @@ -47,6 +47,7 @@ extern "C" {
>> >> >>  #include <odp_packet_flags.h>
>> >> >>  #include <odp_packet_io.h>
>> >> >>  #include <odp_crypto.h>
>> >> >> +#include <odp_classification.h>
>> >> >>  #include <odp_rwlock.h>
>> >> >>
>> >> >>  #ifdef __cplusplus
>> >> >> diff --git a/platform/linux-generic/include/odp_buffer_pool_internal.h
>> >> >> b/platform/linux-generic/include/odp_buffer_pool_internal.h
>> >> >> index e0210bd..07602fe 100644
>> >> >> --- a/platform/linux-generic/include/odp_buffer_pool_internal.h
>> >> >> +++ b/platform/linux-generic/include/odp_buffer_pool_internal.h
>> >> >> @@ -22,6 +22,7 @@ extern "C" {
>> >> >>  #include <odp_buffer_pool.h>
>> >> >>  #include <odp_buffer_internal.h>
>> >> >>  #include <odp_align.h>
>> >> >> +#include <odp_align_internal.h>
>> >> >>  #include <odp_hints.h>
>> >> >>  #include <odp_config.h>
>> >> >>  #include <odp_debug.h>
>> >> >> @@ -64,6 +65,10 @@ struct pool_entry_s {
>> >> >>         size_t                  hdr_size;
>> >> >>  };
>> >> >>
>> >> >> +typedef union pool_entry_u {
>> >> >> +       struct pool_entry_s s;
>> >> >> +       uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct
>> >> >> pool_entry_s))];
>> >> >> +} pool_entry_t;
>> >> >>
>> >> >>  extern void *pool_entry_ptr[];
>> >> >>
>> >> >> @@ -73,6 +78,10 @@ static inline void *get_pool_entry(uint32_t pool_id)
>> >> >>         return pool_entry_ptr[pool_id];
>> >> >>  }
>> >> >>
>> >> >> +static inline uint32_t pool_handle_to_index(odp_buffer_pool_t
>> >> >> pool_hdl)
>> >> >> +{
>> >> >> +       return pool_hdl - 1;
>> >> >> +}
>> >> >>
>> >> >>  static inline odp_buffer_hdr_t *odp_buf_to_hdr(odp_buffer_t buf)
>> >> >>  {
>> >> >> diff --git
>> >> >> a/platform/linux-generic/include/odp_classification_datamodel.h
>> >> >> b/platform/linux-generic/include/odp_classification_datamodel.h
>> >> >> new file mode 100644
>> >> >> index 0000000..18846bc
>> >> >> --- /dev/null
>> >> >> +++ b/platform/linux-generic/include/odp_classification_datamodel.h
>> >> >> @@ -0,0 +1,201 @@
>> >> >> +/* Copyright (c) 2014, Linaro Limited
>> >> >> + * All rights reserved.
>> >> >> + *
>> >> >> + * SPDX-License-Identifier:     BSD-3-Clause
>> >> >> + */
>> >> >> +
>> >> >> +
>> >> >> +/**
>> >> >> + * @file
>> >> >> + *
>> >> >> + * ODP Classification Datamodel
>> >> >> + * Describes the classification internal data model
>> >> >> + */
>> >> >> +
>> >> >> +#ifndef ODP_CLASSIFICATION_DATAMODEL_H_
>> >> >> +#define ODP_CLASSIFICATION_DATAMODEL_H_
>> >> >> +
>> >> >> +#ifdef __cplusplus
>> >> >> +extern "C" {
>> >> >> +#endif
>> >> >> +
>> >> >> +#include <odp_spinlock.h>
>> >> >> +#include <odp_classification.h>
>> >> >> +#include <odp_buffer_pool_internal.h>
>> >> >> +#include <odp_packet_internal.h>
>> >> >> +#include <odp_packet_io_internal.h>
>> >> >> +#include <odp_queue_internal.h>
>> >> >> +
>> >> >> +/* Maximum Class Of Service Entry */
>> >> >> +#define ODP_COS_MAX_ENTRY              64
>> >> >> +/* Maximum PMR Set Entry */
>> >> >> +#define ODP_PMRSET_MAX_ENTRY           64
>> >> >> +/* Maximum PMR Entry */
>> >> >> +#define ODP_PMR_MAX_ENTRY              64
>> >> >> +/* Maximum PMR Terms in a PMR Set */
>> >> >> +#define ODP_PMRTERM_MAX                        8
>> >> >> +/* Maximum PMRs attached in PKTIO Level */
>> >> >> +#define ODP_PKTIO_MAX_PMR              8
>> >> >> +/* L2 Priority Bits */
>> >> >> +#define ODP_COS_L2_QOS_BITS            3
>> >> >> +/* Max L2 QoS value */
>> >> >> +#define ODP_COS_MAX_L2_QOS             (1 << ODP_COS_L2_QOS_BITS)
>> >> >> +/* L2 DSCP Bits */
>> >> >> +#define ODP_COS_L3_QOS_BITS            6
>> >> >> +/* Max L3 QoS Value */
>> >> >> +#define ODP_COS_MAX_L3_QOS             (1 << ODP_COS_L3_QOS_BITS)
>> >> >> +/* Max PMR Term bits */
>> >> >> +#define ODP_PMR_TERM_BYTES_MAX         8
>> >> >> +
>> >> >> +/* forward declaration */
>> >> >> +typedef union pmr_u pmr_t;
>> >> >> +
>> >> >> +/**
>> >> >> +Packet Matching Rule Term Value
>> >> >> +
>> >> >> +Stores the Term and Value mapping for a PMR.
>> >> >> +The maximum size of value currently supported in 64 bits
>> >> >> +**/
>> >> >> +typedef struct pmr_term_value {
>> >> >> +       odp_pmr_match_type_e match_type; /**< Packet Match Type*/
>> >> >> +       odp_pmr_term_e  term;           /* PMR Term */
>> >> >> +       union {
>> >> >> +               struct {
>> >> >> +                       uint64_t        val;
>> >> >> +                       uint64_t        mask;
>> >> >> +               } mask; /**< Match a masked set of bits */
>> >> >> +               struct {
>> >> >> +                       uint64_t        val1;
>> >> >> +                       uint64_t        val2;
>> >> >> +               } range; /**< Match an integer range */
>> >> >> +       };
>> >> >> +} pmr_term_value_t;
>> >> >> +
>> >> >> +typedef union cos_u cos_t;
>> >> >> +/*
>> >> >> +Class Of Service
>> >> >> +*/
>> >> >> +struct cos_s {
>> >> >> +       queue_entry_t *queue;           /* Associated Queue */
>> >> >> +       pool_entry_t *pool;             /* Associated Buffer pool */
>> >> >> +       pmr_t *pmr;                     /* Chained PMR */
>> >> >> +       cos_t *linked_cos;              /* CoS linked with the PMR */
>> >> >> +       uint32_t valid;                 /* validity Flag */
>> >> >> +       odp_drop_e drop_policy;         /* Associated Drop Policy */
>> >> >> +       odp_queue_group_t queue_group;  /* Associated Queue Group */
>> >> >> +       odp_cos_flow_set_t flow_set;    /* Assigned Flow Set */
>> >> >> +       char name[ODP_COS_NAME_LEN];    /* name */
>> >> >> +       size_t headroom;                /* Headroom for this CoS */
>> >> >> +       odp_spinlock_t lock;            /* cos lock */
>> >> >> +};
>> >> >> +
>> >> >> +typedef union cos_u {
>> >> >> +       struct cos_s s;
>> >> >> +       uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct cos_s))];
>> >> >> +} cos_t;
>> >> >> +
>> >> >> +
>> >> >> +/**
>> >> >> +Packet Matching Rule
>> >> >> +
>> >> >> +**/
>> >> >> +struct pmr_s {
>> >> >> +       uint32_t valid;                 /* Validity Flag */
>> >> >> +       odp_atomic_u32_t count;         /* num of packets matching this
>> >> >> rule */
>> >> >> +       uint32_t num_pmr;               /* num of PMR Term Values*/
>> >> >> +       odp_spinlock_t lock;            /* pmr lock*/
>> >> >> +       pmr_term_value_t  pmr_term_value[1];    /* Associated PMR Term
>> >> >> */
>> >> >> +};
>> >> >> +
>> >> >> +typedef union pmr_u {
>> >> >> +       struct pmr_s s;
>> >> >> +       uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct pmr_s))];
>> >> >> +} pmr_t;
>> >> >> +
>> >> >> +/**
>> >> >> +Packet Matching Rule Set
>> >> >> +
>> >> >> +This structure is implemented as a extension over struct pmr_s
>> >> >> +In order to use same pointer to access both pmr_s and pmr_set_s
>> >> >> +'num_pmr' value is used to differentiate between pmr_s and pmr_set_s
>> >> >> struct
>> >> >> +**/
>> >> >> +struct pmr_set_s {
>> >> >> +       pmr_t pmr;
>> >> >> +       pmr_term_value_t  pmr_term_value[ODP_PMRTERM_MAX - 1];
>> >> >> +                       /* List of associated PMR Terms */
>> >> >> +};
>> >> >> +
>> >> >> +typedef union pmr_set_u {
>> >> >> +       struct pmr_set_s s;
>> >> >> +       uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct
>> >> >> pmr_set_s))];
>> >> >> +} pmr_set_t;
>> >> >> +
>> >> >> +/**
>> >> >> +L2 QoS and CoS Map
>> >> >> +
>> >> >> +This structure holds the mapping between L2 QoS value and
>> >> >> +corresponding cos_t object
>> >> >> +**/
>> >> >> +typedef struct pmr_l2_cos {
>> >> >> +       odp_spinlock_t lock;    /* pmr_l2_cos lock */
>> >> >> +       cos_t *cos[ODP_COS_MAX_L2_QOS]; /* Array of CoS objects */
>> >> >> +} pmr_l2_cos_t;
>> >> >> +
>> >> >> +/**
>> >> >> +L3 QoS and CoS Map
>> >> >> +
>> >> >> +This structure holds the mapping between L3 QoS value and
>> >> >> +corresponding cos_t object
>> >> >> +**/
>> >> >> +typedef struct pmr_l3_cos {
>> >> >> +       odp_spinlock_t lock;    /* pmr_l3_cos lock */
>> >> >> +       cos_t *cos[ODP_COS_MAX_L3_QOS]; /* Array of CoS objects */
>> >> >> +} pmr_l3_cos_t;
>> >> >> +
>> >> >> +/**
>> >> >> +Linux Generic Classifier
>> >> >> +
>> >> >> +This structure is stored in pktio_entry and holds all
>> >> >> +the classifier configuration value.
>> >> >> +**/
>> >> >> +typedef struct classifier {
>> >> >> +       odp_spinlock_t lock;            /*pktio_cos lock */
>> >> >> +       uint32_t num_pmr;               /* num of PMRs linked to given
>> >> >> PKTIO*/
>> >> >> +       pmr_t *pmr[ODP_PKTIO_MAX_PMR];  /* PMRs linked with this PKTIO
>> >> >> */
>> >> >> +       cos_t *cos[ODP_PKTIO_MAX_PMR];  /* CoS linked with this PKTIO
>> >> >> */
>> >> >> +       cos_t *error_cos;               /* Associated Error CoS */
>> >> >> +       cos_t *default_cos;             /* Associated Default CoS */
>> >> >> +       uint32_t l3_precedence;         /* L3 QoS precedence */
>> >> >> +       pmr_l2_cos_t l2_cos_table;      /* L2 QoS-CoS table map */
>> >> >> +       pmr_l3_cos_t l3_cos_table;      /* L3 Qos-CoS table map */
>> >> >> +       odp_cos_flow_set_t flow_set;    /* Flow Set to be calculated
>> >> >> +                                       for this pktio */
>> >> >> +       size_t headroom;                /* Pktio Headroom */
>> >> >> +       size_t skip;                    /* Pktio Skip Offset */
>> >> >> +} classifier_t;
>> >> >> +
>> >> >> +/**
>> >> >> +Class of Service Table
>> >> >> +**/
>> >> >> +typedef struct odp_cos_table {
>> >> >> +       cos_t cos_entry[ODP_COS_MAX_ENTRY];
>> >> >> +} cos_tbl_t;
>> >> >> +
>> >> >> +/**
>> >> >> +PMR set table
>> >> >> +**/
>> >> >> +typedef struct pmr_set_tbl {
>> >> >> +       pmr_set_t pmr_set[ODP_PMRSET_MAX_ENTRY];
>> >> >> +} pmr_set_tbl_t;
>> >> >> +
>> >> >> +/**
>> >> >> +PMR table
>> >> >> +**/
>> >> >> +typedef struct pmr_tbl {
>> >> >> +       pmr_t pmr[ODP_PMR_MAX_ENTRY];
>> >> >> +} pmr_tbl_t;
>> >> >> +
>> >> >> +#ifdef __cplusplus
>> >> >> +}
>> >> >> +#endif
>> >> >> +#endif
>> >> >> diff --git
>> >> >> a/platform/linux-generic/include/odp_classification_inlines.h
>> >> >> b/platform/linux-generic/include/odp_classification_inlines.h
>> >> >> new file mode 100644
>> >> >> index 0000000..6b20119
>> >> >> --- /dev/null
>> >> >> +++ b/platform/linux-generic/include/odp_classification_inlines.h
>> >> >> @@ -0,0 +1,259 @@
>> >> >> +/* Copyright (c) 2014, Linaro Limited
>> >> >> + * All rights reserved.
>> >> >> + *
>> >> >> + * SPDX-License-Identifier:     BSD-3-Clause
>> >> >> + */
>> >> >> +
>> >> >> +
>> >> >> +/**
>> >> >> + * @file
>> >> >> + *
>> >> >> + * ODP Classification Inlines
>> >> >> + * Classification Inlines Functions
>> >> >> + */
>> >> >> +#ifndef __ODP_CLASSIFICATION_INLINES_H_
>> >> >> +#define __ODP_CLASSIFICATION_INLINES_H_
>> >> >> +
>> >> >> +#ifdef __cplusplus
>> >> >> +extern "C" {
>> >> >> +#endif
>> >> >> +
>> >> >> +#include <odp_debug.h>
>> >> >> +#include <odph_eth.h>
>> >> >> +#include <odph_ip.h>
>> >> >> +#include <odph_udp.h>
>> >> >> +#include <odph_tcp.h>
>> >> >> +
>> >> >> +/* PMR term value verification function
>> >> >> +These functions verify the given PMR term value with the value in the
>> >> >> packet
>> >> >> +These following functions return 1 on success and 0 on failure
>> >> >> +*/
>> >> >> +
>> >> >> +static inline int verify_pmr_packet_len(odp_packet_hdr_t *pkt_hdr,
>> >> >> +                                       pmr_term_value_t *term_value)
>> >> >> +{
>> >> >> +       if (term_value->match_type == ODP_PMR_MASK) {
>> >> >> +               if (term_value->mask.val == (pkt_hdr->frame_len &
>> >> >> +                   term_value->mask.mask))
>> >> >> +                       return 1;
>> >> >> +       } else {
>> >> >> +               if ((term_value->range.val1 <= pkt_hdr->frame_len) &&
>> >> >> +                   (pkt_hdr->frame_len <= term_value->range.val2))
>> >> >> +                       return 1;
>> >> >> +       }
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +static inline int verify_pmr_ip_proto(uint8_t *pkt_addr,
>> >> >> +                                     odp_packet_hdr_t *pkt_hdr,
>> >> >> +                                     pmr_term_value_t *term_value)
>> >> >> +{
>> >> >> +       odph_ipv4hdr_t *ip;
>> >> >> +       uint8_t proto;
>> >> >> +       if (!pkt_hdr->input_flags.ipv4)
>> >> >> +               return 0;
>> >> >> +       ip = (odph_ipv4hdr_t *)(pkt_addr + pkt_hdr->l3_offset);
>> >> >> +       proto = ip->proto;
>> >> >> +       if (term_value->match_type == ODP_PMR_MASK) {
>> >> >> +               if (term_value->mask.val == (proto &
>> >> >> term_value->mask.mask))
>> >> >> +                       return 1;
>> >> >> +       } else {
>> >> >> +               if ((term_value->range.val1 <= proto) &&
>> >> >> +                   (proto <= term_value->range.val2))
>> >> >> +                       return 1;
>> >> >> +       }
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +
>> >> >> +static inline int verify_pmr_ipv4_saddr(uint8_t *pkt_addr,
>> >> >> +                                       odp_packet_hdr_t *pkt_hdr,
>> >> >> +                                       pmr_term_value_t *term_value)
>> >> >> +{
>> >> >> +       odph_ipv4hdr_t *ip;
>> >> >> +       uint32_t ipaddr;
>> >> >> +       if (!pkt_hdr->input_flags.ipv4)
>> >> >> +               return 0;
>> >> >> +       ip = (odph_ipv4hdr_t *)(pkt_addr + pkt_hdr->l3_offset);
>> >> >> +       ipaddr = odp_be_to_cpu_32(ip->src_addr);
>> >> >> +       if (term_value->match_type == ODP_PMR_MASK) {
>> >> >> +               if (term_value->mask.val == (ipaddr &
>> >> >> term_value->mask.mask))
>> >> >> +                       return 1;
>> >> >> +       } else {
>> >> >> +               if ((term_value->range.val1 <= ipaddr) &&
>> >> >> +                   (ipaddr <= term_value->range.val2))
>> >> >> +                       return 1;
>> >> >> +       }
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +
>> >> >> +static inline int verify_pmr_ipv4_daddr(uint8_t *pkt_addr,
>> >> >> +                                       odp_packet_hdr_t *pkt_hdr,
>> >> >> +                                       pmr_term_value_t *term_value)
>> >> >> +{
>> >> >> +       odph_ipv4hdr_t *ip;
>> >> >> +       uint32_t ipaddr;
>> >> >> +       if (!pkt_hdr->input_flags.ipv4)
>> >> >> +               return 0;
>> >> >> +       ip = (odph_ipv4hdr_t *)(pkt_addr + pkt_hdr->l3_offset);
>> >> >> +       ipaddr = odp_be_to_cpu_32(ip->dst_addr);
>> >> >> +       if (term_value->match_type == ODP_PMR_MASK) {
>> >> >> +               if (term_value->mask.val == (ipaddr &
>> >> >> term_value->mask.mask))
>> >> >> +                       return 1;
>> >> >> +       } else {
>> >> >> +               if ((term_value->range.val1 <= ipaddr) &&
>> >> >> +                   (ipaddr <= term_value->range.val2))
>> >> >> +                       return 1;
>> >> >> +       }
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +
>> >> >> +static inline int verify_pmr_tcp_sport(uint8_t *pkt_addr,
>> >> >> +                                      odp_packet_hdr_t *pkt_hdr,
>> >> >> +                                      pmr_term_value_t *term_value)
>> >> >> +{
>> >> >> +       uint16_t sport;
>> >> >> +       odph_tcphdr_t *tcp;
>> >> >> +       if (!pkt_hdr->input_flags.tcp)
>> >> >> +               return 0;
>> >> >> +       tcp = (odph_tcphdr_t *)(pkt_addr + pkt_hdr->l4_offset);
>> >> >> +       sport = odp_be_to_cpu_16(tcp->src_port);
>> >> >> +       if (term_value->match_type == ODP_PMR_MASK) {
>> >> >> +               if (term_value->mask.val == (sport &
>> >> >> term_value->mask.mask))
>> >> >> +                       return 1;
>> >> >> +       } else {
>> >> >> +               if ((term_value->range.val1 <= sport) &&
>> >> >> +                   (sport <= term_value->range.val2))
>> >> >> +                       return 1;
>> >> >> +       }
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +
>> >> >> +static inline int verify_pmr_tcp_dport(uint8_t *pkt_addr,
>> >> >> +                                      odp_packet_hdr_t *pkt_hdr,
>> >> >> +                                      pmr_term_value_t *term_value)
>> >> >> +{
>> >> >> +       uint16_t dport;
>> >> >> +       odph_tcphdr_t *tcp;
>> >> >> +       if (!pkt_hdr->input_flags.tcp)
>> >> >> +               return 0;
>> >> >> +       tcp = (odph_tcphdr_t *)(pkt_addr + pkt_hdr->l4_offset);
>> >> >> +       dport = odp_be_to_cpu_16(tcp->dst_port);
>> >> >> +       if (term_value->match_type == ODP_PMR_MASK) {
>> >> >> +               if (term_value->mask.val == (dport &
>> >> >> term_value->mask.mask))
>> >> >> +                       return 1;
>> >> >> +       } else {
>> >> >> +               if ((term_value->range.val1 <= dport) &&
>> >> >> +                   (dport <= term_value->range.val2))
>> >> >> +                       return 1;
>> >> >> +       }
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +
>> >> >> +static inline int verify_pmr_udp_dport(uint8_t *pkt_addr,
>> >> >> +                                      odp_packet_hdr_t *pkt_hdr,
>> >> >> +                                      pmr_term_value_t *term_value)
>> >> >> +{
>> >> >> +       uint16_t dport;
>> >> >> +       odph_udphdr_t *udp;
>> >> >> +       if (!pkt_hdr->input_flags.udp)
>> >> >> +               return 0;
>> >> >> +       udp = (odph_udphdr_t *)(pkt_addr + pkt_hdr->l4_offset);
>> >> >> +       dport = odp_be_to_cpu_16(udp->dst_port);
>> >> >> +       if (term_value->match_type == ODP_PMR_MASK) {
>> >> >> +               if (term_value->mask.val == (dport &
>> >> >> term_value->mask.mask))
>> >> >> +                       return 1;
>> >> >> +       } else {
>> >> >> +               if ((term_value->range.val1 <= dport) &&
>> >> >> +                   (dport <= term_value->range.val2))
>> >> >> +                       return 1;
>> >> >> +       }
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +static inline int verify_pmr_udp_sport(uint8_t *pkt_addr,
>> >> >> +                                      odp_packet_hdr_t *pkt_hdr,
>> >> >> +                                      pmr_term_value_t *term_value)
>> >> >> +{
>> >> >> +       uint16_t sport;
>> >> >> +       odph_udphdr_t *udp;
>> >> >> +       if (!pkt_hdr->input_flags.udp)
>> >> >> +               return 0;
>> >> >> +       udp = (odph_udphdr_t *)(pkt_addr + pkt_hdr->l4_offset);
>> >> >> +       sport = odp_be_to_cpu_16(udp->src_port);
>> >> >> +       if (term_value->match_type == ODP_PMR_MASK) {
>> >> >> +               if (term_value->mask.val == (sport &
>> >> >> term_value->mask.mask))
>> >> >> +                       return 1;
>> >> >> +       } else {
>> >> >> +               if ((term_value->range.val1 <= sport) &&
>> >> >> +                   (sport <= term_value->range.val2))
>> >> >> +                       return 1;
>> >> >> +       }
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +
>> >> >> +static inline int verify_pmr_dmac(uint8_t *pkt_addr ODP_UNUSED,
>> >> >> +                                 odp_packet_hdr_t *pkt_hdr ODP_UNUSED,
>> >> >> +                                 pmr_term_value_t *term_value
>> >> >> ODP_UNUSED)
>> >> >> +{
>> >> >> +       ODP_UNIMPLEMENTED();
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +
>> >> >> +static inline int verify_pmr_ipv6_saddr(uint8_t *pkt_addr ODP_UNUSED,
>> >> >> +                                       odp_packet_hdr_t *pkt_hdr
>> >> >> ODP_UNUSED,
>> >> >> +                                       pmr_term_value_t *term_value
>> >> >> ODP_UNUSED)
>> >> >> +{
>> >> >> +       ODP_UNIMPLEMENTED();
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +static inline int verify_pmr_ipv6_daddr(uint8_t *pkt_addr ODP_UNUSED,
>> >> >> +                                       odp_packet_hdr_t *pkt_hdr
>> >> >> ODP_UNUSED,
>> >> >> +                                       pmr_term_value_t *term_value
>> >> >> ODP_UNUSED)
>> >> >> +{
>> >> >> +       ODP_UNIMPLEMENTED();
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +static inline int verify_pmr_vlan_id_0(uint8_t *pkt_addr ODP_UNUSED,
>> >> >> +                                      odp_packet_hdr_t *pkt_hdr
>> >> >> ODP_UNUSED,
>> >> >> +                                      pmr_term_value_t *term_value
>> >> >> ODP_UNUSED)
>> >> >> +{
>> >> >> +       ODP_UNIMPLEMENTED();
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +static inline int verify_pmr_vlan_id_x(uint8_t *pkt_addr ODP_UNUSED,
>> >> >> +                                      odp_packet_hdr_t *pkt_hdr
>> >> >> ODP_UNUSED,
>> >> >> +                                      pmr_term_value_t *term_value
>> >> >> ODP_UNUSED)
>> >> >> +{
>> >> >> +       ODP_UNIMPLEMENTED();
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +static inline int verify_pmr_ipsec_spi(uint8_t *pkt_addr ODP_UNUSED,
>> >> >> +                                      odp_packet_hdr_t *pkt_hdr
>> >> >> ODP_UNUSED,
>> >> >> +                                      pmr_term_value_t *term_value
>> >> >> ODP_UNUSED)
>> >> >> +{
>> >> >> +       ODP_UNIMPLEMENTED();
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +static inline int verify_pmr_ld_vni(uint8_t *pkt_addr ODP_UNUSED,
>> >> >> +                                   odp_packet_hdr_t *pkt_hdr
>> >> >> ODP_UNUSED,
>> >> >> +                                   pmr_term_value_t *term_value
>> >> >> ODP_UNUSED)
>> >> >> +{
>> >> >> +       ODP_UNIMPLEMENTED();
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +static inline int verify_pmr_eth_type_0(uint8_t *pkt_addr ODP_UNUSED,
>> >> >> +                                       odp_packet_hdr_t *pkt_hdr
>> >> >> ODP_UNUSED,
>> >> >> +                                       pmr_term_value_t *term_value
>> >> >> ODP_UNUSED)
>> >> >> +{
>> >> >> +       ODP_UNIMPLEMENTED();
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +static inline int verify_pmr_eth_type_x(uint8_t *pkt_addr ODP_UNUSED,
>> >> >> +                                       odp_packet_hdr_t *pkt_hdr
>> >> >> ODP_UNUSED,
>> >> >> +                                       pmr_term_value_t *term_value
>> >> >> ODP_UNUSED)
>> >> >> +{
>> >> >> +       ODP_UNIMPLEMENTED();
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +#ifdef __cplusplus
>> >> >> +}
>> >> >> +#endif
>> >> >> +#endif
>> >> >> diff --git
>> >> >> a/platform/linux-generic/include/odp_classification_internal.h
>> >> >> b/platform/linux-generic/include/odp_classification_internal.h
>> >> >> new file mode 100644
>> >> >> index 0000000..fd2c6af
>> >> >> --- /dev/null
>> >> >> +++ b/platform/linux-generic/include/odp_classification_internal.h
>> >> >> @@ -0,0 +1,173 @@
>> >> >> +/* Copyright (c) 2014, Linaro Limited
>> >> >> + * All rights reserved.
>> >> >> + *
>> >> >> + * SPDX-License-Identifier:     BSD-3-Clause
>> >> >> + */
>> >> >> +
>> >> >> +
>> >> >> +/**
>> >> >> + * @file
>> >> >> + *
>> >> >> + * ODP Classification Internal
>> >> >> + * Describes the classification internal Functions
>> >> >> + */
>> >> >> +
>> >> >> +#ifndef __ODP_CLASSIFICATION_INTERNAL_H_
>> >> >> +#define __ODP_CLASSIFICATION_INTERNAL_H_
>> >> >> +
>> >> >> +#ifdef __cplusplus
>> >> >> +extern "C" {
>> >> >> +#endif
>> >> >> +
>> >> >> +#include <odp_classification.h>
>> >> >> +#include <odp_queue.h>
>> >> >> +#include <odp_packet_internal.h>
>> >> >> +#include <odp_packet_io.h>
>> >> >> +#include <odp_packet_io_internal.h>
>> >> >> +#include <odp_classification_datamodel.h>
>> >> >> +
>> >> >> +/** Classification Internal function **/
>> >> >> +
>> >> >> +/**
>> >> >> +@internal
>> >> >> +Select a CoS for the given Packet based on pktio
>> >> >> +
>> >> >> +This function will call all the PMRs associated with a pktio for
>> >> >> +a given packet and will return the matched COS object.
>> >> >> +This function will check PMR, L2 and L3 QoS COS object associated
>> >> >> +with the PKTIO interface.
>> >> >> +
>> >> >> +Returns the default cos if the packet does not match any PMR
>> >> >> +Returns the error_cos if the packet has an error
>> >> >> +**/
>> >> >> +cos_t *pktio_select_cos(pktio_entry_t *pktio, uint8_t *pkt_addr,
>> >> >> +                      odp_packet_hdr_t *pkt_hdr);
>> >> >> +
>> >> >> +/**
>> >> >> +@internal
>> >> >> +match_qos_cos
>> >> >> +
>> >> >> +Select a CoS for the given Packet based on QoS values
>> >> >> +This function returns the COS object matching the L2 and L3 QoS
>> >> >> +based on the l3_preference value of the pktio
>> >> >> +**/
>> >> >> +cos_t *match_qos_cos(pktio_entry_t *entry, uint8_t *pkt_addr,
>> >> >> +                    odp_packet_hdr_t *hdr);
>> >> >> +/**
>> >> >> +Packet Classifier
>> >> >> +
>> >> >> +Start function for Packet Classifier
>> >> >> +This function calls Classifier module internal functions for a given
>> >> >> packet and
>> >> >> +enqueues the packet to specific Queue based on PMR and CoS selected.
>> >> >> +**/
>> >> >> +int packet_classifier(odp_pktio_t pktio, odp_packet_t pkt);
>> >> >> +/**
>> >> >> +Packet IO classifier init
>> >> >> +
>> >> >> +This function does initialization of classifier object associated with
>> >> >> pktio.
>> >> >> +This function should be called during pktio initialization.
>> >> >> +**/
>> >> >> +int pktio_classifier_init(pktio_entry_t *pktio);
>> >> >> +
>> >> >> +/**
>> >> >> +@internal
>> >> >> +match_pmr_cos
>> >> >> +
>> >> >> +Match a PMR chain with a Packet and return matching CoS
>> >> >> +This function gets called recursively to check the chained PMR Term
>> >> >> value
>> >> >> +with the packet.
>> >> >> +
>> >> >> +**/
>> >> >> +cos_t *match_pmr_cos(cos_t *cos, uint8_t *pkt_addr, pmr_t *pmr,
>> >> >> +                    odp_packet_hdr_t *hdr);
>> >> >> +/**
>> >> >> +@internal
>> >> >> +CoS associated with L3 QoS value
>> >> >> +
>> >> >> +This function returns the CoS associated with L3 QoS value
>> >> >> +**/
>> >> >> +cos_t *match_qos_l3_cos(pmr_l3_cos_t *l3_cos, uint8_t *pkt_addr,
>> >> >> +                       odp_packet_hdr_t *hdr);
>> >> >> +
>> >> >> +/**
>> >> >> +@internal
>> >> >> +CoS associated with L2 QoS value
>> >> >> +
>> >> >> +This function returns the CoS associated with L2 QoS value
>> >> >> +**/
>> >> >> +cos_t *match_qos_l2_cos(pmr_l2_cos_t *l2_cos, uint8_t *pkt_addr,
>> >> >> +                       odp_packet_hdr_t *hdr);
>> >> >> +/**
>> >> >> +@internal
>> >> >> +Flow Signature Calculation
>> >> >> +
>> >> >> +This function calculates the Flow Signature for a packet based on
>> >> >> +CoS and updates in Packet Meta Data
>> >> >> +**/
>> >> >> +int update_flow_signature(uint8_t *pkt_addr, cos_t *cos);
>> >> >> +
>> >> >> +/**
>> >> >> +@internal
>> >> >> +Allocate a odp_pmr_set_t Handle
>> >> >> +*/
>> >> >> +odp_pmr_set_t alloc_pmr_set(pmr_t **pmr);
>> >> >> +
>> >> >> +/**
>> >> >> +@internal
>> >> >> +Allocate a odp_pmr_t Handle
>> >> >> +*/
>> >> >> +odp_pmr_t alloc_pmr(pmr_t **pmr);
>> >> >> +
>> >> >> +/**
>> >> >> +@internal
>> >> >> +Pointer to pmr_set_t Handle
>> >> >> +This function checks for validity of pmr_set_t Handle
>> >> >> +*/
>> >> >> +pmr_set_t *get_pmr_set_entry(odp_pmr_set_t pmr_set_id);
>> >> >> +
>> >> >> +/**
>> >> >> +@internal
>> >> >> +Pointer to pmr_set_t Handle
>> >> >> +*/
>> >> >> +pmr_set_t *get_pmr_set_entry_internal(odp_pmr_set_t pmr_set_id);
>> >> >> +
>> >> >> +/**
>> >> >> +@internal
>> >> >> +Pointer to pmr_set_t Handle
>> >> >> +This function checks for validity of pmr_set_t Handle
>> >> >> +*/
>> >> >> +pmr_t *get_pmr_entry(odp_pmr_t pmr_id);
>> >> >> +
>> >> >> +/**
>> >> >> +@internal
>> >> >> +Pointer to pmr_set_t Handle
>> >> >> +*/
>> >> >> +pmr_t *get_pmr_entry_internal(odp_pmr_t pmr_id);
>> >> >> +
>> >> >> +/**
>> >> >> +@internal
>> >> >> +Pointer to odp_cos_t Handle
>> >> >> +*/
>> >> >> +cos_t *get_cos_entry(odp_cos_t cos_id);
>> >> >> +
>> >> >> +/**
>> >> >> +@internal
>> >> >> +Pointer to odp_cos_t Handle
>> >> >> +This function checks for validity of odp_cos_t Handle
>> >> >> +*/
>> >> >> +cos_t *get_cos_entry_internal(odp_cos_t cos_id);
>> >> >> +
>> >> >> +/**
>> >> >> +@internal
>> >> >> +Verify PMR with a Packet
>> >> >> +
>> >> >> +This function goes through each PMR_TERM value in pmr_t structure and
>> >> >> +calls verification function for each term.Returns 1 if PMR matches or
>> >> >> 0
>> >> >> +Otherwise.
>> >> >> +**/
>> >> >> +int verify_pmr(pmr_t *pmr, uint8_t *pkt_addr, odp_packet_hdr_t
>> >> >> *pkt_hdr);
>> >> >> +
>> >> >> +#ifdef __cplusplus
>> >> >> +}
>> >> >> +#endif
>> >> >> +#endif
>> >> >> diff --git a/platform/linux-generic/include/odp_internal.h
>> >> >> b/platform/linux-generic/include/odp_internal.h
>> >> >> index f8c1596..04c1030 100644
>> >> >> --- a/platform/linux-generic/include/odp_internal.h
>> >> >> +++ b/platform/linux-generic/include/odp_internal.h
>> >> >> @@ -32,6 +32,8 @@ int odp_buffer_pool_init_global(void);
>> >> >>  int odp_pktio_init_global(void);
>> >> >>  int odp_pktio_init_local(void);
>> >> >>
>> >> >> +int odp_classification_init_global(void);
>> >> >> +
>> >> >>  int odp_queue_init_global(void);
>> >> >>
>> >> >>  int odp_crypto_init_global(void);
>> >> >> diff --git a/platform/linux-generic/include/odp_packet_io_internal.h
>> >> >> b/platform/linux-generic/include/odp_packet_io_internal.h
>> >> >> index d129f22..465127b 100644
>> >> >> --- a/platform/linux-generic/include/odp_packet_io_internal.h
>> >> >> +++ b/platform/linux-generic/include/odp_packet_io_internal.h
>> >> >> @@ -20,6 +20,7 @@ extern "C" {
>> >> >>
>> >> >>  #include <odp_spinlock.h>
>> >> >>  #include <odp_packet_socket.h>
>> >> >> +#include <odp_classification_datamodel.h>
>> >> >>  #include <odp_align_internal.h>
>> >> >>
>> >> >>  #include <odp_config.h>
>> >> >> @@ -43,6 +44,7 @@ struct pktio_entry {
>> >> >>         odp_pktio_type_t type;          /**< pktio type */
>> >> >>         pkt_sock_t pkt_sock;            /**< using socket API for IO */
>> >> >>         pkt_sock_mmap_t pkt_sock_mmap;  /**< using socket mmap API for
>> >> >> IO
>> >> >> */
>> >> >> +       classifier_t cls;               /**< classifier linked with
>> >> >> this
>> >> >> pktio*/
>> >> >>         char name[IFNAMSIZ];            /**< name of pktio provided to
>> >> >>                                            pktio_open() */
>> >> >>  };
>> >> >> diff --git a/platform/linux-generic/odp_buffer_pool.c
>> >> >> b/platform/linux-generic/odp_buffer_pool.c
>> >> >> index 83c51fa..d20999b 100644
>> >> >> --- a/platform/linux-generic/odp_buffer_pool.c
>> >> >> +++ b/platform/linux-generic/odp_buffer_pool.c
>> >> >> @@ -57,12 +57,6 @@ typedef struct {
>> >> >>  } odp_any_buffer_hdr_t;
>> >> >>
>> >> >>
>> >> >> -typedef union pool_entry_u {
>> >> >> -       struct pool_entry_s s;
>> >> >> -
>> >> >> -       uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct
>> >> >> pool_entry_s))];
>> >> >> -
>> >> >> -} pool_entry_t;
>> >> >>
>> >> >>
>> >> >>  typedef struct pool_table_t {
>> >> >> @@ -87,10 +81,6 @@ static inline odp_buffer_pool_t
>> >> >> pool_index_to_handle(uint32_t pool_id)
>> >> >>  }
>> >> >>
>> >> >>
>> >> >> -static inline uint32_t pool_handle_to_index(odp_buffer_pool_t
>> >> >> pool_hdl)
>> >> >> -{
>> >> >> -       return pool_hdl -1;
>> >> >> -}
>> >> >>
>> >> >>
>> >> >>  static inline void set_handle(odp_buffer_hdr_t *hdr,
>> >> >> diff --git a/platform/linux-generic/odp_classification.c
>> >> >> b/platform/linux-generic/odp_classification.c
>> >> >> index 190d71e..3cb1537 100644
>> >> >> --- a/platform/linux-generic/odp_classification.c
>> >> >> +++ b/platform/linux-generic/odp_classification.c
>> >> >> @@ -1,69 +1,321 @@
>> >> >> +/* Copyright (c) 2014, Linaro Limited
>> >> >> + * All rights reserved.
>> >> >> + *
>> >> >> + * SPDX-License-Identifier:     BSD-3-Clause
>> >> >> + */
>> >> >> +
>> >> >>  #include <odp_classification.h>
>> >> >>  #include <odp_align.h>
>> >> >>  #include <odp_queue.h>
>> >> >>  #include <odp_debug.h>
>> >> >> +#include <odp_internal.h>
>> >> >>  #include <odp_debug_internal.h>
>> >> >> +#include <odp_packet_internal.h>
>> >> >>  #include <odp_packet_io.h>
>> >> >> +#include <odp_packet_io_internal.h>
>> >> >> +#include <odp_classification_datamodel.h>
>> >> >> +#include <odp_classification_inlines.h>
>> >> >> +#include <odp_classification_internal.h>
>> >> >> +#include <odp_buffer_pool_internal.h>
>> >> >> +#include <odp_shared_memory.h>
>> >> >> +#include <odph_eth.h>
>> >> >> +#include <string.h>
>> >> >> +#include <odp_spinlock.h>
>> >> >>
>> >> >> -odp_cos_t odp_cos_create(const char *name)
>> >> >> +#define LOCK(a)      odp_spinlock_lock(a)
>> >> >> +#define UNLOCK(a)    odp_spinlock_unlock(a)
>> >> >> +#define LOCK_INIT(a)   odp_spinlock_init(a)
>> >> >> +
>> >> >> +static cos_tbl_t *cos_tbl;
>> >> >> +static pmr_set_tbl_t   *pmr_set_tbl;
>> >> >> +static pmr_tbl_t       *pmr_tbl;
>> >> >> +
>> >> >> +cos_t *get_cos_entry_internal(odp_cos_t cos_id)
>> >> >> +{
>> >> >> +       return &(cos_tbl->cos_entry[cos_id]);
>> >> >> +}
>> >> >> +
>> >> >> +pmr_set_t *get_pmr_set_entry_internal(odp_pmr_set_t pmr_set_id)
>> >> >> +{
>> >> >> +       return &(pmr_set_tbl->pmr_set[pmr_set_id]);
>> >> >> +}
>> >> >> +
>> >> >> +pmr_t *get_pmr_entry_internal(odp_pmr_t pmr_id)
>> >> >>  {
>> >> >> -       (void) name;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       return &(pmr_tbl->pmr[pmr_id]);
>> >> >> +}
>> >> >> +
>> >> >> +int odp_classification_init_global(void)
>> >> >> +{
>> >> >> +       odp_shm_t cos_shm;
>> >> >> +       odp_shm_t pmr_shm;
>> >> >> +       odp_shm_t pmr_set_shm;
>> >> >> +       int i;
>> >> >> +
>> >> >> +       cos_shm = odp_shm_reserve("shm_odp_cos_tbl",
>> >> >> +                       sizeof(cos_tbl_t),
>> >> >> +                       sizeof(cos_t), 0);
>> >> >> +
>> >> >> +       if (cos_shm == ODP_SHM_INVALID) {
>> >> >> +               ODP_ERR("shm allocation failed for shm_odp_cos_tbl");
>> >> >> +               goto error;
>> >> >> +       }
>> >> >> +
>> >> >> +       cos_tbl = odp_shm_addr(cos_shm);
>> >> >> +       if (cos_tbl == NULL)
>> >> >> +               goto error_cos;
>> >> >> +
>> >> >> +       memset(cos_tbl, 0, sizeof(cos_tbl_t));
>> >> >> +       for (i = 0; i < ODP_COS_MAX_ENTRY; i++) {
>> >> >> +               /* init locks */
>> >> >> +               cos_t *cos = get_cos_entry_internal(i);
>> >> >> +               LOCK_INIT(&cos->s.lock);
>> >> >> +       }
>> >> >> +
>> >> >> +       pmr_shm = odp_shm_reserve("shm_odp_pmr_tbl",
>> >> >> +                       sizeof(pmr_tbl_t),
>> >> >> +                       sizeof(pmr_t), 0);
>> >> >> +
>> >> >> +       if (pmr_shm == ODP_SHM_INVALID) {
>> >> >> +               ODP_ERR("shm allocation failed for shm_odp_pmr_tbl");
>> >> >> +               goto error_cos;
>> >> >> +       }
>> >> >> +
>> >> >> +       pmr_tbl = odp_shm_addr(pmr_shm);
>> >> >> +       if (pmr_tbl == NULL)
>> >> >> +               goto error_pmr;
>> >> >> +
>> >> >> +       memset(pmr_tbl, 0, sizeof(pmr_tbl_t));
>> >> >> +       for (i = 0; i < ODP_PMR_MAX_ENTRY; i++) {
>> >> >> +               /* init locks */
>> >> >> +               pmr_t *pmr = get_pmr_entry_internal(i);
>> >> >> +               LOCK_INIT(&pmr->s.lock);
>> >> >> +       }
>> >> >> +
>> >> >> +       pmr_set_shm = odp_shm_reserve("shm_odp_pmr_set_tbl",
>> >> >> +                       sizeof(pmr_set_tbl_t),
>> >> >> +                       sizeof(pmr_set_t), 0);
>> >> >> +
>> >> >> +       if (pmr_set_shm == ODP_SHM_INVALID) {
>> >> >> +               ODP_ERR("shm allocation failed for
>> >> >> shm_odp_pmr_set_tbl");
>> >> >> +               goto error_pmr;
>> >> >> +       }
>> >> >> +
>> >> >> +       pmr_set_tbl = odp_shm_addr(pmr_set_shm);
>> >> >> +       if (pmr_set_tbl == NULL)
>> >> >> +               goto error_pmrset;
>> >> >> +
>> >> >> +       memset(pmr_set_tbl, 0, sizeof(pmr_set_tbl_t));
>> >> >> +       for (i = 0; i < ODP_PMRSET_MAX_ENTRY; i++) {
>> >> >> +               /* init locks */
>> >> >> +               pmr_set_t *pmr = get_pmr_set_entry_internal(i);
>> >> >> +               LOCK_INIT(&pmr->s.pmr.s.lock);
>> >> >> +       }
>> >> >> +
>> >> >>         return 0;
>> >> >> +
>> >> >> +error_pmrset:
>> >> >> +       odp_shm_free(pmr_set_shm);
>> >> >> +error_pmr:
>> >> >> +       odp_shm_free(pmr_shm);
>> >> >> +error_cos:
>> >> >> +       odp_shm_free(cos_shm);
>> >> >> +error:
>> >> >> +       return -1;
>> >> >> +}
>> >> >> +
>> >> >> +odp_cos_t odp_cos_create(const char *name)
>> >> >> +{
>> >> >> +       int i;
>> >> >> +
>> >> >> +       for (i = 0; i < ODP_COS_MAX_ENTRY; i++) {
>> >> >> +               LOCK(&cos_tbl->cos_entry[i].s.lock);
>> >> >> +               if (0 == cos_tbl->cos_entry[i].s.valid) {
>> >> >> +                       strncpy(cos_tbl->cos_entry[i].s.name, name,
>> >> >> +                               ODP_COS_NAME_LEN - 1);
>> >> >> +                       cos_tbl->cos_entry[i].s.name[ODP_COS_NAME_LEN -
>> >> >> 1]
>> >> >> = 0;
>> >> >> +                       cos_tbl->cos_entry[i].s.pmr = NULL;
>> >> >> +                       cos_tbl->cos_entry[i].s.linked_cos = NULL;
>> >> >> +                       cos_tbl->cos_entry[i].s.queue = NULL;
>> >> >> +                       cos_tbl->cos_entry[i].s.pool = NULL;
>> >> >> +                       cos_tbl->cos_entry[i].s.flow_set = 0;
>> >> >> +                       cos_tbl->cos_entry[i].s.headroom = 0;
>> >> >> +                       cos_tbl->cos_entry[i].s.valid = 1;
>> >> >> +                       UNLOCK(&cos_tbl->cos_entry[i].s.lock);
>> >> >> +                       return (odp_cos_t)i;
>> >> >> +               }
>> >> >> +               UNLOCK(&cos_tbl->cos_entry[i].s.lock);
>> >> >> +       }
>> >> >> +       ODP_ERR("ODP_COS_MAX_ENTRY reached");
>> >> >> +       return ODP_COS_INVALID;
>> >> >> +}
>> >> >> +
>> >> >> +odp_pmr_set_t alloc_pmr_set(pmr_t **pmr)
>> >> >> +{
>> >> >> +       int i;
>> >> >> +
>> >> >> +       for (i = 0; i < ODP_PMRSET_MAX_ENTRY; i++) {
>> >> >> +               LOCK(&pmr_set_tbl->pmr_set[i].s.pmr.s.lock);
>> >> >> +               if (0 == pmr_set_tbl->pmr_set[i].s.pmr.s.valid) {
>> >> >> +                       pmr_set_tbl->pmr_set[i].s.pmr.s.valid = 1;
>> >> >> +                       pmr_set_tbl->pmr_set[i].s.pmr.s.num_pmr = 0;
>> >> >> +                       *pmr = (pmr_t *)&pmr_set_tbl->pmr_set[i];
>> >> >> +                       odp_atomic_init_u32(&pmr_set_tbl->pmr_set[i]
>> >> >> +                                           .s.pmr.s.count, 0);
>> >> >> +                       return (odp_pmr_set_t)i; /* return as locked */
>> >> >> +               }
>> >> >> +               UNLOCK(&pmr_set_tbl->pmr_set[i].s.pmr.s.lock);
>> >> >> +       }
>> >> >> +       ODP_ERR("ODP_PMRSET_MAX_ENTRY reached");
>> >> >> +       return ODP_PMR_INVAL;
>> >> >> +}
>> >> >> +
>> >> >> +odp_pmr_t alloc_pmr(pmr_t **pmr)
>> >> >> +{
>> >> >> +       int i;
>> >> >> +
>> >> >> +       for (i = 0; i < ODP_PMR_MAX_ENTRY; i++) {
>> >> >> +               LOCK(&pmr_tbl->pmr[i].s.lock);
>> >> >> +               if (0 == pmr_tbl->pmr[i].s.valid) {
>> >> >> +                       pmr_tbl->pmr[i].s.valid = 1;
>> >> >> +                       odp_atomic_init_u32(&pmr_tbl->pmr[i].s.count,
>> >> >> 0);
>> >> >> +                       pmr_tbl->pmr[i].s.num_pmr = 0;
>> >> >> +                       *pmr = &pmr_tbl->pmr[i];
>> >> >> +                       return (odp_pmr_t)i; /* return as locked */
>> >> >> +               }
>> >> >> +               UNLOCK(&pmr_tbl->pmr[i].s.lock);
>> >> >> +       }
>> >> >> +       ODP_ERR("ODP_PMR_MAX_ENTRY reached");
>> >> >> +       return ODP_PMR_INVAL;
>> >> >> +}
>> >> >> +
>> >> >> +
>> >> >> +cos_t *get_cos_entry(odp_cos_t cos_id)
>> >> >> +{
>> >> >> +       if (cos_id >= ODP_COS_MAX_ENTRY || cos_id == ODP_COS_INVALID)
>> >> >> +               return NULL;
>> >> >> +       if (cos_tbl->cos_entry[cos_id].s.valid == 0)
>> >> >> +               return NULL;
>> >> >> +       return &(cos_tbl->cos_entry[cos_id]);
>> >> >> +}
>> >> >> +
>> >> >> +
>> >> >> +pmr_set_t *get_pmr_set_entry(odp_pmr_set_t pmr_set_id)
>> >> >> +{
>> >> >> +       if (pmr_set_id >= ODP_PMRSET_MAX_ENTRY || pmr_set_id ==
>> >> >> ODP_PMR_INVAL)
>> >> >> +               return NULL;
>> >> >> +       if (pmr_set_tbl->pmr_set[pmr_set_id].s.pmr.s.valid == 0)
>> >> >> +               return NULL;
>> >> >> +       return &(pmr_set_tbl->pmr_set[pmr_set_id]);
>> >> >> +}
>> >> >> +
>> >> >> +pmr_t *get_pmr_entry(odp_pmr_t pmr_id)
>> >> >> +{
>> >> >> +       if (pmr_id >= ODP_PMR_MAX_ENTRY || pmr_id == ODP_PMR_INVAL)
>> >> >> +               return NULL;
>> >> >> +       if (pmr_tbl->pmr[pmr_id].s.valid == 0)
>> >> >> +               return NULL;
>> >> >> +       return &(pmr_tbl->pmr[pmr_id]);
>> >> >>  }
>> >> >>
>> >> >>  int odp_cos_destroy(odp_cos_t cos_id)
>> >> >>  {
>> >> >> -       (void)cos_id;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       cos_t *cos = get_cos_entry(cos_id);
>> >> >> +       if (NULL == cos) {
>> >> >> +               ODP_ERR("Invalid odp_cos_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       cos->s.valid = 0;
>> >> >>         return 0;
>> >> >>  }
>> >> >>
>> >> >>  int odp_cos_set_queue(odp_cos_t cos_id, odp_queue_t queue_id)
>> >> >>  {
>> >> >> -       (void)cos_id;
>> >> >> -       (void)queue_id;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       cos_t *cos = get_cos_entry(cos_id);
>> >> >> +       if (cos == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_cos_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +       /* Locking is not required as intermittent stale
>> >> >> +       data during CoS modification is acceptable*/
>> >> >> +       cos->s.queue = queue_to_qentry(queue_id);
>> >> >>         return 0;
>> >> >>  }
>> >> >>
>> >> >>  int odp_cos_set_drop(odp_cos_t cos_id, odp_drop_e drop_policy)
>> >> >>  {
>> >> >> -       (void)cos_id;
>> >> >> -       (void)drop_policy;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       cos_t *cos = get_cos_entry(cos_id);
>> >> >> +       if (cos == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_cos_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       /*Drop policy is not supported in v1.0*/
>> >> >> +       cos->s.drop_policy = drop_policy;
>> >> >>         return 0;
>> >> >>  }
>> >> >>
>> >> >>  int odp_pktio_set_default_cos(odp_pktio_t pktio_in, odp_cos_t
>> >> >> default_cos)
>> >> >>  {
>> >> >> -       (void)pktio_in;
>> >> >> -       (void)default_cos;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       pktio_entry_t *entry;
>> >> >> +       cos_t *cos;
>> >> >> +       entry = get_pktio_entry(pktio_in);
>> >> >> +       if (entry == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_pktio_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +       cos = get_cos_entry(default_cos);
>> >> >> +       if (cos == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_cos_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       entry->s.cls.default_cos = cos;
>> >> >>         return 0;
>> >> >>  }
>> >> >>
>> >> >>  int odp_pktio_set_error_cos(odp_pktio_t pktio_in, odp_cos_t error_cos)
>> >> >>  {
>> >> >> -       (void)pktio_in;
>> >> >> -       (void)error_cos;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       pktio_entry_t *entry;
>> >> >> +       cos_t *cos;
>> >> >> +
>> >> >> +       entry = get_pktio_entry(pktio_in);
>> >> >> +       if (entry == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_pktio_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       cos = get_cos_entry(error_cos);
>> >> >> +       if (cos == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_cos_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       entry->s.cls.error_cos = cos;
>> >> >>         return 0;
>> >> >>  }
>> >> >>
>> >> >>  int odp_pktio_set_skip(odp_pktio_t pktio_in, size_t offset)
>> >> >>  {
>> >> >> -       (void)pktio_in;
>> >> >> -       (void)offset;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       pktio_entry_t *entry = get_pktio_entry(pktio_in);
>> >> >> +       if (entry == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_cos_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       entry->s.cls.skip = offset;
>> >> >>         return 0;
>> >> >>  }
>> >> >>
>> >> >> -int odp_pktio_set_headroom(odp_pktio_t port_id, size_t headroom)
>> >> >> +int odp_pktio_set_headroom(odp_pktio_t pktio_in, size_t headroom)
>> >> >>  {
>> >> >> -       (void)port_id;
>> >> >> -       (void)headroom;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       pktio_entry_t *entry = get_pktio_entry(pktio_in);
>> >> >> +       if (entry == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_pktio_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +       entry->s.cls.headroom = headroom;
>> >> >>         return 0;
>> >> >>  }
>> >> >>
>> >> >> @@ -72,11 +324,26 @@ int odp_cos_with_l2_priority(odp_pktio_t pktio_in,
>> >> >>                              uint8_t qos_table[],
>> >> >>                              odp_cos_t cos_table[])
>> >> >>  {
>> >> >> -       (void)pktio_in;
>> >> >> -       (void)num_qos;
>> >> >> -       (void)qos_table;
>> >> >> -       (void)cos_table;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       pmr_l2_cos_t *l2_cos;
>> >> >> +       size_t i;
>> >> >> +       cos_t *cos;
>> >> >> +       pktio_entry_t *entry = get_pktio_entry(pktio_in);
>> >> >> +       if (entry == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_pktio_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +       l2_cos = &entry->s.cls.l2_cos_table;
>> >> >> +
>> >> >> +       LOCK(&l2_cos->lock);
>> >> >> +       /* Update the L2 QoS table*/
>> >> >> +       for (i = 0; i < num_qos; i++) {
>> >> >> +               cos = get_cos_entry(cos_table[i]);
>> >> >> +               if (cos != NULL) {
>> >> >> +                       if (ODP_COS_MAX_L2_QOS > qos_table[i])
>> >> >> +                               l2_cos->cos[qos_table[i]] = cos;
>> >> >> +               }
>> >> >> +       }
>> >> >> +       UNLOCK(&l2_cos->lock);
>> >> >>         return 0;
>> >> >>  }
>> >> >>
>> >> >> @@ -86,12 +353,29 @@ int odp_cos_with_l3_qos(odp_pktio_t pktio_in,
>> >> >>                         odp_cos_t cos_table[],
>> >> >>                         bool l3_preference)
>> >> >>  {
>> >> >> -       (void)pktio_in;
>> >> >> -       (void)num_qos;
>> >> >> -       (void)qos_table;
>> >> >> -       (void)cos_table;
>> >> >> -       (void)l3_preference;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       pmr_l3_cos_t *l3_cos;
>> >> >> +       size_t i;
>> >> >> +       pktio_entry_t *entry = get_pktio_entry(pktio_in);
>> >> >> +       cos_t *cos;
>> >> >> +
>> >> >> +       if (entry == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_pktio_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       entry->s.cls.l3_precedence = l3_preference;
>> >> >> +       l3_cos = &entry->s.cls.l3_cos_table;
>> >> >> +
>> >> >> +       LOCK(&l3_cos->lock);
>> >> >> +       /* Update the L3 QoS table*/
>> >> >> +       for (i = 0; i < num_qos; i++) {
>> >> >> +               cos = get_cos_entry(cos_table[i]);
>> >> >> +               if (cos != NULL) {
>> >> >> +                       if (ODP_COS_MAX_L3_QOS > qos_table[i])
>> >> >> +                               l3_cos->cos[qos_table[i]] = cos;
>> >> >> +               }
>> >> >> +       }
>> >> >> +       UNLOCK(&l3_cos->lock);
>> >> >>         return 0;
>> >> >>  }
>> >> >>
>> >> >> @@ -100,12 +384,27 @@ odp_pmr_t odp_pmr_create_match(odp_pmr_term_e
>> >> >> term,
>> >> >>                                const void *mask,
>> >> >>                                size_t val_sz)
>> >> >>  {
>> >> >> -       (void)term;
>> >> >> -       (void)val;
>> >> >> -       (void)mask;
>> >> >> -       (void)val_sz;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> -       return 0;
>> >> >> +       pmr_t *pmr;
>> >> >> +       odp_pmr_t id;
>> >> >> +       if (val_sz > ODP_PMR_TERM_BYTES_MAX) {
>> >> >> +               ODP_ERR("val_sz greater than max supported limit");
>> >> >> +               return ODP_PMR_INVAL;
>> >> >> +       }
>> >> >> +
>> >> >> +       id = alloc_pmr(&pmr);
>> >> >> +       /*if alloc_pmr() is successful it returns with lock acquired*/
>> >> >> +       if (id == ODP_PMR_INVAL)
>> >> >> +               return ODP_PMR_INVAL;
>> >> >> +
>> >> >> +       pmr->s.num_pmr = 1;
>> >> >> +       pmr->s.pmr_term_value[0].match_type = ODP_PMR_MASK;
>> >> >> +       pmr->s.pmr_term_value[0].term = term;
>> >> >> +       pmr->s.pmr_term_value[0].mask.val =  0;
>> >> >> +       pmr->s.pmr_term_value[0].mask.mask =  0;
>> >> >> +       memcpy(&pmr->s.pmr_term_value[0].mask.val, val, val_sz);
>> >> >> +       memcpy(&pmr->s.pmr_term_value[0].mask.mask, mask, val_sz);
>> >> >> +       UNLOCK(&pmr->s.lock);
>> >> >> +       return id;
>> >> >>  }
>> >> >>
>> >> >>  odp_pmr_t odp_pmr_create_range(odp_pmr_term_e term,
>> >> >> @@ -113,18 +412,36 @@ odp_pmr_t odp_pmr_create_range(odp_pmr_term_e
>> >> >> term,
>> >> >>                                const void *val2,
>> >> >>                                size_t val_sz)
>> >> >>  {
>> >> >> -       (void)term;
>> >> >> -       (void)val1;
>> >> >> -       (void)val2;
>> >> >> -       (void)val_sz;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> -       return 0;
>> >> >> +       pmr_t *pmr;
>> >> >> +       odp_pmr_t id;
>> >> >> +
>> >> >> +       if (val_sz > ODP_PMR_TERM_BYTES_MAX) {
>> >> >> +               ODP_ERR("val_sz greater than max supported limit");
>> >> >> +               return ODP_PMR_INVAL;
>> >> >> +       }
>> >> >> +       id = alloc_pmr(&pmr);
>> >> >> +       /*if alloc_pmr() is successful it returns with lock acquired*/
>> >> >> +       if (id == ODP_PMR_INVAL)
>> >> >> +               return ODP_PMR_INVAL;
>> >> >> +
>> >> >> +       pmr->s.num_pmr = 1;
>> >> >> +       pmr->s.pmr_term_value[0].match_type = ODP_PMR_MASK;
>> >> >> +       pmr->s.pmr_term_value[0].term = term;
>> >> >> +       pmr->s.pmr_term_value[0].range.val1 =  0;
>> >> >> +       pmr->s.pmr_term_value[0].range.val2 =  0;
>> >> >> +       memcpy(&pmr->s.pmr_term_value[0].range.val1, val1, val_sz);
>> >> >> +       memcpy(&pmr->s.pmr_term_value[0].range.val2, val2, val_sz);
>> >> >> +       UNLOCK(&pmr->s.lock);
>> >> >> +       return id;
>> >> >>  }
>> >> >>
>> >> >>  int odp_pmr_destroy(odp_pmr_t pmr_id)
>> >> >>  {
>> >> >> -       (void)pmr_id;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       pmr_t *pmr = get_pmr_entry(pmr_id);
>> >> >> +
>> >> >> +       if (pmr == NULL)
>> >> >> +               return -1;
>> >> >> +       pmr->s.valid = 0;
>> >> >>         return 0;
>> >> >>  }
>> >> >>
>> >> >> @@ -132,64 +449,478 @@ int odp_pktio_pmr_cos(odp_pmr_t pmr_id,
>> >> >>                       odp_pktio_t src_pktio,
>> >> >>                       odp_cos_t dst_cos)
>> >> >>  {
>> >> >> -       (void)pmr_id;
>> >> >> -       (void)src_pktio;
>> >> >> -       (void)dst_cos;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       uint8_t num_pmr;
>> >> >> +       pktio_entry_t *pktio_entry;
>> >> >> +       pmr_t *pmr;
>> >> >> +       cos_t *cos;
>> >> >> +
>> >> >> +       pktio_entry = get_pktio_entry(src_pktio);
>> >> >> +       if (pktio_entry == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_pktio_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       pmr = get_pmr_entry(pmr_id);
>> >> >> +       if (pmr == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_pmr_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       cos = get_cos_entry(dst_cos);
>> >> >> +       if (cos == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_cos_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       LOCK(&pktio_entry->s.cls.lock);
>> >> >> +       num_pmr = pktio_entry->s.cls.num_pmr;
>> >> >> +       if (num_pmr >= ODP_PKTIO_MAX_PMR) {
>> >> >> +               ODP_ERR("ODP_PKTIO_MAX_PMR reached");
>> >> >> +               UNLOCK(&pktio_entry->s.cls.lock);
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       pktio_entry->s.cls.pmr[num_pmr] = pmr;
>> >> >> +       pktio_entry->s.cls.cos[num_pmr] = cos;
>> >> >> +       pktio_entry->s.cls.num_pmr++;
>> >> >> +       UNLOCK(&pktio_entry->s.cls.lock);
>> >> >> +
>> >> >>         return 0;
>> >> >>  }
>> >> >>
>> >> >>  int odp_cos_pmr_cos(odp_pmr_t pmr_id, odp_cos_t src_cos, odp_cos_t
>> >> >> dst_cos)
>> >> >>  {
>> >> >> -       (void)pmr_id;
>> >> >> -       (void)src_cos;
>> >> >> -       (void)dst_cos;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       cos_t *cos_src = get_cos_entry(src_cos);
>> >> >> +       cos_t *cos_dst = get_cos_entry(dst_cos);
>> >> >> +       pmr_t *pmr = get_pmr_entry(pmr_id);
>> >> >> +       if (NULL == cos_src || NULL == cos_dst || NULL == pmr) {
>> >> >> +               ODP_ERR("Invalid input handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       /*Locking is not required as intermittent stale data is
>> >> >> acceptable*/
>> >> >> +       cos_src->s.pmr = pmr;
>> >> >> +       cos_src->s.linked_cos = cos_dst;
>> >> >> +
>> >> >>         return 0;
>> >> >>  }
>> >> >>
>> >> >>  signed long odp_pmr_match_count(odp_pmr_t pmr_id)
>> >> >>  {
>> >> >> -       (void)pmr_id;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> -       return 0;
>> >> >> +       pmr_t *pmr = get_pmr_entry(pmr_id);
>> >> >> +       if (pmr == NULL)
>> >> >> +               return -1;
>> >> >> +       return (signed long)odp_atomic_load_u32(&pmr->s.count);
>> >> >>  }
>> >> >>
>> >> >>  unsigned long long odp_pmr_terms_cap(void)
>> >> >>  {
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> -       return 0;
>> >> >> +       unsigned long long term_cap = 0;
>> >> >> +
>> >> >> +       term_cap |= (1 << ODP_PMR_LEN);
>> >> >> +       term_cap |= (1 << ODP_PMR_IPPROTO);
>> >> >> +       term_cap |= (1 << ODP_PMR_UDP_DPORT);
>> >> >> +       term_cap |= (1 << ODP_PMR_TCP_DPORT);
>> >> >> +       term_cap |= (1 << ODP_PMR_UDP_SPORT);
>> >> >> +       term_cap |= (1 << ODP_PMR_TCP_SPORT);
>> >> >> +       term_cap |= (1 << ODP_PMR_SIP_ADDR);
>> >> >> +       term_cap |= (1 << ODP_PMR_DIP_ADDR);
>> >> >> +       return term_cap;
>> >> >>  }
>> >> >>
>> >> >>  unsigned odp_pmr_terms_avail(void)
>> >> >>  {
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> -       return 0;
>> >> >> +       unsigned count = 0;
>> >> >> +       int i;
>> >> >> +
>> >> >> +       for (i = 0; i < ODP_PMR_MAX_ENTRY; i++)
>> >> >> +               if (!pmr_tbl->pmr[i].s.valid)
>> >> >> +                       count++;
>> >> >> +       return count;
>> >> >>  }
>> >> >>
>> >> >>  int odp_pmr_match_set_create(int num_terms, odp_pmr_match_t *terms,
>> >> >>                              odp_pmr_set_t *pmr_set_id)
>> >> >>  {
>> >> >> -       (void)num_terms;
>> >> >> -       (void)terms;
>> >> >> -       (void)pmr_set_id;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> -       return 0;
>> >> >> +       pmr_t *pmr;
>> >> >> +       int i;
>> >> >> +       uint32_t id;
>> >> >> +       int val_sz;
>> >> >> +       int count = 0;
>> >> >> +
>> >> >> +       if (num_terms > ODP_PMRTERM_MAX) {
>> >> >> +               ODP_ERR("no of terms greater than supported
>> >> >> ODP_PMRTERM_MAX");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       id = alloc_pmr_set(&pmr);
>> >> >> +       /*if alloc_pmr_set is successful it returns with the acquired
>> >> >> lock*/
>> >> >> +       if (id == ODP_PMR_INVAL) {
>> >> >> +               *pmr_set_id = id;
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       pmr->s.num_pmr = num_terms;
>> >> >> +       for (i = 0; i < num_terms; i++) {
>> >> >> +               pmr->s.pmr_term_value[i].match_type =
>> >> >> terms[i].match_type;
>> >> >> +               if (terms[i].match_type == ODP_PMR_MASK) {
>> >> >> +                       val_sz = terms[i].mask.val_sz;
>> >> >> +                       if (val_sz > ODP_PMR_TERM_BYTES_MAX)
>> >> >> +                               continue;
>> >> >> +                       pmr->s.pmr_term_value[i].term =
>> >> >> terms[i].mask.term;
>> >> >> +                       pmr->s.pmr_term_value[i].mask.val = 0;
>> >> >> +                       pmr->s.pmr_term_value[i].mask.mask = 0;
>> >> >> +                       memcpy(&pmr->s.pmr_term_value[i].mask.val,
>> >> >> +                              terms[i].mask.val, val_sz);
>> >> >> +                       memcpy(&pmr->s.pmr_term_value[i].mask.mask,
>> >> >> +                              terms[i].mask.mask, val_sz);
>> >> >> +               } else {
>> >> >> +                       val_sz = terms[i].range.val_sz;
>> >> >> +                       if (val_sz > ODP_PMR_TERM_BYTES_MAX)
>> >> >> +                               continue;
>> >> >> +                       pmr->s.pmr_term_value[i].term =
>> >> >> terms[i].range.term;
>> >> >> +                       pmr->s.pmr_term_value[i].range.val1 = 0;
>> >> >> +                       pmr->s.pmr_term_value[i].range.val2 = 0;
>> >> >> +                       memcpy(&pmr->s.pmr_term_value[i].range.val1,
>> >> >> +                              terms[i].range.val1, val_sz);
>> >> >> +                       memcpy(&pmr->s.pmr_term_value[i].range.val2,
>> >> >> +                              terms[i].range.val2, val_sz);
>> >> >> +               }
>> >> >> +               count++;
>> >> >> +       }
>> >> >> +       *pmr_set_id = id;
>> >> >> +       UNLOCK(&pmr->s.lock);
>> >> >> +       return count;
>> >> >>  }
>> >> >>
>> >> >>  int odp_pmr_match_set_destroy(odp_pmr_set_t pmr_set_id)
>> >> >>  {
>> >> >> -       (void)pmr_set_id;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       pmr_set_t *pmr_set = get_pmr_set_entry(pmr_set_id);
>> >> >> +       if (pmr_set == NULL)
>> >> >> +               return -1;
>> >> >> +
>> >> >> +       pmr_set->s.pmr.s.valid = 0;
>> >> >>         return 0;
>> >> >>  }
>> >> >>
>> >> >>  int odp_pktio_pmr_match_set_cos(odp_pmr_set_t pmr_set_id, odp_pktio_t
>> >> >> src_pktio,
>> >> >> -                               odp_cos_t dst_cos)
>> >> >> +               odp_cos_t dst_cos)
>> >> >> +{
>> >> >> +       uint8_t num_pmr;
>> >> >> +       pktio_entry_t *pktio_entry;
>> >> >> +       pmr_t *pmr;
>> >> >> +       cos_t *cos;
>> >> >> +
>> >> >> +       pktio_entry = get_pktio_entry(src_pktio);
>> >> >> +       if (pktio_entry == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_pktio_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       pmr = (pmr_t *)get_pmr_set_entry(pmr_set_id);
>> >> >> +       if (pmr == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_pmr_set_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       cos = get_cos_entry(dst_cos);
>> >> >> +       if (cos == NULL) {
>> >> >> +               ODP_ERR("Invalid odp_cos_t handle");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       LOCK(&pktio_entry->s.cls.lock);
>> >> >> +       num_pmr = pktio_entry->s.cls.num_pmr;
>> >> >> +       if (num_pmr >= ODP_PKTIO_MAX_PMR) {
>> >> >> +               ODP_ERR("ODP_PKTIO_MAX_PMR reached");
>> >> >> +               UNLOCK(&pktio_entry->s.cls.lock);
>> >> >> +               return -1;
>> >> >> +       }
>> >> >> +
>> >> >> +       pktio_entry->s.cls.pmr[num_pmr] = pmr;
>> >> >> +       pktio_entry->s.cls.cos[num_pmr] = cos;
>> >> >> +       pktio_entry->s.cls.num_pmr++;
>> >> >> +       UNLOCK(&pktio_entry->s.cls.lock);
>> >> >> +
>> >> >> +       return 0;
>> >> >> +}
>> >> >> +
>> >> >> +int verify_pmr(pmr_t *pmr, uint8_t *pkt_addr, odp_packet_hdr_t
>> >> >> *pkt_hdr)
>> >> >> +{
>> >> >> +       int pmr_failure = 0;
>> >> >> +       int num_pmr;
>> >> >> +       int i;
>> >> >> +       pmr_term_value_t *term_value;
>> >> >> +
>> >> >> +       /* Locking is not required as PMR rules for in-flight packets
>> >> >> +       delivery during a PMR change is indeterminate*/
>> >> >> +
>> >> >> +       if (!pmr->s.valid)
>> >> >> +               return 0;
>> >> >> +       num_pmr = pmr->s.num_pmr;
>> >> >> +
>> >> >> +       /* Iterate through list of PMR Term values in a pmr_t */
>> >> >> +       for (i = 0; i < num_pmr; i++) {
>> >> >> +               term_value = &pmr->s.pmr_term_value[i];
>> >> >> +               switch (term_value->term) {
>> >> >> +               case ODP_PMR_LEN:
>> >> >> +                       if (!verify_pmr_packet_len(pkt_hdr,
>> >> >> term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_ETHTYPE_0:
>> >> >> +                       if (!verify_pmr_eth_type_0(pkt_addr, pkt_hdr,
>> >> >> +                                                  term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_ETHTYPE_X:
>> >> >> +                       if (!verify_pmr_eth_type_x(pkt_addr, pkt_hdr,
>> >> >> +                                                  term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_VLAN_ID_0:
>> >> >> +                       if (!verify_pmr_vlan_id_0(pkt_addr, pkt_hdr,
>> >> >> +                                                 term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_VLAN_ID_X:
>> >> >> +                       if (!verify_pmr_vlan_id_x(pkt_addr, pkt_hdr,
>> >> >> +                                                 term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_DMAC:
>> >> >> +                       if (!verify_pmr_dmac(pkt_addr, pkt_hdr,
>> >> >> +                                            term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_IPPROTO:
>> >> >> +                       if (!verify_pmr_ip_proto(pkt_addr, pkt_hdr,
>> >> >> +                                                term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_UDP_DPORT:
>> >> >> +                       if (!verify_pmr_udp_dport(pkt_addr, pkt_hdr,
>> >> >> +                                                 term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_TCP_DPORT:
>> >> >> +                       if (!verify_pmr_tcp_dport(pkt_addr, pkt_hdr,
>> >> >> +                                                 term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_UDP_SPORT:
>> >> >> +                       if (!verify_pmr_udp_sport(pkt_addr, pkt_hdr,
>> >> >> +                                                 term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_TCP_SPORT:
>> >> >> +                       if (!verify_pmr_tcp_sport(pkt_addr, pkt_hdr,
>> >> >> +                                                 term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_SIP_ADDR:
>> >> >> +                       if (!verify_pmr_ipv4_saddr(pkt_addr, pkt_hdr,
>> >> >> +                                                  term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_DIP_ADDR:
>> >> >> +                       if (!verify_pmr_ipv4_daddr(pkt_addr, pkt_hdr,
>> >> >> +                                                  term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_SIP6_ADDR:
>> >> >> +                       if (!verify_pmr_ipv6_saddr(pkt_addr, pkt_hdr,
>> >> >> +                                                  term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_DIP6_ADDR:
>> >> >> +                       if (!verify_pmr_ipv6_daddr(pkt_addr, pkt_hdr,
>> >> >> +                                                  term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_IPSEC_SPI:
>> >> >> +                       if (!verify_pmr_ipsec_spi(pkt_addr, pkt_hdr,
>> >> >> +                                                 term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_LD_VNI:
>> >> >> +                       if (!verify_pmr_ld_vni(pkt_addr, pkt_hdr,
>> >> >> +                                              term_value))
>> >> >> +                               pmr_failure = 1;
>> >> >> +                       break;
>> >> >> +               case ODP_PMR_INNER_HDR_OFF:
>> >> >> +                       break;
>> >> >> +               }
>> >> >> +
>> >> >> +               if (pmr_failure)
>> >> >> +                       return false;
>> >> >> +       }
>> >> >> +       odp_atomic_inc_u32(&pmr->s.count);
>> >> >> +       return true;
>> >> >> +}
>> >> >> +
>> >> >> +cos_t *match_pmr_cos(cos_t *cos, uint8_t *pkt_addr, pmr_t *pmr,
>> >> >> +                    odp_packet_hdr_t *hdr)
>> >> >> +{
>> >> >> +       cos_t *retcos = NULL;
>> >> >> +
>> >> >> +       if (cos == NULL || pmr == NULL)
>> >> >> +               return NULL;
>> >> >> +
>> >> >> +       if (!cos->s.valid)
>> >> >> +               return NULL;
>> >> >> +
>> >> >> +       if (verify_pmr(pmr, pkt_addr, hdr)) {
>> >> >> +               /** This gets called recursively to check all the PMRs
>> >> >> in
>> >> >> +                * a PMR chain */
>> >> >> +               retcos = match_pmr_cos(cos->s.linked_cos, pkt_addr,
>> >> >> +                                      cos->s.pmr, hdr);
>> >> >> +               if (!retcos)
>> >> >> +                       return cos;
>> >> >> +       }
>> >> >> +       return retcos;
>> >> >> +}
>> >> >> +
>> >> >> +int pktio_classifier_init(pktio_entry_t *entry)
>> >> >>  {
>> >> >> -       (void)pmr_set_id;
>> >> >> -       (void)src_pktio;
>> >> >> -       (void)dst_cos;
>> >> >> -       ODP_UNIMPLEMENTED();
>> >> >> +       classifier_t *cls;
>> >> >> +       int i;
>> >> >> +       /* classifier lock should be acquired by the calling function
>> >> >> */
>> >> >> +       if (entry == NULL)
>> >> >> +               return -1;
>> >> >> +       cls = &entry->s.cls;
>> >> >> +       cls->num_pmr = 0;
>> >> >> +       cls->flow_set = 0;
>> >> >> +       cls->error_cos = NULL;
>> >> >> +       cls->default_cos = NULL;
>> >> >> +       cls->headroom = 0;
>> >> >> +       cls->skip = 0;
>> >> >> +
>> >> >> +       for (i = 0; i < ODP_PKTIO_MAX_PMR; i++) {
>> >> >> +               cls->pmr[i] = NULL;
>> >> >> +               cls->cos[i] = NULL;
>> >> >> +       }
>> >> >> +
>> >> >>         return 0;
>> >> >>  }
>> >> >> +
>> >> >> +int packet_classifier(odp_pktio_t pktio, odp_packet_t pkt)
>> >> >> +{
>> >> >> +       pktio_entry_t *entry;
>> >> >> +       queue_entry_t *queue;
>> >> >> +       cos_t *cos;
>> >> >> +       odp_packet_hdr_t *pkt_hdr;
>> >> >> +       uint8_t *pkt_addr;
>> >> >> +
>> >> >> +       entry = get_pktio_entry(pktio);
>> >> >> +       if (entry == NULL)
>> >> >> +               return -1;
>> >> >> +
>> >> >> +       pkt_hdr = odp_packet_hdr(pkt);
>> >> >> +       pkt_addr = odp_packet_addr(pkt);
>> >> >> +
>> >> >> +       /* Matching PMR and selecting the CoS for the packet*/
>> >> >> +       cos = pktio_select_cos(entry, pkt_addr, pkt_hdr);
>> >> >> +       if (cos == NULL)
>> >> >> +               return -1;
>> >> >> +
>> >> >> +       /* Enqueuing the Packet based on the CoS */
>> >> >> +       queue = cos->s.queue;
>> >> >> +       return queue_enq(queue, odp_buf_to_hdr((odp_buffer_t)pkt));
>> >> >> +}
>> >> >> +
>> >> >> +cos_t *pktio_select_cos(pktio_entry_t *entry, uint8_t *pkt_addr,
>> >> >> +                      odp_packet_hdr_t *pkt_hdr)
>> >> >> +{
>> >> >> +       pmr_t *pmr;
>> >> >> +       cos_t *cos;
>> >> >> +       uint32_t i;
>> >> >> +       classifier_t *cls;
>> >> >> +
>> >> >> +       cls = &entry->s.cls;
>> >> >> +
>> >> >> +       /* Return error cos for error packet */
>> >> >> +       if (pkt_hdr->error_flags.all)
>> >> >> +               return cls->error_cos;
>> >> >> +       /* Calls all the PMRs attached at the PKTIO level*/
>> >> >> +       for (i = 0; i < cls->num_pmr; i++) {
>> >> >> +               pmr = entry->s.cls.pmr[i];
>> >> >> +               cos = entry->s.cls.cos[i];
>> >> >> +               cos = match_pmr_cos(cos, pkt_addr, pmr, pkt_hdr);
>> >> >> +               if (cos)
>> >> >> +                       return cos;
>> >> >> +       }
>> >> >> +
>> >> >> +       cos = match_qos_cos(entry, pkt_addr, pkt_hdr);
>> >> >> +       if (cos)
>> >> >> +               return cos;
>> >> >> +
>> >> >> +       return cls->default_cos;
>> >> >> +}
>> >> >> +
>> >> >> +cos_t *match_qos_l3_cos(pmr_l3_cos_t *l3_cos, uint8_t *pkt_addr,
>> >> >> +                       odp_packet_hdr_t *hdr)
>> >> >> +{
>> >> >> +       uint8_t dscp;
>> >> >> +       cos_t *cos = NULL;
>> >> >> +       odph_ipv4hdr_t *ipv4;
>> >> >> +       odph_ipv6hdr_t *ipv6;
>> >> >> +
>> >> >> +       if (hdr->input_flags.l3 && hdr->input_flags.ipv4) {
>> >> >> +               ipv4 = (odph_ipv4hdr_t *)(pkt_addr + hdr->l3_offset);
>> >> >> +               dscp = ODPH_IPV4HDR_DSCP(ipv4->tos);
>> >> >> +               cos = l3_cos->cos[dscp];
>> >> >> +       } else if (hdr->input_flags.l3 && hdr->input_flags.ipv6) {
>> >> >> +               ipv6 = (odph_ipv6hdr_t *)(pkt_addr + hdr->l3_offset);
>> >> >> +               dscp = ODPH_IPV6HDR_DSCP(ipv6->ver_tc_flow);
>> >> >> +               cos = l3_cos->cos[dscp];
>> >> >> +       }
>> >> >> +
>> >> >> +       return cos;
>> >> >> +}
>> >> >> +
>> >> >> +cos_t *match_qos_l2_cos(pmr_l2_cos_t *l2_cos, uint8_t *pkt_addr,
>> >> >> +                       odp_packet_hdr_t *hdr)
>> >> >> +{
>> >> >> +       uint8_t qos;
>> >> >> +       cos_t *cos = NULL;
>> >> >> +       odph_ethhdr_t *eth;
>> >> >> +       odph_vlanhdr_t *vlan;
>> >> >> +
>> >> >> +       if (hdr->input_flags.l2 && hdr->input_flags.vlan &&
>> >> >> +           hdr->input_flags.eth) {
>> >> >> +               eth = (odph_ethhdr_t *)(pkt_addr + hdr->l2_offset);
>> >> >> +               vlan = (odph_vlanhdr_t *)(&eth->type);
>> >> >> +               qos = ((vlan->tci >> 13) & 0xFF);
>> >> >> +               cos = l2_cos->cos[qos];
>> >> >> +       }
>> >> >> +       return cos;
>> >> >> +}
>> >> >> +
>> >> >> +cos_t *match_qos_cos(pktio_entry_t *entry, uint8_t *pkt_addr,
>> >> >> +                    odp_packet_hdr_t *hdr)
>> >> >> +{
>> >> >> +       classifier_t *cls = &entry->s.cls;
>> >> >> +       pmr_l2_cos_t *l2_cos;
>> >> >> +       pmr_l3_cos_t *l3_cos;
>> >> >> +       cos_t *cos;
>> >> >> +
>> >> >> +       l2_cos = &cls->l2_cos_table;
>> >> >> +       l3_cos = &cls->l3_cos_table;
>> >> >> +
>> >> >> +       if (cls->l3_precedence) {
>> >> >> +               cos =  match_qos_l3_cos(l3_cos, pkt_addr, hdr);
>> >> >> +               if (cos)
>> >> >> +                       return cos;
>> >> >> +               cos = match_qos_l2_cos(l2_cos, pkt_addr, hdr);
>> >> >> +               if (cos)
>> >> >> +                       return cos;
>> >> >> +       } else {
>> >> >> +               cos = match_qos_l2_cos(l2_cos, pkt_addr, hdr);
>> >> >> +               if (cos)
>> >> >> +                       return cos;
>> >> >> +               cos = match_qos_l3_cos(l3_cos, pkt_addr, hdr);
>> >> >> +               if (cos)
>> >> >> +                       return cos;
>> >> >> +       }
>> >> >> +       return NULL;
>> >> >> +}
>> >> >> diff --git a/platform/linux-generic/odp_init.c
>> >> >> b/platform/linux-generic/odp_init.c
>> >> >> index 672b3d6..c661231 100644
>> >> >> --- a/platform/linux-generic/odp_init.c
>> >> >> +++ b/platform/linux-generic/odp_init.c
>> >> >> @@ -54,6 +54,10 @@ int odp_init_global(odp_init_t *params  ODP_UNUSED,
>> >> >>                 ODP_ERR("ODP crypto init failed.\n");
>> >> >>                 return -1;
>> >> >>         }
>> >> >> +       if (odp_classification_init_global()) {
>> >> >> +               ODP_ERR("ODP crypto init failed.\n");
>> >> >> +               return -1;
>> >> >> +       }
>> >> >>
>> >> >>         return 0;
>> >> >>  }
>> >> >> diff --git a/platform/linux-generic/odp_packet_io.c
>> >> >> b/platform/linux-generic/odp_packet_io.c
>> >> >> index 19b9eea..6bda003 100644
>> >> >> --- a/platform/linux-generic/odp_packet_io.c
>> >> >> +++ b/platform/linux-generic/odp_packet_io.c
>> >> >> @@ -13,10 +13,10 @@
>> >> >>  #include <odp_spinlock.h>
>> >> >>  #include <odp_shared_memory.h>
>> >> >>  #include <odp_packet_socket.h>
>> >> >> -#include <odp_hints.h>
>> >> >>  #include <odp_config.h>
>> >> >>  #include <odp_queue_internal.h>
>> >> >>  #include <odp_schedule_internal.h>
>> >> >> +#include <odp_classification_internal.h>
>> >> >>  #include <odp_debug_internal.h>
>> >> >>
>> >> >>  #include <string.h>
>> >> >> @@ -50,6 +50,7 @@ int odp_pktio_init_global(void)
>> >> >>                 pktio_entry = &pktio_tbl->entries[id - 1];
>> >> >>
>> >> >>                 odp_spinlock_init(&pktio_entry->s.lock);
>> >> >> +               odp_spinlock_init(&pktio_entry->s.cls.lock);
>> >> >>
>> >> >>                 pktio_entry_ptr[id - 1] = pktio_entry;
>> >> >>                 /* Create a default output queue for each pktio
>> >> >> resource
>> >> >> */
>> >> >> @@ -98,12 +99,25 @@ static void unlock_entry(pktio_entry_t *entry)
>> >> >>         odp_spinlock_unlock(&entry->s.lock);
>> >> >>  }
>> >> >>
>> >> >> +static void lock_entry_classifier(pktio_entry_t *entry)
>> >> >> +{
>> >> >> +       odp_spinlock_lock(&entry->s.lock);
>> >> >> +       odp_spinlock_lock(&entry->s.cls.lock);
>> >> >> +}
>> >> >> +
>> >> >> +static void unlock_entry_classifier(pktio_entry_t *entry)
>> >> >> +{
>> >> >> +       odp_spinlock_unlock(&entry->s.cls.lock);
>> >> >> +       odp_spinlock_unlock(&entry->s.lock);
>> >> >> +}
>> >> >> +
>> >> >>  static void init_pktio_entry(pktio_entry_t *entry)
>> >> >>  {
>> >> >>         set_taken(entry);
>> >> >>         entry->s.inq_default = ODP_QUEUE_INVALID;
>> >> >>         memset(&entry->s.pkt_sock, 0, sizeof(entry->s.pkt_sock));
>> >> >>         memset(&entry->s.pkt_sock_mmap, 0,
>> >> >> sizeof(entry->s.pkt_sock_mmap));
>> >> >> +       pktio_classifier_init(entry);
>> >> >>  }
>> >> >>
>> >> >>  static odp_pktio_t alloc_lock_pktio_entry(void)
>> >> >> @@ -115,13 +129,13 @@ static odp_pktio_t alloc_lock_pktio_entry(void)
>> >> >>         for (i = 0; i < ODP_CONFIG_PKTIO_ENTRIES; ++i) {
>> >> >>                 entry = &pktio_tbl->entries[i];
>> >> >>                 if (is_free(entry)) {
>> >> >> -                       lock_entry(entry);
>> >> >> +                       lock_entry_classifier(entry);
>> >> >>                         if (is_free(entry)) {
>> >> >>                                 init_pktio_entry(entry);
>> >> >>                                 id = i + 1;
>> >> >>                                 return id; /* return with entry locked!
>> >> >> */
>> >> >>                         }
>> >> >> -                       unlock_entry(entry);
>> >> >> +                       unlock_entry_classifier(entry);
>> >> >>                 }
>> >> >>         }
>> >> >>
>> >> >> @@ -190,14 +204,14 @@ odp_pktio_t odp_pktio_open(const char *dev,
>> >> >> odp_buffer_pool_t pool)
>> >> >>                 close_pkt_sock(&pktio_entry->s.pkt_sock);
>> >> >>         }
>> >> >>
>> >> >> -       unlock_entry(pktio_entry);
>> >> >> +       unlock_entry_classifier(pktio_entry);
>> >> >>         free_pktio_entry(id);
>> >> >>         ODP_ERR("Unable to init any I/O type.\n");
>> >> >>         return ODP_PKTIO_INVALID;
>> >> >>
>> >> >>  done:
>> >> >>         strncpy(pktio_entry->s.name, dev, IFNAMSIZ);
>> >> >> -       unlock_entry(pktio_entry);
>> >> >> +       unlock_entry_classifier(pktio_entry);
>> >> >>         return id;
>> >> >>  }
>> >> >>
>> >> >> @@ -415,7 +429,7 @@ odp_buffer_hdr_t *pktin_dequeue(queue_entry_t
>> >> >> *qentry)
>> >> >>         odp_buffer_t buf;
>> >> >>         odp_packet_t pkt_tbl[QUEUE_MULTI_MAX];
>> >> >>         odp_buffer_hdr_t *tmp_hdr_tbl[QUEUE_MULTI_MAX];
>> >> >> -       int pkts, i;
>> >> >> +       int pkts, i, j;
>> >> >>
>> >> >>         buf_hdr = queue_deq(qentry);
>> >> >>         if (buf_hdr != NULL)
>> >> >> @@ -425,12 +439,15 @@ odp_buffer_hdr_t *pktin_dequeue(queue_entry_t
>> >> >> *qentry)
>> >> >>         if (pkts <= 0)
>> >> >>                 return NULL;
>> >> >>
>> >> >> -       for (i = 0; i < pkts; ++i) {
>> >> >> +       for (i = 0, j = 0; i < pkts; ++i) {
>> >> >>                 buf = odp_packet_to_buffer(pkt_tbl[i]);
>> >> >> -               tmp_hdr_tbl[i] = odp_buf_to_hdr(buf);
>> >> >> +               buf_hdr = odp_buf_to_hdr(buf);
>> >> >> +               if (0 > packet_classifier(qentry->s.pktin, pkt_tbl[i]))
>> >>
>> >> For linux-generic does it make sense to classify packets in poll-mode
>> >> operation? I.e. odp_pktio_recv?
>> >>
>> >> >> +                       tmp_hdr_tbl[j++] = buf_hdr;
>> >> >>         }
>> >> >>
>> >> >> -       queue_enq_multi(qentry, tmp_hdr_tbl, pkts);
>> >> >> +       if (j)
>> >> >> +               queue_enq_multi(qentry, tmp_hdr_tbl, j);
>> >> >>         buf_hdr = tmp_hdr_tbl[0];
>> >> >>         return buf_hdr;
>> >> >>  }
>> >> >> @@ -446,8 +463,9 @@ int pktin_deq_multi(queue_entry_t *qentry,
>> >> >> odp_buffer_hdr_t *buf_hdr[], int num)
>> >> >>         int nbr;
>> >> >>         odp_packet_t pkt_tbl[QUEUE_MULTI_MAX];
>> >> >>         odp_buffer_hdr_t *tmp_hdr_tbl[QUEUE_MULTI_MAX];
>> >> >> +       odp_buffer_hdr_t *tmp_hdr;
>> >> >>         odp_buffer_t buf;
>> >> >> -       int pkts, i;
>> >> >> +       int pkts, i, j;
>> >> >>
>> >> >>         nbr = queue_deq_multi(qentry, buf_hdr, num);
>> >> >>         if (odp_unlikely(nbr > num))
>> >> >> @@ -464,12 +482,15 @@ int pktin_deq_multi(queue_entry_t *qentry,
>> >> >> odp_buffer_hdr_t *buf_hdr[], int num)
>> >> >>         if (pkts <= 0)
>> >> >>                 return nbr;
>> >> >>
>> >> >> -       for (i = 0; i < pkts; ++i) {
>> >> >> +       for (i = 0, j = 0; i < pkts; ++i) {
>> >> >>                 buf = odp_packet_to_buffer(pkt_tbl[i]);
>> >> >> -               tmp_hdr_tbl[i] = odp_buf_to_hdr(buf);
>> >> >> +               tmp_hdr = odp_buf_to_hdr(buf);
>> >> >> +               if (0 > packet_classifier(qentry->s.pktin, pkt_tbl[i]))
>> >> >> +                       tmp_hdr_tbl[j++] = tmp_hdr;
>> >> >>         }
>> >> >>
>> >> >> -       queue_enq_multi(qentry, tmp_hdr_tbl, pkts);
>> >> >> +       if (j)
>> >> >> +               queue_enq_multi(qentry, tmp_hdr_tbl, j);
>> >> >>         return nbr;
>> >> >>  }
>> >> >>
>> >> >> --
>> >> >> 2.0.1.472.g6f92e5f
>> >> >>
>> >> >>
>> >> >> _______________________________________________
>> >> >> lng-odp mailing list
>> >> >> lng-odp@lists.linaro.org
>> >> >> http://lists.linaro.org/mailman/listinfo/lng-odp
>> >> >
>> >> >
>> >> >
>> >> > _______________________________________________
>> >> > lng-odp mailing list
>> >> > lng-odp@lists.linaro.org
>> >> > http://lists.linaro.org/mailman/listinfo/lng-odp
>> >> >
>> >
>> >

_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to