diff mbox

[ARCH,PATCHv3] Publish ODP Classification Design to Git

Message ID 1407242870-16785-1-git-send-email-bill.fischofer@linaro.org
State New
Headers show

Commit Message

Bill Fischofer Aug. 5, 2014, 12:47 p.m. UTC
Further sentence split cleanup.

Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>
---
 classification_design.dox      | 899 +++++++++++++++++++++++++++++++++++++++++
 images/classification_flow.png | Bin 0 -> 35193 bytes
 2 files changed, 899 insertions(+)
 create mode 100644 classification_design.dox
 create mode 100644 images/classification_flow.png

diff --git a/images/classification_flow.png b/images/classification_flow.png
new file mode 100644
index 0000000000000000000000000000000000000000..2d94ff64ec772aa97f3687181c121fb91d671889
GIT binary patch
literal 35193
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
Ru|ekbQbt9(O42mw{{YqNUv2;Z

literal 0
HcmV?d00001

Comments

Mike Holmes Aug. 5, 2014, 1:58 p.m. UTC | #1
Sentences look good, I found one more issue we don't have an .eps version
of the classification_flow.png for the pdf version of the doc.




On 5 August 2014 08:47, Bill Fischofer <bill.fischofer@linaro.org> wrote:

> Further sentence split cleanup.
>
> Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>
> ---
>  classification_design.dox      | 899
> +++++++++++++++++++++++++++++++++++++++++
>  images/classification_flow.png | Bin 0 -> 35193 bytes
>  2 files changed, 899 insertions(+)
>  create mode 100644 classification_design.dox
>  create mode 100644 images/classification_flow.png
>
> diff --git a/classification_design.dox b/classification_design.dox
> new file mode 100644
> index 0000000..170a1ef
> --- /dev/null
> +++ b/classification_design.dox
> @@ -0,0 +1,899 @@
> +/* Copyright (c) 2014, Linaro Limited
> + * All rights reserved
> + *
> + * SPDX-License-Identifier:     BSD-3-Clause
> + */
> +
> +/*!
> +@page classification_design ODP Design - Classification API
> +For the implementation of the ODP classification API please see @ref
> odp_classify.h
> +
> +@tableofcontents
> +
> +@section introduction Introduction
> +This document defines the Classification APIs supported by ODP v1.0.
> +Classification is logically composed of two stages: Parsing and Rule
> Matching.
> +Parsing takes a raw packet and validates its structure and identifies
> fields of interest in the various headers that comprise the layers of the
> packet.
> +Rule Matching, in turn, takes the result of parsing and sorts packets
> into Classes of Service (CoS) based on application-defined rule sets.
> +@subsection use_of_terms Use of Terms
> +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
> "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
> document are to be interpreted as described in [RFC 2119](
> https://tools.ietf.org/html/rfc21199).
> +@subsection purpose Purpose
> +ODP is a framework for software-based packet forwarding/filtering
> applications, and the purpose of the Packet Classifier API is to enable
> applications to program the platform hardware or software implementation to
> assist in prioritization, classification and scheduling of each packet, so
> that the software application can run faster, scale better and adhere to
> QoS requirements.
> +The following API abstraction are not modelled after any existing product
> implementation, but is instead defined in terms of what a typical
> data-plane application may require from such a platform, without
> sacrificing simplicity and avoiding ambiguity.
> +Certain terms that are being used within the context of existing products
> in relation to packet parsing and classification, such as “access lists”
> are avoided such that not to suggest any relationship between the
> abstraction used within this API and any particular manner in which they
> may be implemented in hardware.
> +These are the key ODP objects that the parser needs to employ, that are
> presently defined in ODP:
> +@subsubsection odp_pktio odp_pktio
> +odp_pktio specifies an individual packet I/O channel instance.
> +In other words, it would translate to a physical interface or a logical
> port, or in the case of channelized protocols (e.g., [Interlaken](
> https://www.google.com/url?q=https%3A%2F%2Fwww.cortina-systems.com%2Fimages%2Fdocuments%2F400023_Interlaken_Technology_White_Paper.pdf&sa=D&sntz=1&usg=AFQjCNEBdJTBmA1XaNGY3pmumQTfgSi1oA))
> it would map to a logical channel on that interface.
> +Since the classifier API deals exclusively with ingress, this object
> represents the source of packets into the classifier.
> +In order to support any non-trivial use case, the classifier API needs to
> be able to assign multiple odp_queue instances for any single odp_pktio
> object, and may also assign any odp_queue instance to more than one
> odp_pktio object.
> +@subsubsection odp_queue odp_queue
> +odp_queue specifies a logical queue for packets, and in the case of
> ingress, this would represent a stream of packets which share several
> attributes, that are delivered to the ODP application for processing.
> +The per-queue attributes currently defined are: queue type, sync
> (ordering); priority; and schedule group (set of processor cores).
> +@subsubsection odp_buffer_pool odp_buffer_pool
> +odp_buffer_pool specifies a collection of buffers of same size and
> alignment, as well as a set of policies such as flow control and processor
> affinity.
> +The classifier API refers to such pools that are designated for storing
> ingress packets.
> +@section functional_description Functional Description
> +Following is the functionality that is required of the classifier API,
> and its underlying implementation.
> +The details and order of the following paragraph is informative, and is
> only intended to help convey the functional scope of a classifier and
> provide context for the API.
> +In reality, implementations may execute many of these steps concurrently,
> or in different order while maintaining the evident dependencies:
> +
> +-# Apply a set of \e classification \e rules to the header of an incoming
> packet, identify the header fields, e.g., \e ethertype, IP version, IP
> protocol, transport layer port numbers, IP DiffServ, VLAN id, 802.1p
> priority.
> +
> +-# Store these fields as packet meta data for application use, and for
> the remainder of parser operations.
> +The \e odp_pktio is also stored as one of the meta data fields for
> subsequent use.
> +
> +-# Compute an \e odp_cos (Class of Service) value from a subset of
> supported fields from 1) above.
> +
> +
> +-# Based on the \e odp_cos from 3) above, select the \e odp_queue through
> which the packet is delivered to the application.
> +
> +-# Validate the packet data integrity (checksums, FCS)  and correctness
> (e.g., length fields) and store the validation result, along with optional
> error layer and type indicator, in packet meta data.
> +Optionally, if a packet fails validation, override the \e odp_cos
> selection in step 3 to a class of service designated for errored packets.
> +
> +-# Since the selected \e odp_queue may require preservation of packet
> order, i.e., SYNC_ATOMIC or SYNC_ORDERED, optionally select the packet
> header fields from which the parser calculates a \e odp_flow_signature,
> which may be a unique flow identifier or a hash, such that the packets
> which are assigned the same \e odp_flow_signature are scheduled in the same
> order they are received.
> +
> +-# Based on the \e odp_cos from 3) above, select the \e odp_buffer_pool
> that should be used to acquire a buffer to store the packet data and meta
> data.
> +
> +-# Allocate a buffer from \e odp_buffer_pool selected in 6) above and
> logically store the packet data and meta data to the allocated buffer, or
> in accordance with class-of-service drop policy and subject to pool buffer
> availability, optionally discard the packet.
> +
> +-# Enqueue the buffer into the \e odp_queue selected in 4) above.
> +
> +The above is an abstract description of the classifier functionality, and
> may be applied to a variety of applications in many different ways.
> +The ultimate meaning of how this functionality applies to an application
> also depends on other ODP modules, so the above may not complete a full
> depiction.
> +For instance, the exact meaning of \e priority, which is a per-queue
> attribute is influenced by the ODP scheduler semantics, and the system
> behavior under stress depends on the ODP buffer pool module behavior.
> +
> +For the sole purpose of illustrating the above abstract functionality,
> here is an example of a Layer-2 (IEEE 802.1D) bridge application:
> +Such a forwarding application that also adheres to IEEE 802.1p/q
> priority, which has 8 traffic priority levels, might create 8 \e
> odp_buffer_pool instances, one for each PCP priority level, and 8 \e
> odp_queue instances one per priority level.
> +Incoming packets will be inspected for a VLAN header; the PCP field will
> be extracted, and used to select both the pool and the queue.
> +Because each queue will be assigned a priority value, the packets with
> highest PCP values will be scheduled before any packet with a lower PCP
> value.
> +Also, in a case of congestion, buffer pools for lower priority packets
> will be depleted earlier than the pools containing packets of the high
> priority, and hence the lower priority packets will be dropped (assuming
> that is the only flow control method that is supported in the platform)
> while higher priority packets will continue to be received into buffers and
> processed.
> +@subsection flow_diagram Classification Processing Flow Diagram
> +@image html classification_flow.png "Figure 1: Classification Flow
> Diagram"
> +@image latex classification_flow.eps "Figure 1: Classification Flow
> Diagram"
> +
> +@section api_elements API Elements
> +While the above description refers to the abstracted packet classifier,
> the following is the description of the API designed to program the packet
> classifier, and is intended to add clarity to the functions provided
> further below.
> +@subsection cos_creation Class of Service Creation and Binding
> +To program the classifier, a class-of-service instance must be created,
> which will contain the packet filtering resources that it may require.
> +All subsequent calls refer to one or more of these resources.
> +Each class of service instance must be associated with a single queue or
> queue group, which will be the destination of all packets matching that
> particular filter.
> +The queue assignment is implemented as a separate function call such that
> the queue may be modified at any time, without tearing down the filters
> that define the class of service.
> +In other words, it is possible to change the destination queue for a
> class of service defined by its filters quickly and dynamically.
> +Optionally, on platforms that support multiple packet buffer pools, each
> class of service may be assigned a different pool such that when buffers
> are exhausted for one class of service, other classes are not negatively
> impacted and continue to be processed.
> +
> +@subsection default_packet_handling Default packet handling
> +There SHOULD be one \b odp_cos assigned to each port with the \c
> odp_cos_pktio_set()  function,  which will function as the default
> class-of-service for all packets received from an ingress port, that do not
> match any of the filters defined subsequently.
> +At minimum this default class-of-service MUST have a queue and a buffer
> pool assigned to it on platforms that support multiple packet buffer pools.
> +Multiple odp_pktio instances (i.e., multiple ports) MAY each have their
> own default odp_cos, or MAY share a odp_cos with other ports, based on
> application requirements.
> +
> +@subsection packet_classification Packet Classification
> +For each odp_pktio port, the API allows the assignment of a
> class-of-service to a packet using one of  three methods:
> +
> +-# The packet may be assigned a specific class-of-service based on its
> Layer-2 (802.1P/902.1Q VLAN tag) priority field.
> +Since the standard field defines 8 discrete priority levels, the API
> allows to assign an odp_cos to each of these priority levels with the \c
> odp_cos_with_l2_priority() function.
> +
> +-# Similarly, a class-of-service may be assigned using the Layer-3 (IP
> DiffServ) header field.
> +The application supplies an array of \e odp_cos values that covers the
> entire range of the standard protocol header field, where array elements do
> not need to contain unique values.
> +There is also a need to specify if Layer-3 priority takes precedence over
> Layer-2 priority in a packet with both headers present.
> +
> +-# Additionally, the application may also program a number of \e pattern
> \e matching \e rules that assign a class-of-service for packets with header
> fields matching specified values.
> +The field-matching rules take precedence over the previously described
> priority-based assignment of a class-of-service.
> +Using these matching rules the application should be able for example to
> identify all packets containing VoIP traffic based on the protocol being
> UDP, and a specific destination or source port numbers, and appropriately
> assign these packets an class-of-service that maps to a higher priority
> queue, assuring voice packets a lower and bound latency.
> +
> +@subsection scaling_and_flow Scaling and Flow Discrimination
> +In addition to classifying packets and routing them to those queues with
> the appropriate priority, and optionally limiting their memory consumption
> by designating certain classes of packets to specific buffer pools, the
> classifier API also facilitates the scaling of data-plane application on
> multi-core systems by creating a mechanism to define which packet headers
> need to be combined to result in a value representing a specific packet
> flow.
> +The classifier generates a signature, which can be a checksum or hash of
> arbitrary strength that covers those packet header fields that are
> identified by the application as identifying flows.
> +
> +The \e flow \e signatures that result from hashing are then stored with
> the packet meta data (along with its class-of-service and its ingress \e
> odp_pktio port), and subsequently may be utilized by the implementation of
> a scheduler queue to maintain the order of packets with the same flow
> signature, while allowing packets with different signatures to be processed
> concurrently and independently on different processing cores.
> +
> +@subsection packet_meta_data Packet meta data Elements
> +Here are the specific information elements that SHOULD be stored within
> the packet meta data structure:
> +- Protocol fields that are decoded and extracted by the parsing phase
> +- Flow-signature calculated from a prescribed collection of protocol
> fields
> +- The class-of-service identifier that is selected for the packet
> +- The ingress port identifier
> +- The result of packet validation, including an indication of the type of
> error detected, if any
> +
> +The ODP packet API module SHALL provide accessors for retrieving the
> above meta data fields from the container buffer in an
> implementation-independent manner.
> +
> +@section api_definitions API Definitions
> +@subsection data_types Data Types
> +The following data types are referenced in the API descriptions described
> below.
> +The names are part of the ODP API and MUST be present in any conforming
> implementation, however the type values shown here are illustrative and
> implementations SHOULD either use these or substitute their own type values
> that are appropriate to the underlying platform.
> +
> +@verbatim
> +/**
> + * 'odp_pktio_t' value to indicate any port
> + */
> +#define ODP_PKTIO_ANY         ((odp_pktio_t)~0)
> +
> +
> +/**
> + * 'odp_pktio_t' value to indicate an error
> + */
> +#define ODP_PKTIO_INVALID ((odp_pktio_t)0)
> +
> +
> +/**
> + * Class of service instance type
> + */
> +typedef uint32_t odp_cos_t;
> +
> +
> +/**
> + * flow signature type, only used for packet meta data field.
> + */
> +typedef uint32_t odp_flowsig_t;
> +
> +
> +/**
> + * This value is returned from odp_cos_create() on failure,
> + * May also be used as a “sink” class of service that
> + * results in packets being discarded.
> + */
> +#define ODP_COS_INVALID        ((odp_cos_t)~0)
> +@endverbatim
> +
> +@subsection cos_routines Class of Service Routines
> +Conforming ODP implementations MUST provide the following Classification
> APIs:
> +@subsubsection cos_create odp_cos_create
> +@verbatim
> +/**
> + * Create a class-of-service
> + *
> + * @param  name is a string intended for debugging purposes.
> + *
> + * @return Class of service instance identifier,
> + *         or ODP_COS_INVALID on error.
> + */
> +
> +odp_cos_t odp_cos_create(const char *name);
> +@endverbatim
> +
> +This routine is used to create a class of service that can be the target
> of classifier rules.
> +The number of such classes supported is implementation-defined.
> +Attempts to create more than are supported by the implementation will
> result in an \c ODP_COS_INVALID return and errno being set to \c
> ODP_IMPLEMENTATION_LIMIT.
> +
> +@subsubsection cos_destroy odp_cos_destroy
> +@verbatim
> +/**
> + * Discard a class-of-service along with all its associated resources
> + *
> + * @param cos_id class-of-service instance.
> + *
> + * @return 0 on success, -1 on error.
> + */
> +
> +int odp_cos_destroy(odp_cos_t cos_id);
> +@endverbatim
> +
> +This routine is the bracketing routine for odp_cos_create().
> +It is used to destroy an existing CoS.
> +It is the caller’s responsibility to ensure that no active pattern
> matching rules refer to the CoS prior to calling this routine.
> +Results are unpredictable if this restriction is not met.
> +@subsubsection cos_set_queue odp_cos_set_queue
> +@verbatim
> +/**
> + * Assign a queue for a class-of-service
> + *
> + * @param cos_id   class-of-service instance.
> + *
> + * @param          queue_id is the identifier of a queue where all packets
> + *                 of this specific class of service will be enqueued.
> + *
> + * @return         0 on success, negative error code on failure.
> + */
> +
> +int odp_cos_set_queue(odp_cos_t cos_id, odp_queue_t queue_id);
> +@endverbatim
> +
> +This routine associates a target queue with a CoS such that all packets
> assigned to this CoS will be enqueued to the specified queue_id at the end
> of classification processing.
> +@subsubsection cos_set_queue_group odp_cos_set_queue_group
> +@verbatim
> +/**
> + * Assign a homogenous queue-group to a class-of-service.
> + *
> + * @param cos_id         identifier of class-of-service instance
> + * @param queue_group_id identifier of the queue group to receive packets
> + *                       associated with this class of service.
> + *
> + * @return               0 on success, negative error code on failure.
> + */
> +
> +int odp_cos_set_queue_group(odp_cos_t cos_id, odp_queue_group_t
> queue_group_id);
> +@endverbatim
> +
> +This routine associates a target queue group with a CoS such that all
> packets assigned to this CoS will be distributed to the specified
> queue_group_id at the end of classification processing.
> +@subsubsection cos_set_pool odp_cos_set_pool
> +@verbatim
> +/**
> + * Assign packet buffer pool for specific class-of-service
> + *
> + * @param cos_id  class-of-service instance.
> + * @param pool_id is a buffer pool identifier where all packet buffers
> + *                will be sourced to store packet that belong to this
> + *                class of service.
> + *
> + * @return        0 on success negative error code on failure.
> + *
> + *
> + */
> +
> +int odp_cos_set_pool(odp_cos_t cos_id, odp_buffer_pool_t pool_id);
> +@endverbatim
> +
> +This OPTIONAL routine associates a target buffer pool with a CoS such
> that all packets assigned to this CoS will be stored in packet buffers
> allocated from the designated pool_id.
> +
> +
> +@subsection cos_drop_policy Class of Service Drop Policy Routines
> +These routines control how drop policies are to be observed for a given
> class of service.
> +@subsubsection drop_data_types Data types
> +~~~~~{.c}
> +enum odp_cos_drop_e {
> +        ODP_COS_DROP_POOL,        /**< Follow buffer pool drop policy */
> +        ODP_COS_DROP_NEVER,       /**< Never drop, ignoring buffer pool
> policy */
> +};
> +typedef enum odp_drop_e odp_drop_t;
> +~~~~~
> +
> +@subsubsection cos_set_drop odp_cos_set_drop
> +@verbatim
> +/**
> + * Assign packet drop policy for specific class-of-service
> + *
> + * @param   cos_id class-of-service instance.
> + * @param   drop_policy is the desired packet drop policy for this class.
> + *
> + * @return  0 on success negative error code on failure.
> + */
> +
> +int odp_cos_set_drop(odp_cos_t cos_id, odp_drop_t drop_policy);
> +@endverbatim
> +
> +This routine sets the drop policy for a class of service.
> +It is an OPTIONAL routine.
> +If an implementation does not provide this function it MUST supply a
> definition of it that simply returns ODP_FUNCTION_NOT_AVAILABLE.
> +@subsubsection pktio_set_default_cos odp_pktio_set_default_cos
> +@verbatim
> +/**
> + * Setup per-port default class-of-service
> + *
> + * @param   pktio_in ingress port identifier.
> + * @param   default_cos class-of-service set to all packets arriving
> + *          at the 'pktio_in' ingress port, unless overridden by
> subsequent
> + *          header-based filters.
> + *
> + * @return  0 on success negative error code on failure.
> + *
> + *
> + * @note    This may replace the default queue per pktio.
> + */
> +
> +int odp_pktio_set_default_cos(odp_pktio_t pktio_in, odp_cos_t
> default_cos);
> +@endverbatim
> +
> +This routine specifies a default class of service for a given pktio
> instance.
> +Incoming packets on the specified pktio are assigned to this class of
> service if no other pattern matching rule obtains.
> +@subsubsection pktio_set_error_cos odp_pktio_set_error_cos
> +@verbatim
> +/**
> + * Setup per-port error class-of-service
> + *
> + * @param   pktio_in ingress port identifier.
> + * @param   error_cos class-of-service set to all packets arriving
> + *          at the 'pktio_in' ingress port that contain an error.
> + *
> + * @return  0 on success negative error code on failure.
> + */
> +
> +int odp_pktio_set_error_cos(odp_pktio_t pktio_in, odp_cos_t error_cos);
> +@endverbatim
> +
> +This OPTIONAL function assigns a class-of-service used to handle packets
> containing various types of errors.
> +The specific errors types include L2 FCS and optionally L3/L4 checksum
> errors, malformed headers, etc., depending on platform capabilities.
> +The specified error_cos MAY simply discard these packets or deliver them
> via a queue to the application for further processing.
> +@subsubsection pktio_set_skip odp_pktio_set_skip
> +@verbatim
> +/**
> + * Setup per-port header offset
> + *
> + * @param   pktio_in ingress port identifier.
> + * @param   offset is the number of bytes the classifier must skip.
> + *
> + * @return  Success or ODP_FUNCTION_NOT_AVAILABLE
> + */
> +
> +int odp_pktio_set_skip(odp_pktio_t pktio_in, size_t offset);
> +@endverbatim
> +
> +This OPTIONAL function applies to ports that carry an additional headers
> preceding the standard Ethernet header.
> +Such headers are typically vendor-specific and thus the classifier is not
> required to parse such headers, but the size of a custom header is critical
> for the classifier to be able to parse standard protocol headers that
> normally follow.
> +@subsubsection cos_set_headroom odp_cos_set_headroom
> +@verbatim
> +/**
> + * Specify per-port buffer headroom
> + *
> + * @param   pktio_in  ingress port identifier.
> + * @param   headroom  number of bytes of space preceding packet data to
> reserve
> + *                    for use as headroom.  Must not exceed the
> implementation
> + *                    defined ODP_PACKET_MAX_HEADROOM.
> + *
> + * @return  Success or ODP_PARAMETER_ERROR,
> + *                  or ODP_FUNCTION_NOT_AVAILABLE
> + */
> +
> +int odp_cos_set_headroom(odp_cos_t cos_id, size_t req_room);
> +@endverbatim
> +
> +This OPTIONAL routine specifies the number of bytes of headroom that
> should be reserved for each packet assigned to this class of service.
> +Each implementation defines an ODP_PACKET_MAX_HEADROOM limit that sets an
> upper bound on the size of the headroom that can be reserved for a packet.
> +@subsubsection cos_with_l2_priority odp_cos_with_l2_priority
> +@verbatim
> +/**
> + * Request to override per-port class of service
> + * based on Layer-2 priority field if present.
> + *
> + * @param   pktio_in ingress port identifier.
> + * @param   num_qos is the number of QoS levels, typically 8.
> + * @param   qos_table are the values of the Layer-2 QoS header field.
> + * @param   cos_table is the class-of-service assigned to each of the
> + *          allowed Layer-2 QOS levels.
> + * @return  0 on success negative error code on failure.
> + */
> +
> +int odp_cos_with_l2_priority(odp_pktio_t pktio_in,
> +                               size_t num_qos,
> +                               uint8_t qos_table[],        /**< 'num_qos'
> elements */
> +                               odp_cos_t cos_table[]);     /**< 'num_qos'
> elements */
> +@endverbatim
> +
> +This routine is used to assign classes of service based on the layer 2
> (L2) priority associated with input packets received on the specified
> pktio_in.
> +For each of the values in qos_table[], the corresponding value in
> cos_table[] will be assigned.
> +@subsubsection cos_with_l3_dscp odp_cos_with_l3_dscp
> +@verbatim
> +/**
> + *
> + * @param   pktio_in ingress port identifier.
> + * @param   num_qos is the number of allowed Layer-3 QoS levels.
> + * @param   qos_table are the values of the Layer-3 QoS header field.
> + * @param   cos_table is the class-of-service assigned to each of the
> + *          allowed Layer-3 QOS levels.
> + * @param   l3_preference when true, Layer-3 QoS overrides L2 QoS when
> present.
> + *
> + * @return  0 on success negative error code on failure.
> + */
> +
> +int odp_cos_with_l3_qos(odp_pktio_t pktio_in,
> +                          size_t num_qos,
> +                          uint8_t qos_table[],        /**< 'num_qos'
> elements */
> +                          odp_cos_t cos_table[],        /**< 'num_qos'
> elements */
> +                          odp_bool_t l3_preference);
> +@endverbatim
> +
> +This OPTIONAL routine is used to assign classes of service based on the
> layer 3 (L3) Differentiated Services (DS) designation.
> +This is the DSCP field of an IPv4 header or the first six bits of the
> Traffic Class of an IPv6 header.
> +For each of the values in qos_table[], the corresponding value in
> cos_table[] will be assigned.
> +The l3_preference flag is use to control whether the CoS assigned by this
> routine takes precedence over the CoS assigned by
> odp_cos_with_l2_priority() in the event that both apply to the same packet.
> +
> +@subsection pmrs Pattern Matching Rules
> +While the above routines permit class of service assignments to be made
> based on static criteria, the real power of classification is the ability
> to identify flows based on the variable contents of packet headers.
> +To do this ODP provides support for defining pattern matching rules
> (PMRs) that operate based on values contained in specified header fields.
> +
> +Associated with PMRs are enums that are used to specify standard packet
> header fields:
> +@subsubsection cos_hdr_flow_fields odp_cos_hdr_flow_fields_e
> +@verbatim
> +/**
> + * Packet header field enumeration
> + * for fields that may be used to calculate
> + * the flow signature, if present in a packet.
> + */
> +
> +enum odp_cos_hdr_flow_fields_e {
> +        ODP_COS_FHDR_IN_PKTIO,        /**< Ingress port number */
> +        ODP_COS_FHDR_L2_SAP,          /**< Ethernet Source MAC address */
> +        ODP_COS_FHDR_L2_DAP,          /**< Ethernet Destination MAC
> address */
> +        ODP_COS_FHDR_L2_VID,          /**< Ethernet VLAN ID */
> +        ODP_COS_FHDR_L3_FLOW          /**< IPv6 flow_id */
> +        ODP_COS_FHDR_L3_SAP,          /**< IP source address */
> +        ODP_COS_FHDR_L3_DAP,          /**< IP destination address */
> +        ODP_COS_FHDR_L4_PROTO,        /**< IP protocol (e.g.
> TCP/UDP/ICMP) */
> +        ODP_COS_FHDR_L4_SAP,          /**< Transport source port */
> +        ODP_COS_FHDR_L4_DAP,          /**< Transport destination port */
> +        ODP_COS_FHDR_IPSEC_SPI,       /**< IPsec session identifier */
> +        ODP_COS_FHDR_LD_VNI,          /**< NVGRE/VXLAN network identifier
> */
> +        ODP_COS_FHDR_USER             /**< Application-specific header
> field(s) */
> +};
> +@endverbatim
> +
> +Conforming ODP implementations SHOULD implement efficient flow set
> management routines such as these:
> +
> +~~~~~{.c}
> +/**
> + * Set of header fields that take part in flow signature hash calculation:
> + * bit positions per 'odp_cos_hdr_flow_fields_e' enumeration.
> + *
> +typedef uint16_t odp_cos_flow_set_t;
> +
> +
> +/**
> + * Set a member of the flow signature fields data set
> + *
> +static inline odp_cos_flow_set_t
> +odp_cos_flow_set( odp_cos_flow_set_t set,
> +        enum odp_cos_hdr_flow_fields_e field)
> +{
> +        return set | (1U << field);
> +}
> +
> +
> +/**
> + * Test a member of the flow signature fields data set
> + *
> +static inline bool
> +odp_cos_flow_is_set( odp_cos_flow_set_t set,
> +        enum odp_cos_hdr_flow_fields_e field)
> +{
> +        return (set & (1U << field)) != 0;
> +}
> +~~~~~
> +
> +These routines are intended to be used in support of the following flow
> signature APIs:
> +
> +@subsubsection cos_class_flow_sig odp_cos_class_flow_signature
> +@verbatim
> +/**
> + * Set up set of headers used to calculate a flow signature
> + * based on class-of-service.
> + *
> + * @param cos_id class of service instance identifier
> + * @param req_data_set requested data-set for flow signature calculation
> + *
> + * @return data-set that was successfully applied. All-zeros data set
> + * indicates a failure to assign any of the requested fields, or other
> + * error.
> + */
> +
> +odp_cos_flow_set_t
> +odp_cos_class_flow_signature(odp_cos_t cos_id,
> +        odp_cos_flow_set_t req_data_set);
> +@endverbatim
> +
> +This OPTIONAL routine associates a fow set with a class of service for
> flow signature calculation.
> +
> +@subsubsection cos_port_flow_sig odp_cos_port_flow_signature
> +@verbatim
> +/**
> + * Set up set of headers used to calculate a flow signature
> + * based on ingress port.
> + *
> + * @param pktio_in ingress port identifier.
> + * @param req_data_set requested data-set for flow signature calculation
> + *
> + * @return data-set that was successfully applied. An all-zeros data-set
> + * indicates a failure to assign any of the requested fields, or other
> + * error.
> + */
> +
> +odp_cos_flow_set_t
> +odp_cos_port_flow_signature(odp_pktio_t pktio_in,
> +                odp_cos_flow_set_t req_data_set);
> +@endverbatim
> +
> +@subsection pmr_routines Pattern Matching Rules Routines
> +The following data structures SHOULD be implemented to support the
> definition of pattern matching routines by conforming ODP implementations:
> +
> +~~~~~{.c}
> +/**
> + * PMR - Packet Matching Rule
> + * Up to 32 bit of ternary matching of one of the available header fields
> + *
> +
> +
> +#define        ODP_PMR_INVAL ((odp_pmr_t)NULL)
> +typedef struct odp_pmr_s *odp_pmr_t;
> +~~~~~
> +
> +@subsecion terms Terms
> +Terms are the elements of a PMR and are identified by the following enum:
> +
> +@verbatim
> +enum odp_pmr_term_e {
> +    ODP_PMR_ETHTYPE_0,        /**< Initial (outer) Ethertype only
> (*val=uint16_t)*/
> +    ODP_PMR_ETHTYPE_X,        /**< Ethertype of most inner VLAN tag
> (*val=uint16_t)*/
> +    ODP_PMR_VLAN_ID_0,        /**< First VLAN ID (outer) (*val=uint16_t)
> */
> +    ODP_PMR_VLAN_ID_X,        /**< Last VLAN ID (inner) (*val=uint16_t) */
> +    ODP_PMR_DMAC,             /**< destination MAC address
> (*val=uint64_t) */
> +    ODP_PMR_IPPROTO,          /**< IP Protocol or IPv6 Next Header
> (*val=uint8_t) */
> +    ODP_PMR_UDP_DPORT,        /**< Destination UDP port, implies
> IPPROTO=17 */
> +    ODP_PMR_TCP_DPORT,        /**< Destination TCP port implies IPPROTO=6
> */
> +    ODP_PMR_UDP_SPORT,        /**< Source UDP Port (*val=uint16_t) */
> +    ODP_PMR_TCP_SPORT,        /**< Source TCP port (*val=uint16_t) */
> +    ODP_PMR_SIP_ADDR,         /**< Source IP address (uint32_t) */
> +    ODP_PMR_DIP_ADDR,         /**< Destination IP address (uint32_t) */
> +    ODP_PMR_SIP6_ADDR,        /**< Source IP address (uint8_t[16]) */
> +    ODP_PMR_DIP6_ADDR,        /**< Destination IP address (uint8_t[16]) */
> +    ODP_PMR_IPSEC_SPI,        /**< IPsec session
> identifier(*val=uint32_t) */
> +    ODP_PMR_LD_VNI,           /**< NVGRE/VXLAN network identifier
> (*val=uint32_t) */
> +
> +
> +    /** Inner header may repeat above values with this offset */
> +    ODP_PMR_INNER_HDR_OFF=32
> +};
> +@endverbatim
> +
> +@subsubsection tunnel_considerations Tunnel Considerations
> +Note that PMRs may be extended to support tunnels and tenants  (NVGRE,
> VXLAN) via the ODP_PMR_INNER_HDR_OFF enum.
> +This enum is intended to be used as an “adder” to a PMR to indicate that
> the term refers to an inner header.
> +For example, the term ODP_PMR_DMAC would refer to the destination MAC
> address of the packet if the packet is not a tunnel, or of the outer header
> (the tunnel) if the packet is a tunnel.
> +To refer to the inner (tenant) destination MAC, the term would be
> specified as ODP_PMR_INNER_HDR_OFF+ODP_PMR_DMAC.
> +
> +@subsection pmr_apis PMR APIs
> +The following APIs are provided to enable an ODP application to specify
> PMRs as a series of individual or cascaded terms:
> +@subsubsection pmr_create_match odp_pmr_create_match
> +@verbatim
> +/**
> + * Create a packet match rule with mask and value
> + *
> + * @param term      is one value of the enumerated values supported
> + * @param val       is the value to match against the packet header
> + *                  in native byte order.
> + * @param   mask    is the mask to indicate which bits of the header
> + *                  should be matched ('1') and which should be ignored
> ('0')
> + * @param   val_sz  size of the ‘val’ and ‘mask’ arguments,
> + *                  that must match the value size requirement of the
> + *                  specific ‘term’.
> + *
> + * @return a handle of the matching rule or ODP_PMR_INVAL on error
> + */
> +
> +odp_pmr_t odp_pmr_create_match(enum odp_pmr_term_e term,
> +                               const void *val, const void *mask, size_t
> val_sz);
> +@endverbatim
> +
> +This routine creates a PMR that matches a single value to a term.
> +
> +@subsubsection pmr_create_range odp_pmr_create_range
> +@verbatim
> +/**
> + * Create a packet match rule with value range
> + *
> + * @param term      is one value of the enumerated values supported
> + * @param val1      is the lower bound of the header field range.
> + * @param val2      is the upper bound of the header field range.
> + * @param val_sz    size of the ‘val1’ and ‘val2’ arguments,
> + *                  that must match the value size requirement of the
> + *                  specific ‘term’.
> + *
> + * @return a handle of the matching rule or ODP_PMR_INVAL on error
> + * @note: Range is inclusive [val1..val2].
> + */
> +
> +odp_pmr_t odp_pmr_create_range(enum odp_pmr_term_e term,
> +                                        const void *val1, const void
> *val2, size_t val_sz);
> +@endverbatim
> +
> +This routine creates a PMR that matches an inclusive range of values to a
> term.
> +
> +@subsubsection pmr_destroy odp_pmr_destroy
> +@verbatim
> +/**
> + * Invalidate a packet match rule and vacate its resources
> + *
> + * @param pmr_id    the identifier of the PMR to be destroyed
> + *
> + * @return Success or ODP_PMR_INVALID if the specified pmr_id not found.
> + */
> +
> +int odp_pmr_destroy(odp_omr_t pmr_id);
> +@endverbatim
> +
> +This routine destroys a previously created PMR.
> +If the PMR is currently associated with an active class of service it is
> unpredictable at which point the match defined by the PMR is deactivated in
> terms of packet flow.
> +However, implementations MUST ensure that a PMR is either matched or not
> matched in its entirety such that dynamic changes to PMRs do not result in
> partial matches.
> +
> +@subsubsection pktio_pmr_cos odp_pktio_pmr_cos
> +@verbatim
> +/**
> + * Apply a PMR to a pktio to assign a CoS.
> + *
> + * @param pmr_id     the id of the PMR to be activated
> + * @param src_pktio  the pktio to which this PMR is to be applied
> + * @param dst_cos    the CoS to be assigned by this PMR
> + *
> + * @return Success or ODP_PARAMETER_ERROR
> + */
> +
> +int odp_pktio_pmr_cos(odp_pmr_t pmr_id, odp_pktio_t src_pktio, odp_cos_t
> dst_cos);
> +@endverbatim
> +
> +This routine links a pktio to a corresponding class of service via a
> specified PMR.
> +Any packet received on the specified src_pktio that matches the specified
> pmr_id will be assigned to the specified dst_cos.
> +If multiple PMRs match the implementation MAY define an inherent
> precedence or it MAY be unpredictable as to which PMR will determine the
> assigned CoS.
> +For this reason applications SHOULD NOT be written to use conflicting or
> ambiguous PMR definitions.
> +
> +@subsubsection cos_pmr_cos odp_cos_pmr_cos
> +@verbatim
> +/**
> + * Cascade a PMR to refine packets from one CoS to another.
> + *
> + * @param pmr_id     the id of the PMR to be activated
> + * @param src_cos    the id of the CoS to be filtered
> + * @param dst_cos    the id of the CoS to be assigned to packets filtered
> + *                   from src_cos that match pmr_id.
> + *
> + * @return Success or ODP_PARAMETER_ERROR if an input is in error
> + *                 or ODP_IMPLEMENTATION_LIMIT if cascade depth is
> exceeded
> + */
> +
> +int odp_cos_pmr_cos(odp_pmr_t pmr_id, odp_cos_t src_cos, odp_cos_t
> dst_cos);
> +@endverbatim
> +
> +This routine is used to cascade PMRs by passing packets assigned to the
> src_cos through another PMR.
> +Those matching are reassigned to the specified dst_cos.
> +Note that this process can be repeated to an implementation-defined
> maximum supported cascade depth.
> +When cascades are defined, the actual class of service assigned to a
> packet is the result of the longest chain of PMRs that can be matched
> against the packet.
> +
> +For example, suppose the following sequence of PMRs is in effect:
> +
> +@verbatim
> +odp_pktio_pmr_cos(pmr_idA, pktio_id, cos_idA);
> +odp_cos_pmr_cos(pmr_idB, cos_idA, cos_idB);
> +odp_cos_pmr_cos(pmr_idC, cos_idB, cos_idC);
> +odp_cos_pmr_cos(pmr_idD, cos_idC, cos_idD);
> +@endverbatim
> +
> +If a packet arrives on pktio_id that matches pmr_idA it is assigned to
> cos_idA.
> +But since it is now on cos_idA it is further filtered by pmr_idB and if
> it matches is reassigned to cos_idB.
> +This process continues until no further more specific match is found to
> determine the final CoS that the packet receives.
> +
> +Note that given this rule set a packet that matched pmr_idA and pmr_idC
> it would be assigned to cos_idA because the rule that can assign packets to
> pmr_idC is only applicable to packets that are assigned to cos_idB, not
> cos_idA.
> +
> +Using cascaded PMRs it is possible to build quite sophisticated filters
> (up to the implementation limits supported by a given platform).
> +For example, one could add additional rules to the above set:
> +
> +@verbatim
> +odp_cos_pmr_cos(pmr_idAC, cos_idA, cos_idC);
> +odp_cos_pmr_cos(pmr_idAD, cos_idA, cos_idD);
> +@endverbatim
> +
> +To cover cases where some packets on cos_idA should be further sorted to
> cos_idB while others should be sorted directly to cos_idC or cos_idD.
> +Again it is the application’s responsibility to ensure that the cascades
> remain unambiguous and that loops be avoided (e.g., having rules that
> bounce packets between cos_idA and cos_idB endlessly).
> +
> +@subsection pmr_stats PMR Statistics
> +Conforming ODP implementations SHOULD maintain statistics regarding PMRs
> and provide the following routines for retrieving them:
> +
> +@subsubsection pmr_match_count odp_pmr_match_count
> +@verbatim
> +/**
> + * Retrieve packet matcher statistics
> + *
> + * @param pmr_id    the id of the PMR from which to retrieve the count
> + *
> + * @return The current number of matches for a given matcher instance.
> + */
> +
> +signed long odp_pmr_match_count(odp_pmr_t pmr_id);
> +@endverbatim
> +
> +@subsubsection pmr_terms_cap odp_pmr_terms_cap
> +@verbatim
> +/**
> + * Inquire about matching terms supported by the classifier
> + *
> + * @return A mask one bit per enumerated term, one for each of
> op_pmr_term_e
> + */
> +
> +unsigned long long odp_pmr_terms_cap(void);
> +@endverbatim
> +
> +@subsubsection pmr_terms_avail odp_pmr_terms_avail
> +@verbatim
> +/**
> + * Return the number of packet matching terms available for use
> + *
> + * @return A number of packet matcher resources available for use.
> + */
> +
> +unsigned odp_pmr_terms_avail(void);
> +@endverbatim
> +
> +@subsection pmr_composite_rules Pattern Matching Composite Routines
> +As a shorthand, applications MAY express pattern matching rules using a
> table rather than constructing them term-by-term.
> +ODP implementations MUST support both methods of rule specification but
> MAY have implementation-specific restrictions on the complexity of
> table-based rules they support.
> +Note that some implementations MAY be able to implement tables directly
> while others MAY choose to implement tables by internally generating the
> equivalent set of term generating calls.
> +
> +@subsubsection pmr_table_structure PMR Table Structure
> +@verbatim
> +/**
> + * Following structure is used to define composite packet matching rules
> + * in the form of an array of individual match or range rules.
> + * The underlying platform may not support all or any specific combination
> + * of value match or range rules, and the application should take care
> + * of inspecting the return value when installing such rules, and perform
> + * appropriate fallback action.
> + */
> +
> +typedef struct odp_pmr_match_t {
> +            enum odp_pmr_match_type_e {
> +                    ODP_PMR_MASK,           /**< Match a masked set of
> bits */
> +                    ODP_PMR_RANGE,          /**< Match an integer range */
> +      } match_type;
> +            union {
> +                    struct {
> +                            enum odp_pmr_term_e  term;
> +                            const void              *val;
> +                            const void              *mask;
> +                            unsigned int             val_sz;
> +                    } mask; /**< Match a masked set of bits */
> +                    struct {
> +                            enum odp_pmr_term_e  term;
> +                            const void              *val1;
> +                            const void              *val2;
> +                            unsigned int             val_sz;
> +                    } range; /**< Match an integer range */
> +            };
> +} odp_pmr_match_t;
> +
> +
> +/** An opaque handle to a composite packet match rule-set */
> +typedef struct odp_pmr_set_s *odp_pmr_set_t;
> +@endverbatim;
> +
> +The above structure is used with the following APIs to implement
> table-based PMRs:
> +
> +@subsubsection pmr_match_set_create odp_pmr_match_set_create
> +@verbatim
> +/**
> + * Create a composite packet match rule
> + *
> + * @param num_terms  is the number of terms in the match rule.
> + * @param terms      is an array of num_terms entries, one entry per
> + *                   term desired.
> + * @param dst_cos    is the class-of-service to be assigned to packets
> + *                   that match the compound rule-set, or a subset
> thereof,
> + *                   if partly applied.
> + * @param pmr_set_id is the returned handle to the composite rule set.
> + *
> + * @return The return value may be a negative number indicating a general
> + * error, or a positive number indicating the number of ‘terms’ elements
> that
> + * have been successfully mapped to the underlying platform
> classification engine,
> + * and may be in the range from 1 to ‘num_terms’.
> + */
> +
> +int odp_pmr_match_set_create(int num_terms, odp_pmr_match_t *terms,
> +                             odp_pmr_set_t *pmr_set_id);
> +@endverbatim
> +
> +This routine is used to create a PMR match set.
> + It is the equivalent to a cascade of PMRs except that there are no
> “intermediate” classes of service defined.
> +Instead, the entire match set either matches or does not match as a
> single entity.
> +
> +@subsubsection pmr_match_set_destroy odp_pmr_match_set_destroy
> +@verbatim
> +/**
> + * Function to delete a composite packet match rule set
> + *
> + * All of the resources pertaining to the match set associated with the
> + * class-of-service will be released, but the class-of-service will
> + * remain intact.
> + *
> + * @param pmr_set_id a composite rule-set handle returned when created.
> + *
> + * @note Depending on the implementation details, destroying a rule-set
> + * may not guarantee the availability of hardware resources to create the
> + * same or essentially similar rule-set.
> + */
> +
> +int odp_pmr_match_set_destroy(odp_pmr_set_t pmr_set_id);
> +@endverbatim
> +
> +This routine destroys a PMR match set previously created by
> odp_pmr_match_set_create().
> +
> +@subsubsection pktio_pmr_match_set_cos odp_pktio_pmr_match_set_cos
> +@verbatim
> +/**
> + * Apply a PMR Match Set to a pktio to assign a CoS.
> + *
> + * @param pmr_set_id the id of the PMR match set to be activated
> + * @param src_pktio  the pktio to which this PMR match set is to be
> applied
> + * @param dst_cos    the CoS to be assigned by this PMR match set
> + *
> + * @return Success or ODP_PARAMETER_ERROR
> + */
> +
> +int odp_pktio_pmr_match_set_cos(odp_pmr_t pmr_id, odp_pktio_t src_pktio,
> +                                odp_cos_t dst_cos);
> +@endverbatim
> +
> +This routine is the same as odp_pktio_pmr_cos() except that it operates
> on PMR match sets rather than individual PMRs.
> +
> +@section items_pending Items pending resolution
> +- Revise ‘odp_packet_io.h’ API with respect of default input queue per
> ‘pktio’ instance.
> +- Revise ‘odp_queue.h’ API to support an arbitrary priority range,
> typically 8 priority levels with numeric priority values are
> platform-specific.
> +- Add specific packet meta data fields to go into packet buffer which
> contain all meta data fields parsed and generated by the classifier, for
> later application use.
> +
> +@section implementation_notes Implementation Notes
> +The following sections are not part of the specification, but shed light
> into the intent of the specification in several areas, describing some
> specific implementation approaches of these aspects.
> +
> +@subsection supporting_multi_pools Supporting multiple buffer pools
> +The support of multiple buffer pools for containing packet buffers is
> optional, and may not be supported by some platforms.
> +The importance of this feature stems from the need of protecting a
> networking application in the event of a congestion, or an attempted denial
> of service attack.
> +Separating different classes of service to dedicated buffer pools allows
> the system to limit the memory resources that may be consumed by a
> particular type of traffic, thereby reserving buffer resources for other
> classes of traffic.
> +
> +In a software implementation, a packet would already be stored in memory
> when the classifier is invoked, and so it seems the classifier is unable to
> insert itself into the process of selecting a buffer pool.
> +For obvious reasons the copying of a packet into a new buffer allocated
> from a different pool by the classifier is not a desirable solution.
> +
> +The recommended solution is to implement buffer pools in the form of
> buffer counters, while the actual buffers all belong to a single free list
> when not used to store a packet.
> +In such an implementation, the classifier will be able to associate a
> packet already occupying a buffer to a different pool than the default by
> incrementing the buffer counter of the newly selected pool, and
> decrementing the counter representing the default pool.
> +If however the selected pool counter has already reached a certain limit,
> the classifier would be able to e.g discard the packet instead of
> incrementing the destination pool counter, and thereby enforce the
> desirable semantics of distinct buffer pools per class of service.
> +
> +Other possible action that may be taken in response to running out of
> buffers or coming too low on buffers include back-pressure and
> random-early-detect with a discard probability inversely proportional to
> the number of free buffers in a pool.
> +A related implementation topic is the ability to begin dropping some
> packets before a buffer pool is entirely exhausted.
> +This is typically referred to as <em>Random Early Detect</em> (or “RED”).
> +This is deemed to be a feature of the buffer pool implementation on a
> given platform, where in addition to a hard limit on the number of buffers
> that can be allocated to a pool, there can also be an option discard
> packets with a probability the increases as the number of outstanding
> buffers approaches that hard limit.
> +
> +@subsection resolving_gaps Resolving gaps between the API and hardware
> capabilities
> +On platforms that support hardware packet accelerators, it is possible
> that the packet parsing and classification functionality is sufficient to
> address only a portion of the functionality specified within this document.
> +This gap may be potentially bridged by augmenting the hardware
> classification capabilities with a software logic implemented as part of
> the platform.
> +In that case, the platform will have to curve out a fraction of the
> processing resources and dedicate those to the software classification
> logic, which would be invoked for packets that the hardware platform was
> unable to classify completely.
> +At the time of this writing, it is believed however that  the performance
> penalty that will be incurred as a result of software augmentation is
> unjustified for most application, i.e.
> +it is preferred to lose the precision of packet prioritization while
> maintaining full hardware packet processing speed.
> +
> +@subsection loopback_case The case for loopback ports, and some of their
> uses
> +In some applications, it may be desirable to be able to run a single
> packet through the classifier more than once.
> +For example, an encrypted IPsec packet is received from a physical port.
> +The encrypted packet is assigned a class of service based on its outer
> unencrypted header fields.
> +Later, processing the packet entails decrypting the payload of the
> packet, authenticating it, and removing the original outer headers, which
> reveals a new set of protocol headers which need to be used to re-classify
> the packet, and assign it a new priority and buffer pool.
> +An elegant solution for this use case would be to take advantage of
> “loopback” logical ports that may be implemented in certain platforms, by
> transmitting decapsulated packet into a loop-back port.
> +The same packet then is received from a loop-back port and is examined by
> the classifier in accordance to the rules assigned to the loopback
> odp_pktio logical port instance.
> +Similar mechanism may be applied to tunnel termination processing,
> fragment reassembly et al.
> +
> +@section related_topics Related Topics
> +The following section discusses aspects of the ODP API that are not
> integral to the classifier, which only applies to ingress preprocessing.
> +This section covers miscellaneous aspects of the API that need to be
> addressed, and are related to packet buffer processing and egress
> post-processing.
> +Additional packet buffer manipulation APIs
> +The need for these following calls are made evident by the need to
> encapsulate, i.e., remove some headers and add other, thereby changing the
> size of the headers of a packet during processing.
> +
> +@subsection initial_headroom Configuring initial packet buffer headroom
> +The following function is provided to configure the pktio receive
> mechanism to (optionally)reserve some headroom between start of the first
> buffer to the first byte of the first packet data byte, which subsequently
> could be used to increase the header size “in-place”, without allocating
> additional gather list elements.
> +If the request is granted, at least <req_bytes> bytes will be reserved in
> the front of the packet data:
> +@verbatim
> +int odp_pktio_set_headroom(odp_pktio_t port_id, unsigned req_bytes);
> +@endverbatim
> +The return value should be negative if the request can not be satisfied,
> or positive otherwise indicating the actual minimum headroom reserved.
> +Note that the implementation may reserve more than the requested amount
> of headroom, and hence on platforms that are unable to support per-port (or
> per CoS) headroom configuration, a system-wide headroom configuration may
> be set to the largest of all such requests, and thus satisfy the
> requirement.
> +In addition to the above per-port headroom configuration call, there
> should be an optional, per-CoS call that allows the reservation of
> different amounts of packet buffer headroom for packets that match certain
> criteria: for example, the following call allows the application to request
> that only packets that are expected to be encapsulated in a tunnel, be
> augmented with a large headroom amount, while packets that are received
> from a tunnel, and are IP fragments, be assigned a different headroom
> requirement (see definition for odp_cos_set_headroom() above.
> +Egress packet scheduling, prioritization and ordering
> +
> +
> +Open Issues
> +* Parallel matching rules relative precedence.
> +* Specify application-defined header field declaration APIs.
> +* Review RFC 4301 for match requirements for IPsec SA, consider the use
> of L4 port ranges instead of or in addition to value & mask matching
> criteria.
> +* Consider the type of packet checks should route a packet through the
> error CoS: L2 is a safe choice, but L3/L4 checksum or other exceptions
> deserve consideration.
> +Usage Examples
> +Following is a simple sample configuration using the API elements
> described above.
> +TBD.
> +
> +*/
> diff --git a/images/classification_flow.png
> b/images/classification_flow.png
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..2d94ff64ec772aa97f3687181c121fb91d671889
> GIT binary patch
> literal 35193
> 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
> Ru|ekbQbt9(O42mw{{YqNUv2;Z
>
> literal 0
> HcmV?d00001
>
> --
> 1.8.3.2
>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
diff mbox

Patch

diff --git a/classification_design.dox b/classification_design.dox
new file mode 100644
index 0000000..170a1ef
--- /dev/null
+++ b/classification_design.dox
@@ -0,0 +1,899 @@ 
+/* Copyright (c) 2014, Linaro Limited
+ * All rights reserved
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/*!
+@page classification_design ODP Design - Classification API
+For the implementation of the ODP classification API please see @ref odp_classify.h
+
+@tableofcontents
+
+@section introduction Introduction
+This document defines the Classification APIs supported by ODP v1.0.
+Classification is logically composed of two stages: Parsing and Rule Matching.
+Parsing takes a raw packet and validates its structure and identifies fields of interest in the various headers that comprise the layers of the packet.
+Rule Matching, in turn, takes the result of parsing and sorts packets into Classes of Service (CoS) based on application-defined rule sets.
+@subsection use_of_terms Use of Terms
+The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://tools.ietf.org/html/rfc21199).
+@subsection purpose Purpose
+ODP is a framework for software-based packet forwarding/filtering applications, and the purpose of the Packet Classifier API is to enable applications to program the platform hardware or software implementation to assist in prioritization, classification and scheduling of each packet, so that the software application can run faster, scale better and adhere to QoS requirements.
+The following API abstraction are not modelled after any existing product implementation, but is instead defined in terms of what a typical data-plane application may require from such a platform, without sacrificing simplicity and avoiding ambiguity.
+Certain terms that are being used within the context of existing products in relation to packet parsing and classification, such as “access lists” are avoided such that not to suggest any relationship between the abstraction used within this API and any particular manner in which they may be implemented in hardware.
+These are the key ODP objects that the parser needs to employ, that are presently defined in ODP:
+@subsubsection odp_pktio odp_pktio
+odp_pktio specifies an individual packet I/O channel instance.
+In other words, it would translate to a physical interface or a logical port, or in the case of channelized protocols (e.g., [Interlaken](https://www.google.com/url?q=https%3A%2F%2Fwww.cortina-systems.com%2Fimages%2Fdocuments%2F400023_Interlaken_Technology_White_Paper.pdf&sa=D&sntz=1&usg=AFQjCNEBdJTBmA1XaNGY3pmumQTfgSi1oA)) it would map to a logical channel on that interface.
+Since the classifier API deals exclusively with ingress, this object represents the source of packets into the classifier.
+In order to support any non-trivial use case, the classifier API needs to be able to assign multiple odp_queue instances for any single odp_pktio object, and may also assign any odp_queue instance to more than one odp_pktio object.
+@subsubsection odp_queue odp_queue
+odp_queue specifies a logical queue for packets, and in the case of ingress, this would represent a stream of packets which share several attributes, that are delivered to the ODP application for processing.
+The per-queue attributes currently defined are: queue type, sync (ordering); priority; and schedule group (set of processor cores).
+@subsubsection odp_buffer_pool odp_buffer_pool
+odp_buffer_pool specifies a collection of buffers of same size and alignment, as well as a set of policies such as flow control and processor affinity.
+The classifier API refers to such pools that are designated for storing ingress packets.
+@section functional_description Functional Description
+Following is the functionality that is required of the classifier API, and its underlying implementation.
+The details and order of the following paragraph is informative, and is only intended to help convey the functional scope of a classifier and provide context for the API.
+In reality, implementations may execute many of these steps concurrently, or in different order while maintaining the evident dependencies:
+
+-# Apply a set of \e classification \e rules to the header of an incoming packet, identify the header fields, e.g., \e ethertype, IP version, IP protocol, transport layer port numbers, IP DiffServ, VLAN id, 802.1p priority.
+
+-# Store these fields as packet meta data for application use, and for the remainder of parser operations.
+The \e odp_pktio is also stored as one of the meta data fields for subsequent use.
+
+-# Compute an \e odp_cos (Class of Service) value from a subset of supported fields from 1) above.
+
+
+-# Based on the \e odp_cos from 3) above, select the \e odp_queue through which the packet is delivered to the application.
+
+-# Validate the packet data integrity (checksums, FCS)  and correctness (e.g., length fields) and store the validation result, along with optional error layer and type indicator, in packet meta data.
+Optionally, if a packet fails validation, override the \e odp_cos selection in step 3 to a class of service designated for errored packets.
+
+-# Since the selected \e odp_queue may require preservation of packet order, i.e., SYNC_ATOMIC or SYNC_ORDERED, optionally select the packet header fields from which the parser calculates a \e odp_flow_signature, which may be a unique flow identifier or a hash, such that the packets which are assigned the same \e odp_flow_signature are scheduled in the same order they are received.
+
+-# Based on the \e odp_cos from 3) above, select the \e odp_buffer_pool that should be used to acquire a buffer to store the packet data and meta data.
+
+-# Allocate a buffer from \e odp_buffer_pool selected in 6) above and logically store the packet data and meta data to the allocated buffer, or in accordance with class-of-service drop policy and subject to pool buffer availability, optionally discard the packet.
+
+-# Enqueue the buffer into the \e odp_queue selected in 4) above.
+
+The above is an abstract description of the classifier functionality, and may be applied to a variety of applications in many different ways.
+The ultimate meaning of how this functionality applies to an application also depends on other ODP modules, so the above may not complete a full depiction.
+For instance, the exact meaning of \e priority, which is a per-queue attribute is influenced by the ODP scheduler semantics, and the system behavior under stress depends on the ODP buffer pool module behavior.
+
+For the sole purpose of illustrating the above abstract functionality, here is an example of a Layer-2 (IEEE 802.1D) bridge application:
+Such a forwarding application that also adheres to IEEE 802.1p/q priority, which has 8 traffic priority levels, might create 8 \e odp_buffer_pool instances, one for each PCP priority level, and 8 \e odp_queue instances one per priority level.
+Incoming packets will be inspected for a VLAN header; the PCP field will be extracted, and used to select both the pool and the queue.
+Because each queue will be assigned a priority value, the packets with highest PCP values will be scheduled before any packet with a lower PCP value.
+Also, in a case of congestion, buffer pools for lower priority packets will be depleted earlier than the pools containing packets of the high priority, and hence the lower priority packets will be dropped (assuming that is the only flow control method that is supported in the platform) while higher priority packets will continue to be received into buffers and processed.
+@subsection flow_diagram Classification Processing Flow Diagram
+@image html classification_flow.png "Figure 1: Classification Flow Diagram"
+@image latex classification_flow.eps "Figure 1: Classification Flow Diagram"
+
+@section api_elements API Elements
+While the above description refers to the abstracted packet classifier, the following is the description of the API designed to program the packet classifier, and is intended to add clarity to the functions provided further below.
+@subsection cos_creation Class of Service Creation and Binding
+To program the classifier, a class-of-service instance must be created, which will contain the packet filtering resources that it may require.
+All subsequent calls refer to one or more of these resources.
+Each class of service instance must be associated with a single queue or queue group, which will be the destination of all packets matching that particular filter.
+The queue assignment is implemented as a separate function call such that the queue may be modified at any time, without tearing down the filters that define the class of service.
+In other words, it is possible to change the destination queue for a class of service defined by its filters quickly and dynamically.
+Optionally, on platforms that support multiple packet buffer pools, each class of service may be assigned a different pool such that when buffers are exhausted for one class of service, other classes are not negatively impacted and continue to be processed.
+
+@subsection default_packet_handling Default packet handling
+There SHOULD be one \b odp_cos assigned to each port with the \c odp_cos_pktio_set()  function,  which will function as the default class-of-service for all packets received from an ingress port, that do not match any of the filters defined subsequently.
+At minimum this default class-of-service MUST have a queue and a buffer pool assigned to it on platforms that support multiple packet buffer pools.
+Multiple odp_pktio instances (i.e., multiple ports) MAY each have their own default odp_cos, or MAY share a odp_cos with other ports, based on application requirements.
+
+@subsection packet_classification Packet Classification
+For each odp_pktio port, the API allows the assignment of a class-of-service to a packet using one of  three methods:
+
+-# The packet may be assigned a specific class-of-service based on its Layer-2 (802.1P/902.1Q VLAN tag) priority field.
+Since the standard field defines 8 discrete priority levels, the API allows to assign an odp_cos to each of these priority levels with the \c odp_cos_with_l2_priority() function.
+
+-# Similarly, a class-of-service may be assigned using the Layer-3 (IP DiffServ) header field.
+The application supplies an array of \e odp_cos values that covers the entire range of the standard protocol header field, where array elements do not need to contain unique values.
+There is also a need to specify if Layer-3 priority takes precedence over Layer-2 priority in a packet with both headers present.
+
+-# Additionally, the application may also program a number of \e pattern \e matching \e rules that assign a class-of-service for packets with header fields matching specified values.
+The field-matching rules take precedence over the previously described priority-based assignment of a class-of-service.
+Using these matching rules the application should be able for example to identify all packets containing VoIP traffic based on the protocol being UDP, and a specific destination or source port numbers, and appropriately assign these packets an class-of-service that maps to a higher priority queue, assuring voice packets a lower and bound latency.
+
+@subsection scaling_and_flow Scaling and Flow Discrimination
+In addition to classifying packets and routing them to those queues with the appropriate priority, and optionally limiting their memory consumption by designating certain classes of packets to specific buffer pools, the classifier API also facilitates the scaling of data-plane application on multi-core systems by creating a mechanism to define which packet headers need to be combined to result in a value representing a specific packet flow.
+The classifier generates a signature, which can be a checksum or hash of arbitrary strength that covers those packet header fields that are identified by the application as identifying flows.
+
+The \e flow \e signatures that result from hashing are then stored with the packet meta data (along with its class-of-service and its ingress \e odp_pktio port), and subsequently may be utilized by the implementation of a scheduler queue to maintain the order of packets with the same flow signature, while allowing packets with different signatures to be processed concurrently and independently on different processing cores.
+
+@subsection packet_meta_data Packet meta data Elements
+Here are the specific information elements that SHOULD be stored within the packet meta data structure:
+- Protocol fields that are decoded and extracted by the parsing phase
+- Flow-signature calculated from a prescribed collection of protocol fields
+- The class-of-service identifier that is selected for the packet
+- The ingress port identifier
+- The result of packet validation, including an indication of the type of error detected, if any
+
+The ODP packet API module SHALL provide accessors for retrieving the above meta data fields from the container buffer in an implementation-independent manner.
+
+@section api_definitions API Definitions
+@subsection data_types Data Types
+The following data types are referenced in the API descriptions described below.
+The names are part of the ODP API and MUST be present in any conforming implementation, however the type values shown here are illustrative and implementations SHOULD either use these or substitute their own type values that are appropriate to the underlying platform.
+
+@verbatim
+/**
+ * 'odp_pktio_t' value to indicate any port
+ */
+#define ODP_PKTIO_ANY         ((odp_pktio_t)~0)
+
+
+/**
+ * 'odp_pktio_t' value to indicate an error
+ */
+#define ODP_PKTIO_INVALID ((odp_pktio_t)0)
+
+
+/**
+ * Class of service instance type
+ */
+typedef uint32_t odp_cos_t;
+
+
+/**
+ * flow signature type, only used for packet meta data field.
+ */
+typedef uint32_t odp_flowsig_t;
+
+
+/**
+ * This value is returned from odp_cos_create() on failure,
+ * May also be used as a “sink” class of service that
+ * results in packets being discarded.
+ */
+#define ODP_COS_INVALID        ((odp_cos_t)~0)
+@endverbatim
+
+@subsection cos_routines Class of Service Routines
+Conforming ODP implementations MUST provide the following Classification APIs:
+@subsubsection cos_create odp_cos_create
+@verbatim
+/**
+ * Create a class-of-service
+ *
+ * @param  name is a string intended for debugging purposes.
+ *
+ * @return Class of service instance identifier,
+ *         or ODP_COS_INVALID on error.
+ */
+
+odp_cos_t odp_cos_create(const char *name);
+@endverbatim
+
+This routine is used to create a class of service that can be the target of classifier rules.
+The number of such classes supported is implementation-defined.
+Attempts to create more than are supported by the implementation will result in an \c ODP_COS_INVALID return and errno being set to \c ODP_IMPLEMENTATION_LIMIT.
+
+@subsubsection cos_destroy odp_cos_destroy
+@verbatim
+/**
+ * Discard a class-of-service along with all its associated resources
+ *
+ * @param cos_id class-of-service instance.
+ *
+ * @return 0 on success, -1 on error.
+ */
+
+int odp_cos_destroy(odp_cos_t cos_id);
+@endverbatim
+
+This routine is the bracketing routine for odp_cos_create().
+It is used to destroy an existing CoS.
+It is the caller’s responsibility to ensure that no active pattern matching rules refer to the CoS prior to calling this routine.
+Results are unpredictable if this restriction is not met.
+@subsubsection cos_set_queue odp_cos_set_queue
+@verbatim
+/**
+ * Assign a queue for a class-of-service
+ *
+ * @param cos_id   class-of-service instance.
+ *
+ * @param          queue_id is the identifier of a queue where all packets
+ *                 of this specific class of service will be enqueued.
+ *
+ * @return         0 on success, negative error code on failure.
+ */
+
+int odp_cos_set_queue(odp_cos_t cos_id, odp_queue_t queue_id);
+@endverbatim
+
+This routine associates a target queue with a CoS such that all packets assigned to this CoS will be enqueued to the specified queue_id at the end of classification processing.
+@subsubsection cos_set_queue_group odp_cos_set_queue_group
+@verbatim
+/**
+ * Assign a homogenous queue-group to a class-of-service.
+ *
+ * @param cos_id         identifier of class-of-service instance
+ * @param queue_group_id identifier of the queue group to receive packets
+ *                       associated with this class of service.
+ *
+ * @return               0 on success, negative error code on failure.
+ */
+
+int odp_cos_set_queue_group(odp_cos_t cos_id, odp_queue_group_t queue_group_id);
+@endverbatim
+
+This routine associates a target queue group with a CoS such that all packets assigned to this CoS will be distributed to the specified queue_group_id at the end of classification processing.
+@subsubsection cos_set_pool odp_cos_set_pool
+@verbatim
+/**
+ * Assign packet buffer pool for specific class-of-service
+ *
+ * @param cos_id  class-of-service instance.
+ * @param pool_id is a buffer pool identifier where all packet buffers
+ *                will be sourced to store packet that belong to this
+ *                class of service.
+ *
+ * @return        0 on success negative error code on failure.
+ *
+ *
+ */
+
+int odp_cos_set_pool(odp_cos_t cos_id, odp_buffer_pool_t pool_id);
+@endverbatim
+
+This OPTIONAL routine associates a target buffer pool with a CoS such that all packets assigned to this CoS will be stored in packet buffers allocated from the designated pool_id.
+
+
+@subsection cos_drop_policy Class of Service Drop Policy Routines
+These routines control how drop policies are to be observed for a given class of service.
+@subsubsection drop_data_types Data types
+~~~~~{.c}
+enum odp_cos_drop_e {
+        ODP_COS_DROP_POOL,        /**< Follow buffer pool drop policy */
+        ODP_COS_DROP_NEVER,       /**< Never drop, ignoring buffer pool policy */
+};
+typedef enum odp_drop_e odp_drop_t;
+~~~~~
+
+@subsubsection cos_set_drop odp_cos_set_drop
+@verbatim
+/**
+ * Assign packet drop policy for specific class-of-service
+ *
+ * @param   cos_id class-of-service instance.
+ * @param   drop_policy is the desired packet drop policy for this class.
+ *
+ * @return  0 on success negative error code on failure.
+ */
+
+int odp_cos_set_drop(odp_cos_t cos_id, odp_drop_t drop_policy);
+@endverbatim
+
+This routine sets the drop policy for a class of service.
+It is an OPTIONAL routine.
+If an implementation does not provide this function it MUST supply a definition of it that simply returns ODP_FUNCTION_NOT_AVAILABLE.
+@subsubsection pktio_set_default_cos odp_pktio_set_default_cos
+@verbatim
+/**
+ * Setup per-port default class-of-service
+ *
+ * @param   pktio_in ingress port identifier.
+ * @param   default_cos class-of-service set to all packets arriving
+ *          at the 'pktio_in' ingress port, unless overridden by subsequent
+ *          header-based filters.
+ *
+ * @return  0 on success negative error code on failure.
+ *
+ *
+ * @note    This may replace the default queue per pktio.
+ */
+
+int odp_pktio_set_default_cos(odp_pktio_t pktio_in, odp_cos_t default_cos);
+@endverbatim
+
+This routine specifies a default class of service for a given pktio instance.
+Incoming packets on the specified pktio are assigned to this class of service if no other pattern matching rule obtains.
+@subsubsection pktio_set_error_cos odp_pktio_set_error_cos
+@verbatim
+/**
+ * Setup per-port error class-of-service
+ *
+ * @param   pktio_in ingress port identifier.
+ * @param   error_cos class-of-service set to all packets arriving
+ *          at the 'pktio_in' ingress port that contain an error.
+ *
+ * @return  0 on success negative error code on failure.
+ */
+
+int odp_pktio_set_error_cos(odp_pktio_t pktio_in, odp_cos_t error_cos);
+@endverbatim
+
+This OPTIONAL function assigns a class-of-service used to handle packets containing various types of errors.
+The specific errors types include L2 FCS and optionally L3/L4 checksum errors, malformed headers, etc., depending on platform capabilities.
+The specified error_cos MAY simply discard these packets or deliver them via a queue to the application for further processing.
+@subsubsection pktio_set_skip odp_pktio_set_skip
+@verbatim
+/**
+ * Setup per-port header offset
+ *
+ * @param   pktio_in ingress port identifier.
+ * @param   offset is the number of bytes the classifier must skip.
+ *
+ * @return  Success or ODP_FUNCTION_NOT_AVAILABLE
+ */
+
+int odp_pktio_set_skip(odp_pktio_t pktio_in, size_t offset);
+@endverbatim
+
+This OPTIONAL function applies to ports that carry an additional headers preceding the standard Ethernet header.
+Such headers are typically vendor-specific and thus the classifier is not required to parse such headers, but the size of a custom header is critical for the classifier to be able to parse standard protocol headers that normally follow.
+@subsubsection cos_set_headroom odp_cos_set_headroom
+@verbatim
+/**
+ * Specify per-port buffer headroom
+ *
+ * @param   pktio_in  ingress port identifier.
+ * @param   headroom  number of bytes of space preceding packet data to reserve
+ *                    for use as headroom.  Must not exceed the implementation
+ *                    defined ODP_PACKET_MAX_HEADROOM.
+ *
+ * @return  Success or ODP_PARAMETER_ERROR,
+ *                  or ODP_FUNCTION_NOT_AVAILABLE
+ */
+
+int odp_cos_set_headroom(odp_cos_t cos_id, size_t req_room);
+@endverbatim
+
+This OPTIONAL routine specifies the number of bytes of headroom that should be reserved for each packet assigned to this class of service.
+Each implementation defines an ODP_PACKET_MAX_HEADROOM limit that sets an upper bound on the size of the headroom that can be reserved for a packet.
+@subsubsection cos_with_l2_priority odp_cos_with_l2_priority
+@verbatim
+/**
+ * Request to override per-port class of service
+ * based on Layer-2 priority field if present.
+ *
+ * @param   pktio_in ingress port identifier.
+ * @param   num_qos is the number of QoS levels, typically 8.
+ * @param   qos_table are the values of the Layer-2 QoS header field.
+ * @param   cos_table is the class-of-service assigned to each of the
+ *          allowed Layer-2 QOS levels.
+ * @return  0 on success negative error code on failure.
+ */
+
+int odp_cos_with_l2_priority(odp_pktio_t pktio_in,
+                               size_t num_qos,
+                               uint8_t qos_table[],        /**< 'num_qos' elements */
+                               odp_cos_t cos_table[]);     /**< 'num_qos' elements */
+@endverbatim
+
+This routine is used to assign classes of service based on the layer 2 (L2) priority associated with input packets received on the specified pktio_in.
+For each of the values in qos_table[], the corresponding value in cos_table[] will be assigned.
+@subsubsection cos_with_l3_dscp odp_cos_with_l3_dscp
+@verbatim
+/**
+ *
+ * @param   pktio_in ingress port identifier.
+ * @param   num_qos is the number of allowed Layer-3 QoS levels.
+ * @param   qos_table are the values of the Layer-3 QoS header field.
+ * @param   cos_table is the class-of-service assigned to each of the
+ *          allowed Layer-3 QOS levels.
+ * @param   l3_preference when true, Layer-3 QoS overrides L2 QoS when present.
+ *
+ * @return  0 on success negative error code on failure.
+ */
+
+int odp_cos_with_l3_qos(odp_pktio_t pktio_in,
+                          size_t num_qos,
+                          uint8_t qos_table[],        /**< 'num_qos' elements */
+                          odp_cos_t cos_table[],        /**< 'num_qos' elements */
+                          odp_bool_t l3_preference);
+@endverbatim
+
+This OPTIONAL routine is used to assign classes of service based on the layer 3 (L3) Differentiated Services (DS) designation.
+This is the DSCP field of an IPv4 header or the first six bits of the Traffic Class of an IPv6 header.
+For each of the values in qos_table[], the corresponding value in cos_table[] will be assigned.
+The l3_preference flag is use to control whether the CoS assigned by this routine takes precedence over the CoS assigned by odp_cos_with_l2_priority() in the event that both apply to the same packet.
+
+@subsection pmrs Pattern Matching Rules
+While the above routines permit class of service assignments to be made based on static criteria, the real power of classification is the ability to identify flows based on the variable contents of packet headers.
+To do this ODP provides support for defining pattern matching rules (PMRs) that operate based on values contained in specified header fields.
+
+Associated with PMRs are enums that are used to specify standard packet header fields:
+@subsubsection cos_hdr_flow_fields odp_cos_hdr_flow_fields_e
+@verbatim
+/**
+ * Packet header field enumeration
+ * for fields that may be used to calculate
+ * the flow signature, if present in a packet.
+ */
+
+enum odp_cos_hdr_flow_fields_e {
+        ODP_COS_FHDR_IN_PKTIO,        /**< Ingress port number */
+        ODP_COS_FHDR_L2_SAP,          /**< Ethernet Source MAC address */
+        ODP_COS_FHDR_L2_DAP,          /**< Ethernet Destination MAC address */
+        ODP_COS_FHDR_L2_VID,          /**< Ethernet VLAN ID */
+        ODP_COS_FHDR_L3_FLOW          /**< IPv6 flow_id */
+        ODP_COS_FHDR_L3_SAP,          /**< IP source address */
+        ODP_COS_FHDR_L3_DAP,          /**< IP destination address */
+        ODP_COS_FHDR_L4_PROTO,        /**< IP protocol (e.g. TCP/UDP/ICMP) */
+        ODP_COS_FHDR_L4_SAP,          /**< Transport source port */
+        ODP_COS_FHDR_L4_DAP,          /**< Transport destination port */
+        ODP_COS_FHDR_IPSEC_SPI,       /**< IPsec session identifier */
+        ODP_COS_FHDR_LD_VNI,          /**< NVGRE/VXLAN network identifier */
+        ODP_COS_FHDR_USER             /**< Application-specific header field(s) */
+};
+@endverbatim
+
+Conforming ODP implementations SHOULD implement efficient flow set management routines such as these:
+
+~~~~~{.c}
+/**
+ * Set of header fields that take part in flow signature hash calculation:
+ * bit positions per 'odp_cos_hdr_flow_fields_e' enumeration.
+ *
+typedef uint16_t odp_cos_flow_set_t;
+
+
+/**
+ * Set a member of the flow signature fields data set
+ *
+static inline odp_cos_flow_set_t
+odp_cos_flow_set( odp_cos_flow_set_t set,
+        enum odp_cos_hdr_flow_fields_e field)
+{
+        return set | (1U << field);
+}
+
+
+/**
+ * Test a member of the flow signature fields data set
+ *
+static inline bool
+odp_cos_flow_is_set( odp_cos_flow_set_t set,
+        enum odp_cos_hdr_flow_fields_e field)
+{
+        return (set & (1U << field)) != 0;
+}
+~~~~~
+
+These routines are intended to be used in support of the following flow signature APIs:
+
+@subsubsection cos_class_flow_sig odp_cos_class_flow_signature
+@verbatim
+/**
+ * Set up set of headers used to calculate a flow signature
+ * based on class-of-service.
+ *
+ * @param cos_id class of service instance identifier
+ * @param req_data_set requested data-set for flow signature calculation
+ *
+ * @return data-set that was successfully applied. All-zeros data set
+ * indicates a failure to assign any of the requested fields, or other
+ * error.
+ */
+
+odp_cos_flow_set_t
+odp_cos_class_flow_signature(odp_cos_t cos_id,
+        odp_cos_flow_set_t req_data_set);
+@endverbatim
+
+This OPTIONAL routine associates a fow set with a class of service for flow signature calculation.
+
+@subsubsection cos_port_flow_sig odp_cos_port_flow_signature
+@verbatim
+/**
+ * Set up set of headers used to calculate a flow signature
+ * based on ingress port.
+ *
+ * @param pktio_in ingress port identifier.
+ * @param req_data_set requested data-set for flow signature calculation
+ *
+ * @return data-set that was successfully applied. An all-zeros data-set
+ * indicates a failure to assign any of the requested fields, or other
+ * error.
+ */
+
+odp_cos_flow_set_t
+odp_cos_port_flow_signature(odp_pktio_t pktio_in,
+                odp_cos_flow_set_t req_data_set);
+@endverbatim
+
+@subsection pmr_routines Pattern Matching Rules Routines
+The following data structures SHOULD be implemented to support the definition of pattern matching routines by conforming ODP implementations:
+
+~~~~~{.c}
+/**
+ * PMR - Packet Matching Rule
+ * Up to 32 bit of ternary matching of one of the available header fields
+ *
+
+
+#define        ODP_PMR_INVAL ((odp_pmr_t)NULL)
+typedef struct odp_pmr_s *odp_pmr_t;
+~~~~~
+
+@subsecion terms Terms
+Terms are the elements of a PMR and are identified by the following enum:
+
+@verbatim
+enum odp_pmr_term_e {
+    ODP_PMR_ETHTYPE_0,        /**< Initial (outer) Ethertype only (*val=uint16_t)*/
+    ODP_PMR_ETHTYPE_X,        /**< Ethertype of most inner VLAN tag (*val=uint16_t)*/
+    ODP_PMR_VLAN_ID_0,        /**< First VLAN ID (outer) (*val=uint16_t) */
+    ODP_PMR_VLAN_ID_X,        /**< Last VLAN ID (inner) (*val=uint16_t) */
+    ODP_PMR_DMAC,             /**< destination MAC address (*val=uint64_t) */
+    ODP_PMR_IPPROTO,          /**< IP Protocol or IPv6 Next Header (*val=uint8_t) */
+    ODP_PMR_UDP_DPORT,        /**< Destination UDP port, implies IPPROTO=17 */
+    ODP_PMR_TCP_DPORT,        /**< Destination TCP port implies IPPROTO=6 */
+    ODP_PMR_UDP_SPORT,        /**< Source UDP Port (*val=uint16_t) */
+    ODP_PMR_TCP_SPORT,        /**< Source TCP port (*val=uint16_t) */
+    ODP_PMR_SIP_ADDR,         /**< Source IP address (uint32_t) */
+    ODP_PMR_DIP_ADDR,         /**< Destination IP address (uint32_t) */
+    ODP_PMR_SIP6_ADDR,        /**< Source IP address (uint8_t[16]) */
+    ODP_PMR_DIP6_ADDR,        /**< Destination IP address (uint8_t[16]) */
+    ODP_PMR_IPSEC_SPI,        /**< IPsec session identifier(*val=uint32_t) */
+    ODP_PMR_LD_VNI,           /**< NVGRE/VXLAN network identifier (*val=uint32_t) */
+
+
+    /** Inner header may repeat above values with this offset */
+    ODP_PMR_INNER_HDR_OFF=32
+};
+@endverbatim
+
+@subsubsection tunnel_considerations Tunnel Considerations
+Note that PMRs may be extended to support tunnels and tenants  (NVGRE, VXLAN) via the ODP_PMR_INNER_HDR_OFF enum.
+This enum is intended to be used as an “adder” to a PMR to indicate that the term refers to an inner header.
+For example, the term ODP_PMR_DMAC would refer to the destination MAC address of the packet if the packet is not a tunnel, or of the outer header (the tunnel) if the packet is a tunnel.
+To refer to the inner (tenant) destination MAC, the term would be specified as ODP_PMR_INNER_HDR_OFF+ODP_PMR_DMAC.
+
+@subsection pmr_apis PMR APIs
+The following APIs are provided to enable an ODP application to specify PMRs as a series of individual or cascaded terms:
+@subsubsection pmr_create_match odp_pmr_create_match
+@verbatim
+/**
+ * Create a packet match rule with mask and value
+ *
+ * @param term      is one value of the enumerated values supported
+ * @param val       is the value to match against the packet header
+ *                  in native byte order.
+ * @param   mask    is the mask to indicate which bits of the header
+ *                  should be matched ('1') and which should be ignored ('0')
+ * @param   val_sz  size of the ‘val’ and ‘mask’ arguments,
+ *                  that must match the value size requirement of the
+ *                  specific ‘term’.
+ *
+ * @return a handle of the matching rule or ODP_PMR_INVAL on error
+ */
+
+odp_pmr_t odp_pmr_create_match(enum odp_pmr_term_e term,
+                               const void *val, const void *mask, size_t val_sz);
+@endverbatim
+
+This routine creates a PMR that matches a single value to a term.
+
+@subsubsection pmr_create_range odp_pmr_create_range
+@verbatim
+/**
+ * Create a packet match rule with value range
+ *
+ * @param term      is one value of the enumerated values supported
+ * @param val1      is the lower bound of the header field range.
+ * @param val2      is the upper bound of the header field range.
+ * @param val_sz    size of the ‘val1’ and ‘val2’ arguments,
+ *                  that must match the value size requirement of the
+ *                  specific ‘term’.
+ *
+ * @return a handle of the matching rule or ODP_PMR_INVAL on error
+ * @note: Range is inclusive [val1..val2].
+ */
+
+odp_pmr_t odp_pmr_create_range(enum odp_pmr_term_e term,
+                                        const void *val1, const void *val2, size_t val_sz);
+@endverbatim
+
+This routine creates a PMR that matches an inclusive range of values to a term.
+
+@subsubsection pmr_destroy odp_pmr_destroy
+@verbatim
+/**
+ * Invalidate a packet match rule and vacate its resources
+ *
+ * @param pmr_id    the identifier of the PMR to be destroyed
+ *
+ * @return Success or ODP_PMR_INVALID if the specified pmr_id not found.
+ */
+
+int odp_pmr_destroy(odp_omr_t pmr_id);
+@endverbatim
+
+This routine destroys a previously created PMR.
+If the PMR is currently associated with an active class of service it is unpredictable at which point the match defined by the PMR is deactivated in terms of packet flow.
+However, implementations MUST ensure that a PMR is either matched or not matched in its entirety such that dynamic changes to PMRs do not result in partial matches.
+
+@subsubsection pktio_pmr_cos odp_pktio_pmr_cos
+@verbatim
+/**
+ * Apply a PMR to a pktio to assign a CoS.
+ *
+ * @param pmr_id     the id of the PMR to be activated
+ * @param src_pktio  the pktio to which this PMR is to be applied
+ * @param dst_cos    the CoS to be assigned by this PMR
+ *
+ * @return Success or ODP_PARAMETER_ERROR
+ */
+
+int odp_pktio_pmr_cos(odp_pmr_t pmr_id, odp_pktio_t src_pktio, odp_cos_t dst_cos);
+@endverbatim
+
+This routine links a pktio to a corresponding class of service via a specified PMR.
+Any packet received on the specified src_pktio that matches the specified pmr_id will be assigned to the specified dst_cos.
+If multiple PMRs match the implementation MAY define an inherent precedence or it MAY be unpredictable as to which PMR will determine the assigned CoS.
+For this reason applications SHOULD NOT be written to use conflicting or ambiguous PMR definitions.
+
+@subsubsection cos_pmr_cos odp_cos_pmr_cos
+@verbatim
+/**
+ * Cascade a PMR to refine packets from one CoS to another.
+ *
+ * @param pmr_id     the id of the PMR to be activated
+ * @param src_cos    the id of the CoS to be filtered
+ * @param dst_cos    the id of the CoS to be assigned to packets filtered
+ *                   from src_cos that match pmr_id.
+ *
+ * @return Success or ODP_PARAMETER_ERROR if an input is in error
+ *                 or ODP_IMPLEMENTATION_LIMIT if cascade depth is exceeded
+ */
+
+int odp_cos_pmr_cos(odp_pmr_t pmr_id, odp_cos_t src_cos, odp_cos_t dst_cos);
+@endverbatim
+
+This routine is used to cascade PMRs by passing packets assigned to the src_cos through another PMR.
+Those matching are reassigned to the specified dst_cos.
+Note that this process can be repeated to an implementation-defined maximum supported cascade depth.
+When cascades are defined, the actual class of service assigned to a packet is the result of the longest chain of PMRs that can be matched against the packet.
+
+For example, suppose the following sequence of PMRs is in effect:
+
+@verbatim
+odp_pktio_pmr_cos(pmr_idA, pktio_id, cos_idA);
+odp_cos_pmr_cos(pmr_idB, cos_idA, cos_idB);
+odp_cos_pmr_cos(pmr_idC, cos_idB, cos_idC);
+odp_cos_pmr_cos(pmr_idD, cos_idC, cos_idD);
+@endverbatim
+
+If a packet arrives on pktio_id that matches pmr_idA it is assigned to cos_idA.
+But since it is now on cos_idA it is further filtered by pmr_idB and if it matches is reassigned to cos_idB.
+This process continues until no further more specific match is found to determine the final CoS that the packet receives.
+
+Note that given this rule set a packet that matched pmr_idA and pmr_idC it would be assigned to cos_idA because the rule that can assign packets to pmr_idC is only applicable to packets that are assigned to cos_idB, not cos_idA.
+
+Using cascaded PMRs it is possible to build quite sophisticated filters (up to the implementation limits supported by a given platform).
+For example, one could add additional rules to the above set:
+
+@verbatim
+odp_cos_pmr_cos(pmr_idAC, cos_idA, cos_idC);
+odp_cos_pmr_cos(pmr_idAD, cos_idA, cos_idD);
+@endverbatim
+
+To cover cases where some packets on cos_idA should be further sorted to cos_idB while others should be sorted directly to cos_idC or cos_idD.
+Again it is the application’s responsibility to ensure that the cascades remain unambiguous and that loops be avoided (e.g., having rules that bounce packets between cos_idA and cos_idB endlessly).
+
+@subsection pmr_stats PMR Statistics
+Conforming ODP implementations SHOULD maintain statistics regarding PMRs and provide the following routines for retrieving them:
+
+@subsubsection pmr_match_count odp_pmr_match_count
+@verbatim
+/**
+ * Retrieve packet matcher statistics
+ *
+ * @param pmr_id    the id of the PMR from which to retrieve the count
+ *
+ * @return The current number of matches for a given matcher instance.
+ */
+
+signed long odp_pmr_match_count(odp_pmr_t pmr_id);
+@endverbatim
+
+@subsubsection pmr_terms_cap odp_pmr_terms_cap
+@verbatim
+/**
+ * Inquire about matching terms supported by the classifier
+ *
+ * @return A mask one bit per enumerated term, one for each of op_pmr_term_e
+ */
+
+unsigned long long odp_pmr_terms_cap(void);
+@endverbatim
+
+@subsubsection pmr_terms_avail odp_pmr_terms_avail
+@verbatim
+/**
+ * Return the number of packet matching terms available for use
+ *
+ * @return A number of packet matcher resources available for use.
+ */
+
+unsigned odp_pmr_terms_avail(void);
+@endverbatim
+
+@subsection pmr_composite_rules Pattern Matching Composite Routines
+As a shorthand, applications MAY express pattern matching rules using a table rather than constructing them term-by-term.
+ODP implementations MUST support both methods of rule specification but MAY have implementation-specific restrictions on the complexity of table-based rules they support.
+Note that some implementations MAY be able to implement tables directly while others MAY choose to implement tables by internally generating the equivalent set of term generating calls.
+
+@subsubsection pmr_table_structure PMR Table Structure
+@verbatim
+/**
+ * Following structure is used to define composite packet matching rules
+ * in the form of an array of individual match or range rules.
+ * The underlying platform may not support all or any specific combination
+ * of value match or range rules, and the application should take care
+ * of inspecting the return value when installing such rules, and perform
+ * appropriate fallback action.
+ */
+
+typedef struct odp_pmr_match_t {
+            enum odp_pmr_match_type_e {
+                    ODP_PMR_MASK,           /**< Match a masked set of bits */
+                    ODP_PMR_RANGE,          /**< Match an integer range */
+      } match_type;
+            union {
+                    struct {
+                            enum odp_pmr_term_e  term;
+                            const void              *val;
+                            const void              *mask;
+                            unsigned int             val_sz;
+                    } mask; /**< Match a masked set of bits */
+                    struct {
+                            enum odp_pmr_term_e  term;
+                            const void              *val1;
+                            const void              *val2;
+                            unsigned int             val_sz;
+                    } range; /**< Match an integer range */
+            };
+} odp_pmr_match_t;
+
+
+/** An opaque handle to a composite packet match rule-set */
+typedef struct odp_pmr_set_s *odp_pmr_set_t;
+@endverbatim;
+
+The above structure is used with the following APIs to implement table-based PMRs:
+
+@subsubsection pmr_match_set_create odp_pmr_match_set_create
+@verbatim
+/**
+ * Create a composite packet match rule
+ *
+ * @param num_terms  is the number of terms in the match rule.
+ * @param terms      is an array of num_terms entries, one entry per
+ *                   term desired.
+ * @param dst_cos    is the class-of-service to be assigned to packets
+ *                   that match the compound rule-set, or a subset thereof,
+ *                   if partly applied.
+ * @param pmr_set_id is the returned handle to the composite rule set.
+ *
+ * @return The return value may be a negative number indicating a general
+ * error, or a positive number indicating the number of ‘terms’ elements that
+ * have been successfully mapped to the underlying platform classification engine,
+ * and may be in the range from 1 to ‘num_terms’.
+ */
+
+int odp_pmr_match_set_create(int num_terms, odp_pmr_match_t *terms,
+                             odp_pmr_set_t *pmr_set_id);
+@endverbatim
+
+This routine is used to create a PMR match set.
+ It is the equivalent to a cascade of PMRs except that there are no “intermediate” classes of service defined.
+Instead, the entire match set either matches or does not match as a single entity.
+
+@subsubsection pmr_match_set_destroy odp_pmr_match_set_destroy
+@verbatim
+/**
+ * Function to delete a composite packet match rule set
+ *
+ * All of the resources pertaining to the match set associated with the
+ * class-of-service will be released, but the class-of-service will
+ * remain intact.
+ *
+ * @param pmr_set_id a composite rule-set handle returned when created.
+ *
+ * @note Depending on the implementation details, destroying a rule-set
+ * may not guarantee the availability of hardware resources to create the
+ * same or essentially similar rule-set.
+ */
+
+int odp_pmr_match_set_destroy(odp_pmr_set_t pmr_set_id);
+@endverbatim
+
+This routine destroys a PMR match set previously created by odp_pmr_match_set_create().
+
+@subsubsection pktio_pmr_match_set_cos odp_pktio_pmr_match_set_cos
+@verbatim
+/**
+ * Apply a PMR Match Set to a pktio to assign a CoS.
+ *
+ * @param pmr_set_id the id of the PMR match set to be activated
+ * @param src_pktio  the pktio to which this PMR match set is to be applied
+ * @param dst_cos    the CoS to be assigned by this PMR match set
+ *
+ * @return Success or ODP_PARAMETER_ERROR
+ */
+
+int odp_pktio_pmr_match_set_cos(odp_pmr_t pmr_id, odp_pktio_t src_pktio,
+                                odp_cos_t dst_cos);
+@endverbatim
+
+This routine is the same as odp_pktio_pmr_cos() except that it operates on PMR match sets rather than individual PMRs.
+
+@section items_pending Items pending resolution
+- Revise ‘odp_packet_io.h’ API with respect of default input queue per ‘pktio’ instance.
+- Revise ‘odp_queue.h’ API to support an arbitrary priority range, typically 8 priority levels with numeric priority values are platform-specific.
+- Add specific packet meta data fields to go into packet buffer which contain all meta data fields parsed and generated by the classifier, for later application use.
+
+@section implementation_notes Implementation Notes
+The following sections are not part of the specification, but shed light into the intent of the specification in several areas, describing some specific implementation approaches of these aspects.
+
+@subsection supporting_multi_pools Supporting multiple buffer pools
+The support of multiple buffer pools for containing packet buffers is optional, and may not be supported by some platforms.
+The importance of this feature stems from the need of protecting a networking application in the event of a congestion, or an attempted denial of service attack.
+Separating different classes of service to dedicated buffer pools allows the system to limit the memory resources that may be consumed by a particular type of traffic, thereby reserving buffer resources for other classes of traffic.
+
+In a software implementation, a packet would already be stored in memory when the classifier is invoked, and so it seems the classifier is unable to insert itself into the process of selecting a buffer pool.
+For obvious reasons the copying of a packet into a new buffer allocated from a different pool by the classifier is not a desirable solution.
+
+The recommended solution is to implement buffer pools in the form of buffer counters, while the actual buffers all belong to a single free list when not used to store a packet.
+In such an implementation, the classifier will be able to associate a packet already occupying a buffer to a different pool than the default by incrementing the buffer counter of the newly selected pool, and decrementing the counter representing the default pool.
+If however the selected pool counter has already reached a certain limit, the classifier would be able to e.g discard the packet instead of incrementing the destination pool counter, and thereby enforce the desirable semantics of distinct buffer pools per class of service.
+
+Other possible action that may be taken in response to running out of buffers or coming too low on buffers include back-pressure and random-early-detect with a discard probability inversely proportional to the number of free buffers in a pool.
+A related implementation topic is the ability to begin dropping some packets before a buffer pool is entirely exhausted.
+This is typically referred to as <em>Random Early Detect</em> (or “RED”).
+This is deemed to be a feature of the buffer pool implementation on a given platform, where in addition to a hard limit on the number of buffers that can be allocated to a pool, there can also be an option discard packets with a probability the increases as the number of outstanding buffers approaches that hard limit.
+
+@subsection resolving_gaps Resolving gaps between the API and hardware capabilities
+On platforms that support hardware packet accelerators, it is possible that the packet parsing and classification functionality is sufficient to address only a portion of the functionality specified within this document.
+This gap may be potentially bridged by augmenting the hardware classification capabilities with a software logic implemented as part of the platform.
+In that case, the platform will have to curve out a fraction of the processing resources and dedicate those to the software classification logic, which would be invoked for packets that the hardware platform was unable to classify completely.
+At the time of this writing, it is believed however that  the performance penalty that will be incurred as a result of software augmentation is unjustified for most application, i.e.
+it is preferred to lose the precision of packet prioritization while maintaining full hardware packet processing speed.
+
+@subsection loopback_case The case for loopback ports, and some of their uses
+In some applications, it may be desirable to be able to run a single packet through the classifier more than once.
+For example, an encrypted IPsec packet is received from a physical port.
+The encrypted packet is assigned a class of service based on its outer unencrypted header fields.
+Later, processing the packet entails decrypting the payload of the packet, authenticating it, and removing the original outer headers, which reveals a new set of protocol headers which need to be used to re-classify the packet, and assign it a new priority and buffer pool.
+An elegant solution for this use case would be to take advantage of “loopback” logical ports that may be implemented in certain platforms, by transmitting decapsulated packet into a loop-back port.
+The same packet then is received from a loop-back port and is examined by the classifier in accordance to the rules assigned to the loopback odp_pktio logical port instance.
+Similar mechanism may be applied to tunnel termination processing, fragment reassembly et al.
+
+@section related_topics Related Topics
+The following section discusses aspects of the ODP API that are not integral to the classifier, which only applies to ingress preprocessing.
+This section covers miscellaneous aspects of the API that need to be addressed, and are related to packet buffer processing and egress post-processing.
+Additional packet buffer manipulation APIs
+The need for these following calls are made evident by the need to encapsulate, i.e., remove some headers and add other, thereby changing the size of the headers of a packet during processing.
+
+@subsection initial_headroom Configuring initial packet buffer headroom
+The following function is provided to configure the pktio receive mechanism to (optionally)reserve some headroom between start of the first buffer to the first byte of the first packet data byte, which subsequently could be used to increase the header size “in-place”, without allocating additional gather list elements.
+If the request is granted, at least <req_bytes> bytes will be reserved in the front of the packet data:
+@verbatim
+int odp_pktio_set_headroom(odp_pktio_t port_id, unsigned req_bytes);
+@endverbatim
+The return value should be negative if the request can not be satisfied, or positive otherwise indicating the actual minimum headroom reserved.
+Note that the implementation may reserve more than the requested amount of headroom, and hence on platforms that are unable to support per-port (or per CoS) headroom configuration, a system-wide headroom configuration may be set to the largest of all such requests, and thus satisfy the requirement.
+In addition to the above per-port headroom configuration call, there should be an optional, per-CoS call that allows the reservation of different amounts of packet buffer headroom for packets that match certain criteria: for example, the following call allows the application to request that only packets that are expected to be encapsulated in a tunnel, be augmented with a large headroom amount, while packets that are received from a tunnel, and are IP fragments, be assigned a different headroom requirement (see definition for odp_cos_set_headroom() above.
+Egress packet scheduling, prioritization and ordering
+
+
+Open Issues
+* Parallel matching rules relative precedence.
+* Specify application-defined header field declaration APIs.
+* Review RFC 4301 for match requirements for IPsec SA, consider the use of L4 port ranges instead of or in addition to value & mask matching criteria.
+* Consider the type of packet checks should route a packet through the error CoS: L2 is a safe choice, but L3/L4 checksum or other exceptions deserve consideration.
+Usage Examples
+Following is a simple sample configuration using the API elements described above.
+TBD.
+
+*/