diff mbox

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

Message ID 1417838383-3215-3-git-send-email-bala.manoharan@linaro.org
State New
Headers show

Commit Message

Balasubramanian Manoharan Dec. 6, 2014, 3:59 a.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>
---
 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        | 878 +++++++++++++++++++--
 platform/linux-generic/odp_init.c                  |   4 +
 platform/linux-generic/odp_packet_io.c             |  47 +-
 12 files changed, 1493 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

Balasubramanian Manoharan Dec. 6, 2014, 4:16 a.m. UTC | #1
These patches are available in the following public repo

http://git.linaro.org/people/bala.manoharan/classification.git

Regards,
Bala

On 6 December 2014 at 09:29, 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>
> ---
>  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        | 878
> +++++++++++++++++++--
>  platform/linux-generic/odp_init.c                  |   4 +
>  platform/linux-generic/odp_packet_io.c             |  47 +-
>  12 files changed, 1493 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..e3c4bf7 100644
> --- a/platform/linux-generic/odp_classification.c
> +++ b/platform/linux-generic/odp_classification.c
> @@ -1,69 +1,318 @@
> +/* 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");
> +               return -1;
> +       }
> +
> +       cos_tbl = odp_shm_addr(cos_shm);
> +       if (cos_tbl == NULL) {
> +               odp_shm_free(cos_shm);
> +               return -1;
> +       }
> +
> +       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");
> +               return -1;
> +       }
> +
> +       pmr_tbl = odp_shm_addr(pmr_shm);
> +       if (pmr_tbl == NULL) {
> +               odp_shm_free(pmr_shm);
> +               return -1;
> +       }
> +
> +       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");
> +               return -1;
> +       }
> +
> +       pmr_set_tbl = odp_shm_addr(pmr_set_shm);
> +       if (pmr_set_tbl == NULL) {
> +               odp_shm_free(pmr_set_shm);
> +               return -1;
> +       }
> +
> +       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;
>  }
>
> +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 intermitted 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 +321,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 +350,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 +381,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_DBG();
> +               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 +409,34 @@ 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)
> +               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 +444,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 intermitted 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)
>  {
> -       (void)pmr_set_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 = (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)
> +{
> +       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
>
>
Bill Fischofer Dec. 8, 2014, 2:35 a.m. UTC | #2
General comments:

This patch will conflict with the buffer pool patch I posted this evening,
because we're both moving the same things from odp_buffer_pool.c to
odp_buffer_pool_internal.h.  Whichever gets merged first the other can do
the very trivial fixup to resolve the conflict.

Aside from a few minor comments (see below).  This looks good.

Bill

On Fri, Dec 5, 2014 at 9:59 PM, 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>
> ---
>  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        | 878
> +++++++++++++++++++--
>  platform/linux-generic/odp_init.c                  |   4 +
>  platform/linux-generic/odp_packet_io.c             |  47 +-
>  12 files changed, 1493 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..e3c4bf7 100644
> --- a/platform/linux-generic/odp_classification.c
> +++ b/platform/linux-generic/odp_classification.c
> @@ -1,69 +1,318 @@
> +/* 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");
> +               return -1;
> +       }
> +
> +       cos_tbl = odp_shm_addr(cos_shm);
> +       if (cos_tbl == NULL) {
> +               odp_shm_free(cos_shm);
> +               return -1;
> +       }
> +
> +       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");
> +               return -1;
> +       }
> +
>

Good you're doing the step-by-step checks here, but if the first
odp_shm_reserve() call succeeds and the second one fails, you exit without
doing an odp_shm_free() for the first one, so it's now lost.  Similar
problem with chaining the reserves/frees as you step through this routine.
For robustness, you need to back out all of the prior successful
reservations when you detect a later error.


> +       pmr_tbl = odp_shm_addr(pmr_shm);
> +       if (pmr_tbl == NULL) {
> +               odp_shm_free(pmr_shm);
> +               return -1;
> +       }
> +
> +       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");
> +               return -1;
> +       }
> +
> +       pmr_set_tbl = odp_shm_addr(pmr_set_shm);
> +       if (pmr_set_tbl == NULL) {
> +               odp_shm_free(pmr_set_shm);
> +               return -1;
> +       }
> +
> +       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;
>  }
>
> +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 intermitted stale
> +       data during CoS modification is acceptable*/
>

Typo: intermitted.  I assume either intermediate or intermittent?


> +       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 +321,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 +350,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 +381,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_DBG();
>

Is the null ODP_DBG() intentional here?  Looks odd.  Vestigial from some
debugging, perhaps?


> +               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 +409,34 @@ 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)
> +               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 +444,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 intermitted 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)
>  {
> -       (void)pmr_set_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 = (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)
> +{
> +       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
>
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..e3c4bf7 100644
--- a/platform/linux-generic/odp_classification.c
+++ b/platform/linux-generic/odp_classification.c
@@ -1,69 +1,318 @@ 
+/* 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");
+		return -1;
+	}
+
+	cos_tbl = odp_shm_addr(cos_shm);
+	if (cos_tbl == NULL) {
+		odp_shm_free(cos_shm);
+		return -1;
+	}
+
+	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");
+		return -1;
+	}
+
+	pmr_tbl = odp_shm_addr(pmr_shm);
+	if (pmr_tbl == NULL) {
+		odp_shm_free(pmr_shm);
+		return -1;
+	}
+
+	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");
+		return -1;
+	}
+
+	pmr_set_tbl = odp_shm_addr(pmr_set_shm);
+	if (pmr_set_tbl == NULL) {
+		odp_shm_free(pmr_set_shm);
+		return -1;
+	}
+
+	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;
 }
 
+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 intermitted 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 +321,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 +350,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 +381,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_DBG();
+		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 +409,34 @@  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)
+		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 +444,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 intermitted 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)
 {
-	(void)pmr_set_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 = (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)
+{
+	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;
 }