diff mbox

[v6,3/3] linux-generic: classification initial implementation

Message ID 1418040176-9134-3-git-send-email-bala.manoharan@linaro.org
State Accepted
Commit 5b0cb951dc3d9732496cb7d18cd0c9fe5d6375c6
Headers show

Commit Message

Balasubramanian Manoharan Dec. 8, 2014, 12:02 p.m. UTC
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.manoharan@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

Comments

Bill Fischofer Dec. 9, 2014, 2:23 a.m. UTC | #1
On Mon, Dec 8, 2014 at 6:02 AM, Balasubramanian Manoharan <
bala.manoharan@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.manoharan@linaro.org>
>

Reviewed-by: Bill Fischofer <bill.fischofer@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]))
> +                       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
>
Ciprian Barbu Dec. 9, 2014, 4:47 p.m. UTC | #2
I have one question that just came to me. See below.

On Tue, Dec 9, 2014 at 4:23 AM, Bill Fischofer
<bill.fischofer@linaro.org> wrote:
>
>
> On Mon, Dec 8, 2014 at 6:02 AM, Balasubramanian Manoharan
> <bala.manoharan@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.manoharan@linaro.org>
>
>
> Reviewed-by: Bill Fischofer <bill.fischofer@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
>
Bill Fischofer Dec. 9, 2014, 5:53 p.m. UTC | #3
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.

On Tue, Dec 9, 2014 at 10:47 AM, Ciprian Barbu <ciprian.barbu@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.fischofer@linaro.org> wrote:
> >
> >
> > On Mon, Dec 8, 2014 at 6:02 AM, Balasubramanian Manoharan
> > <bala.manoharan@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.manoharan@linaro.org>
> >
> >
> > Reviewed-by: Bill Fischofer <bill.fischofer@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
> >
>
Ciprian Barbu Dec. 10, 2014, 10:54 a.m. UTC | #4
On Tue, Dec 9, 2014 at 7:53 PM, Bill Fischofer
<bill.fischofer@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.

>
> On Tue, Dec 9, 2014 at 10:47 AM, Ciprian Barbu <ciprian.barbu@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.fischofer@linaro.org> wrote:
>> >
>> >
>> > On Mon, Dec 8, 2014 at 6:02 AM, Balasubramanian Manoharan
>> > <bala.manoharan@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.manoharan@linaro.org>
>> >
>> >
>> > Reviewed-by: Bill Fischofer <bill.fischofer@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
>> >
>
>
Balasubramanian Manoharan Dec. 10, 2014, 12:03 p.m. UTC | #5
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.fischofer@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. 
> >
> > On Tue, Dec 9, 2014 at 10:47 AM, Ciprian Barbu <ciprian.barbu@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.fischofer@linaro.org> wrote:
> >> >
> >> >
> >> > On Mon, Dec 8, 2014 at 6:02 AM, Balasubramanian Manoharan
> >> > <bala.manoharan@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.manoharan@linaro.org>
> >> >
> >> >
> >> > Reviewed-by: Bill Fischofer <bill.fischofer@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
> >> >
> >
> >
Ciprian Barbu Dec. 10, 2014, 12:46 p.m. UTC | #6
On Wed, Dec 10, 2014 at 2:03 PM, Bala Manoharan
<bala.manoharan@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.fischofer@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.barbu@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.fischofer@linaro.org> wrote:
>> >> >
>> >> >
>> >> > On Mon, Dec 8, 2014 at 6:02 AM, Balasubramanian Manoharan
>> >> > <bala.manoharan@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.manoharan@linaro.org>
>> >> >
>> >> >
>> >> > Reviewed-by: Bill Fischofer <bill.fischofer@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
>> >> >
>> >
>> >
Balasubramanian Manoharan Dec. 10, 2014, 1:03 p.m. UTC | #7
On Wed, Dec 10, 2014 at 02:46:34PM +0200, Ciprian Barbu wrote:
> On Wed, Dec 10, 2014 at 2:03 PM, Bala Manoharan
> <bala.manoharan@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.fischofer@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.
>
Classification is mainly required for distributing the incoming packets to multiple queues based
on configured classification rules so as to enforce QoS, priority etc from the application
point of view. But if you are receiving the packet using odp_pktio_recv there is no need for classification
as you have already received the packet at the application. 
> >> >
> >> > On Tue, Dec 9, 2014 at 10:47 AM, Ciprian Barbu <ciprian.barbu@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.fischofer@linaro.org> wrote:
> >> >> >
> >> >> >
> >> >> > On Mon, Dec 8, 2014 at 6:02 AM, Balasubramanian Manoharan
> >> >> > <bala.manoharan@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.manoharan@linaro.org>
> >> >> >
> >> >> >
> >> >> > Reviewed-by: Bill Fischofer <bill.fischofer@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
> >> >> >
> >> >
> >> >
Bill Fischofer Dec. 10, 2014, 7:01 p.m. UTC | #8
Ciprian, in SoCs the parser/classifier is integrated into the MACs and
happens at line rate while the packets are coming off the wire and still in
the HW receive FIFOs.  This is necessary so that classifier can select the
target buffer pool info to feed to the receive buffer allocator and DMA
engines so that the packets get stored in the correct memory area.  For PCI
based systems the same is done by the "intelligent NICs" that DPDK talks
to.  They parse and classify incoming packets and then distribute them to
the correct host receive ring based on the results of this.  However, they
are typically not terribly programmable in this regard, just implementing
standards like Microsoft RSS, or perhaps have some limited configuration
capability.

Obviously not something that we can mimic in Linux generic without a lot of
extraneous overhead.  To do what HW does you'd have to receive the packet
into a dedicated receive area, parse and classify it, and then recopy it
into the correct buffer pool.  The extra data copying would be prohibitive
in this case.


On Wed, Dec 10, 2014 at 7:03 AM, Bala Manoharan <bala.manoharan@linaro.org>
wrote:

> On Wed, Dec 10, 2014 at 02:46:34PM +0200, Ciprian Barbu wrote:
> > On Wed, Dec 10, 2014 at 2:03 PM, Bala Manoharan
> > <bala.manoharan@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.fischofer@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.
> >
> Classification is mainly required for distributing the incoming packets to
> multiple queues based
> on configured classification rules so as to enforce QoS, priority etc from
> the application
> point of view. But if you are receiving the packet using odp_pktio_recv
> there is no need for classification
> as you have already received the packet at the application.
> > >> >
> > >> > On Tue, Dec 9, 2014 at 10:47 AM, Ciprian Barbu <
> ciprian.barbu@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.fischofer@linaro.org> wrote:
> > >> >> >
> > >> >> >
> > >> >> > On Mon, Dec 8, 2014 at 6:02 AM, Balasubramanian Manoharan
> > >> >> > <bala.manoharan@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.manoharan@linaro.org>
> > >> >> >
> > >> >> >
> > >> >> > Reviewed-by: Bill Fischofer <bill.fischofer@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
>
diff mbox

Patch

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]))
+			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;
 }