diff mbox

[ODP/PATCH,v1] ODP Buffer Segment Support API

Message ID 1412754609-4452-1-git-send-email-bala.manoharan@linaro.org
State New
Headers show

Commit Message

Balasubramanian Manoharan Oct. 8, 2014, 7:50 a.m. UTC
This patch contains ODP Buffer Management missing APIs
The intent of this patch is to port the missing APIs from Buffer Management design document into Linux-generic repo.
The dummy functions will be replaced during linux-generic implementation.

Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>
---
 platform/linux-generic/include/api/odp_buffer.h    | 203 ++++++++++++++++++++-
 .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
 platform/linux-generic/odp_buffer.c                | 120 ++++++++++++
 platform/linux-generic/odp_buffer_pool.c           |   7 +
 4 files changed, 351 insertions(+), 9 deletions(-)

Comments

Ola Liljedahl Oct. 8, 2014, 8:07 a.m. UTC | #1
As I wrote in my comment to the architecture discussion yesterday, I am
against segmentation for buffers. Or at least there must be the possibility
to create a buffer pool with guaranteed non-segmented buffers. Segmented
packets are OK but not all usages for buffers relate to packets. A lot of
internal usages (timeouts, SW messages, internal data structures) will not
be able to handle segmented buffers so *you must be able to force the
creation of buffer pools with non-segmented buffers.*

-- Ola


On 8 October 2014 09:50, Balasubramanian Manoharan <
bala.manoharan@linaro.org> wrote:

> This patch contains ODP Buffer Management missing APIs
> The intent of this patch is to port the missing APIs from Buffer
> Management design document into Linux-generic repo.
> The dummy functions will be replaced during linux-generic implementation.
>
> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>
> ---
>  platform/linux-generic/include/api/odp_buffer.h    | 203
> ++++++++++++++++++++-
>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
>  platform/linux-generic/odp_buffer.c                | 120 ++++++++++++
>  platform/linux-generic/odp_buffer_pool.c           |   7 +
>  4 files changed, 351 insertions(+), 9 deletions(-)
>
> diff --git a/platform/linux-generic/include/api/odp_buffer.h
> b/platform/linux-generic/include/api/odp_buffer.h
> index d8577fd..aeb75ed 100644
> --- a/platform/linux-generic/include/api/odp_buffer.h
> +++ b/platform/linux-generic/include/api/odp_buffer.h
> @@ -28,8 +28,34 @@ extern "C" {
>   */
>  typedef uint32_t odp_buffer_t;
>
> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
> +/**
> +* ODP buffer segment
> +*/
> +typedef uint32_t odp_buffer_segment_t;
>
> +/**
> +* ODP buffer type
> +*/
> +typedef enum odp_buffer_type {
> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */
> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold any other
> +                                       buffer type */
> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
> +                                       no additional metadata */
> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
> +} odp_buffer_type_e;
> +
> +/**
> +* ODP buffer options
> +*/
> +typedef enum odp_buffer_opts {
> +       ODP_BUFFER_OPTS_NONE,
> +       ODP_BUFFER_OPTS_UNSEGMENTED
> +} odp_buffer_opts_e;
> +
> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
>
>  /**
>   * Buffer start address
> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
>   */
>  int odp_buffer_type(odp_buffer_t buf);
>
> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any other
> -                                         buffer type */
> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional
> metadata */
> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
> -
> -
>  /**
>   * Tests if buffer is valid
>   *
> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
>  int odp_buffer_is_valid(odp_buffer_t buf);
>
>  /**
> + * Tests if buffer is segmented
> + *
> + * @param[in]  buf     Buffer handle
> + *
> + * @return             1 if buffer has more than one segment,
> + *                     otherwise 0
> + */
> +
> +int odp_buffer_is_segmented(odp_buffer_t buf);
> +
> +/**
> + * Get address and size of user meta data associated with a buffer
> + *
> + * @param[in]  buf             Buffer handle
> + * @param[out] udata_size      Number of bytes of user meta data available
> + *                             at the returned address
> + * @return                     Address of the user meta data for this
> buffer
> + *                             or NULL if the buffer has no user meta
> data.
> + */
> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
> +
> +/**
> + * Get address of user meta data associated with a buffer
> + *
> + * @param[in]  buf     Buffer handle
> + *
> + * @return             Address of the user meta data for this buffer
> + *                     or NULL if the buffer has no user meta data.
> + */
> +void *odp_buffer_udata_addr(odp_buffer_t buf);
> +
> +/**
> + * Get count of number of segments in a buffer
> + *
> + * @param[in]  buf     Buffer handle
> + *
> + * @return             Count of the number of segments in buf
> + */
> +size_t odp_buffer_segment_count(odp_buffer_t buf);
> +
> +/**
> + * Get the segment identifier for a buffer segment by index
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  ndx     Segment index of segment of interest
> + *
> + * @return             Segment identifier or ODP_SEGMENT_INVALID if the
> + *                     supplied ndx is out of range.
> + */
> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf, size_t
> ndx);
> +
> +/**
> + * Get the next segment identifier for a buffer segment
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  seg     Segment identifier of the previous segment
> + *
> + * @return             Segment identifier of the next segment,
> +                       or ODP_SEGMENT_INVALID.
> + */
> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
> +                                            odp_buffer_segment_t seg);
> +/**
> + * Get start address for a specified buffer segment
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  seg     Segment identifier of the buffer to be addressed
> + * @param[out] seglen  Returned number of bytes in this buffer
> + *                     segment available at returned address
> + *
> + * @return             Segment start address or NULL
> + */
> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
> +size_t *seglen);
> +
> +/**
> + *Unmap a buffer segment
> + *
> + * @param[in]  seg     Buffer segment handle
> + */
> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
> +
> +/**
> +* Get start address for a specified buffer offset
> +*
> +* @param[in]   buf     Buffer handle
> +* @param[in]   offset  Byte offset within the buffer to be addressed
> +* @param[out]  seglen  Returned number of bytes in this buffer
> +*                      segment available at returned address
> +*
> +* @return              Offset start address or NULL
> +*/
> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
> +size_t *seglen);
> +
> +/**
> + * Unmap a buffer segment by offset
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  offset  Buffer offset
> + */
> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
> +
> +/**
>   * Print buffer metadata to STDOUT
>   *
>   * @param buf      Buffer handle
> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
>   */
>  void odp_buffer_print(odp_buffer_t buf);
>
> +/**
> + * Split a buffer into two buffers at a specified split point
> + *
> + * @param[in]  buf     Handle of buffer to split
> + * @param[in]  offset  Byte offset within buf to split buffer
> + *
> + * @return             Buffer handle of the created split buffer
> + */
> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
> +
> +/**
> + * Join two buffers into a single buffer
> + *
> + * @param[in]  buf1    Buffer handle of first buffer to join
> + * @param[in]  buf2    Buffer handle of second buffer to join
> + *
> + * @return             Buffer handle of the joined buffer
> + */
> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);
> +
> +/**
> + * Trim a buffer at a specified trim point
> + *
> + * @param[in]  buf     Buffer handle of buffer to trim
> + * @param[in]  offset  byte offset within buf to trim
> + *
> + * @return             Handle of the trimmed buffer or
> + *                     ODP_BUFFER_INVALID if the operation was not
> performed
> + */
> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
> +/**
> + * Extend a buffer for a specified number of bytes
> + *
> + * @param[in]  buf     Buffer handle of buffer to expand
> + * @param[in]  ext     size, in bytes, of the extent to add to the
> + *                     existing buffer.
> + *
> + * @return             Handle of the extended buffer or ODP_BUFFER_INVALID
> + *                     if the operation was not performed
> + */
> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
> +
> +/**
> + * Clone a buffer, returning an exact copy of it
> + *
> + * @param[in]  buf     Buffer handle of buffer to duplicate
> + *
> + * @return             Handle of the duplicated buffer or
> ODP_BUFFER_INVALID
> + *                     if the operation was not performed
> + */
> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
> +
> +/**
> + * Copy a buffer, returning an exact copy of it
> + *
> + * @param[in]  buf     Buffer handle of buffer to copy
> + *
> + * @return             Handle of the copied buffer or ODP_BUFFER_INVALID
> + *                     if the operation was not performed
> + */
> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
> +
> +
>
>  #ifdef __cplusplus
>  }
> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
> b/platform/linux-generic/include/api/odp_buffer_pool.h
> index fe88898..f85d96c 100644
> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const char
> *name,
>
>
>  /**
> + * Get the next buffer pool from its predecessor
> + *
> + * @param[in]  pool            Buffer pool handle
> + * @param[out] name            Name of the pool
> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1 chars)
> + * @param[out] udata_size      Size of user meta data used by this pool.
> + * @param[out] buf_num         Number of buffers contained in this pool
> + * @param[out] buf_size        Default size of application data in each
> buffer
> + * @param[out] buf_type        Buffer type of the pool
> + * @param[out] buf_opts        Buffer options for this pool
> + * @param[out] predef          Predefined (1) or Created (0).
> + *
> + * @return                     Buffer pool handle
> + */
> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
> +                                      char *name, size_t *udata_size,
> +                                      size_t *buf_num, size_t *buf_size,
> +                                      enum odp_buffer_type *buf_type,
> +                                      enum odp_buffer_opts *buf_opts,
> +                                      uint32_t *predef);
> +/**
>   * Find a buffer pool by name
>   *
>   * @param name      Name of the pool
> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t pool);
>   */
>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
>
> +/**
> +* Allocate a buffer from a buffer pool
> +*
> +* @param[in]   pool    Pool handle
> +* @param[in]   size    Size of object to store in buffer
> +*
> +* @return              Buffer handle or ODP_BUFFER_INVALID
> +*/
> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size);
>
>  /**
>   * Buffer free
> diff --git a/platform/linux-generic/odp_buffer.c
> b/platform/linux-generic/odp_buffer.c
> index e54e0e7..7f4b4f0 100644
> --- a/platform/linux-generic/odp_buffer.c
> +++ b/platform/linux-generic/odp_buffer.c
> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
>  }
>
> +int odp_buffer_is_segmented(odp_buffer_t buf)
> +{
> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
> +
> +       if (buf_hdr->scatter.num_bufs == 0)
> +               return 0;
> +       else
> +               return 1;
> +}
> +
> +size_t odp_buffer_segment_count(odp_buffer_t buf)
> +{
> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
> +}
>
>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
>  {
> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
>         printf("\n%s\n", str);
>  }
>
> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
> +{
> +       (void)buf;
> +       (void)udata_size;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +void *odp_buffer_udata_addr(odp_buffer_t buf)
> +{
> +       (void)buf;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
> +                                                size_t ndx)
> +{
> +       (void)buf;
> +       (void)ndx;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
> +                                            odp_buffer_segment_t seg)
> +{
> +       (void)buf;
> +       (void)seg;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
> +                            size_t *seglen)
> +{
> +       (void)buf;
> +       (void)seg;
> +       (void)seglen;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
> +size_t *seglen)
> +{
> +       (void)buf;
> +       (void)offset;
> +       (void)seglen;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
> +{
> +       (void)buf;
> +       (void)offset;
> +       ODP_UNIMPLEMENTED();
> +       return;
> +}
> +
>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t buf_src)
>  {
>         (void)buf_dst;
>         (void)buf_src;
>  }
> +
> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
> +{
> +       (void)buf;
> +       (void)offset;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
> +{
> +       (void)buf1;
> +       (void)buf2;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
> +{
> +       (void)buf;
> +       (void)offset;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
> +{
> +       (void)buf;
> +       (void)ext;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
> +{
> +       (void)buf;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
> +{
> +       (void)buf;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> diff --git a/platform/linux-generic/odp_buffer_pool.c
> b/platform/linux-generic/odp_buffer_pool.c
> index a48d7d6..bff4db5 100644
> --- a/platform/linux-generic/odp_buffer_pool.c
> +++ b/platform/linux-generic/odp_buffer_pool.c
> @@ -471,6 +471,13 @@ odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t
> pool_hdl)
>         return handle.u32;
>  }
>
> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size)
> +{
> +       (void)pool;
> +       (void) size;
> +       ODP_ERR("%s function is yet to be implemented", __func__);
> +       return 0;
> +}
>
>  void odp_buffer_free(odp_buffer_t buf)
>  {
> --
> 2.0.1.472.g6f92e5f
>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
Bill Fischofer Oct. 16, 2014, 3:38 p.m. UTC | #2
From the buffer design doc (p. 8-9):
Buffer Pool Options

The odp_buffer_opts_e enum is used to specify additional options relating
to the buffer pool.  Buffer pool options defined are:


   -

   ODP_BUFFER_OPTS_NONE
   -

   ODP_BUFFER_OPTS_UNSEGMENTED


These options are additive so an application can simply specify a buf_opts
by ORing together the options needed.  Note that buffer pool options are
themselves OPTIONAL and a given implementation MAY fail the buffer pool
creation request with an appropriate errno if the requested option is not
supported by the underlying ODP implementation, with the exception that
UNSEGMENTED pools MUST be supported for non-packet types and for packet
types as long as the requested size is less than the implementation-defined
native packet segment size.

Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options with no
additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies that the
buffer pool should be unsegmented.

So unsegmented buffer pool support is available.  As far as RAW buffers go,
again from the doc (p. 14):
ODP_BUFFER_TYPE_RAWThis is the “basic” buffer type which simply consists of
a single fixed-sized block of contiguous memory.  Buffers of this type do
not support user meta data and the only built-in meta data supported for
this type of buffer are those that are statically computable, such as pool
and size. This type of buffer is entirely under application control and
most of the buffer APIs defined in this document are not available.  APIs
for this type of buffer are described in this document.

So RAW buffers are always unsegmented.  The intent is that Packets are by
default segmented but can be unsegmented while the other buffer types are
by default unsegmented but (with the exception of RAW buffers) can be made
segmented.  This is because all buffers start out as a single segment and
hence are unsegmented until they are expanded to overflow that single
segment.

Hope that clarifies things.  Again, this is all very straightforward and
only comes into play when actually needed.



On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin <Jerin.Jacob@caviumnetworks.com
> wrote:

>  If there is no valid use case for supporting segmentation for raw
> buffers then lets drop it. At least it will reduce the effort of
>
> implementing and testing/verification buffer APIs on  different platforms.
>
>
>  ------------------------------
> *From:* lng-odp-bounces@lists.linaro.org <lng-odp-bounces@lists.linaro.org>
> on behalf of Ola Liljedahl <ola.liljedahl@linaro.org>
> *Sent:* Wednesday, October 8, 2014 1:37 PM
> *To:* Balasubramanian Manoharan
> *Cc:* lng-odp@lists.linaro.org
> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>
>  As I wrote in my comment to the architecture discussion yesterday, I am
> against segmentation for buffers. Or at least there must be the possibility
> to create a buffer pool with guaranteed non-segmented buffers. Segmented
> packets are OK but not all usages for buffers relate to packets. A lot of
> internal usages (timeouts, SW messages, internal data structures) will not
> be able to handle segmented buffers so *you must be able to force the
> creation of buffer pools with non-segmented buffers.*
>
>  -- Ola
>
>
> On 8 October 2014 09:50, Balasubramanian Manoharan <
> bala.manoharan@linaro.org> wrote:
>
>> This patch contains ODP Buffer Management missing APIs
>> The intent of this patch is to port the missing APIs from Buffer
>> Management design document into Linux-generic repo.
>> The dummy functions will be replaced during linux-generic implementation.
>>
>> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>
>> ---
>>  platform/linux-generic/include/api/odp_buffer.h    | 203
>> ++++++++++++++++++++-
>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
>>  platform/linux-generic/odp_buffer.c                | 120 ++++++++++++
>>  platform/linux-generic/odp_buffer_pool.c           |   7 +
>>  4 files changed, 351 insertions(+), 9 deletions(-)
>>
>> diff --git a/platform/linux-generic/include/api/odp_buffer.h
>> b/platform/linux-generic/include/api/odp_buffer.h
>> index d8577fd..aeb75ed 100644
>> --- a/platform/linux-generic/include/api/odp_buffer.h
>> +++ b/platform/linux-generic/include/api/odp_buffer.h
>> @@ -28,8 +28,34 @@ extern "C" {
>>   */
>>  typedef uint32_t odp_buffer_t;
>>
>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>> +/**
>> +* ODP buffer segment
>> +*/
>> +typedef uint32_t odp_buffer_segment_t;
>>
>> +/**
>> +* ODP buffer type
>> +*/
>> +typedef enum odp_buffer_type {
>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */
>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold any
>> other
>> +                                       buffer type */
>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
>> +                                       no additional metadata */
>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
>> +} odp_buffer_type_e;
>> +
>> +/**
>> +* ODP buffer options
>> +*/
>> +typedef enum odp_buffer_opts {
>> +       ODP_BUFFER_OPTS_NONE,
>> +       ODP_BUFFER_OPTS_UNSEGMENTED
>> +} odp_buffer_opts_e;
>> +
>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
>>
>>  /**
>>   * Buffer start address
>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
>>   */
>>  int odp_buffer_type(odp_buffer_t buf);
>>
>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any other
>> -                                         buffer type */
>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional
>> metadata */
>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
>> -
>> -
>>  /**
>>   * Tests if buffer is valid
>>   *
>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
>>  int odp_buffer_is_valid(odp_buffer_t buf);
>>
>>  /**
>> + * Tests if buffer is segmented
>> + *
>> + * @param[in]  buf     Buffer handle
>> + *
>> + * @return             1 if buffer has more than one segment,
>> + *                     otherwise 0
>> + */
>> +
>> +int odp_buffer_is_segmented(odp_buffer_t buf);
>> +
>> +/**
>> + * Get address and size of user meta data associated with a buffer
>> + *
>> + * @param[in]  buf             Buffer handle
>> + * @param[out] udata_size      Number of bytes of user meta data
>> available
>> + *                             at the returned address
>> + * @return                     Address of the user meta data for this
>> buffer
>> + *                             or NULL if the buffer has no user meta
>> data.
>> + */
>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
>> +
>> +/**
>> + * Get address of user meta data associated with a buffer
>> + *
>> + * @param[in]  buf     Buffer handle
>> + *
>> + * @return             Address of the user meta data for this buffer
>> + *                     or NULL if the buffer has no user meta data.
>> + */
>> +void *odp_buffer_udata_addr(odp_buffer_t buf);
>> +
>> +/**
>> + * Get count of number of segments in a buffer
>> + *
>> + * @param[in]  buf     Buffer handle
>> + *
>> + * @return             Count of the number of segments in buf
>> + */
>> +size_t odp_buffer_segment_count(odp_buffer_t buf);
>> +
>> +/**
>> + * Get the segment identifier for a buffer segment by index
>> + *
>> + * @param[in]  buf     Buffer handle
>> + * @param[in]  ndx     Segment index of segment of interest
>> + *
>> + * @return             Segment identifier or ODP_SEGMENT_INVALID if the
>> + *                     supplied ndx is out of range.
>> + */
>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>> size_t ndx);
>> +
>> +/**
>> + * Get the next segment identifier for a buffer segment
>> + *
>> + * @param[in]  buf     Buffer handle
>> + * @param[in]  seg     Segment identifier of the previous segment
>> + *
>> + * @return             Segment identifier of the next segment,
>> +                       or ODP_SEGMENT_INVALID.
>> + */
>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>> +                                            odp_buffer_segment_t seg);
>> +/**
>> + * Get start address for a specified buffer segment
>> + *
>> + * @param[in]  buf     Buffer handle
>> + * @param[in]  seg     Segment identifier of the buffer to be addressed
>> + * @param[out] seglen  Returned number of bytes in this buffer
>> + *                     segment available at returned address
>> + *
>> + * @return             Segment start address or NULL
>> + */
>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
>> +size_t *seglen);
>> +
>> +/**
>> + *Unmap a buffer segment
>> + *
>> + * @param[in]  seg     Buffer segment handle
>> + */
>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
>> +
>> +/**
>> +* Get start address for a specified buffer offset
>> +*
>> +* @param[in]   buf     Buffer handle
>> +* @param[in]   offset  Byte offset within the buffer to be addressed
>> +* @param[out]  seglen  Returned number of bytes in this buffer
>> +*                      segment available at returned address
>> +*
>> +* @return              Offset start address or NULL
>> +*/
>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>> +size_t *seglen);
>> +
>> +/**
>> + * Unmap a buffer segment by offset
>> + *
>> + * @param[in]  buf     Buffer handle
>> + * @param[in]  offset  Buffer offset
>> + */
>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
>> +
>> +/**
>>   * Print buffer metadata to STDOUT
>>   *
>>   * @param buf      Buffer handle
>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
>>   */
>>  void odp_buffer_print(odp_buffer_t buf);
>>
>> +/**
>> + * Split a buffer into two buffers at a specified split point
>> + *
>> + * @param[in]  buf     Handle of buffer to split
>> + * @param[in]  offset  Byte offset within buf to split buffer
>> + *
>> + * @return             Buffer handle of the created split buffer
>> + */
>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
>> +
>> +/**
>> + * Join two buffers into a single buffer
>> + *
>> + * @param[in]  buf1    Buffer handle of first buffer to join
>> + * @param[in]  buf2    Buffer handle of second buffer to join
>> + *
>> + * @return             Buffer handle of the joined buffer
>> + */
>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);
>> +
>> +/**
>> + * Trim a buffer at a specified trim point
>> + *
>> + * @param[in]  buf     Buffer handle of buffer to trim
>> + * @param[in]  offset  byte offset within buf to trim
>> + *
>> + * @return             Handle of the trimmed buffer or
>> + *                     ODP_BUFFER_INVALID if the operation was not
>> performed
>> + */
>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
>> +/**
>> + * Extend a buffer for a specified number of bytes
>> + *
>> + * @param[in]  buf     Buffer handle of buffer to expand
>> + * @param[in]  ext     size, in bytes, of the extent to add to the
>> + *                     existing buffer.
>> + *
>> + * @return             Handle of the extended buffer or
>> ODP_BUFFER_INVALID
>> + *                     if the operation was not performed
>> + */
>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
>> +
>> +/**
>> + * Clone a buffer, returning an exact copy of it
>> + *
>> + * @param[in]  buf     Buffer handle of buffer to duplicate
>> + *
>> + * @return             Handle of the duplicated buffer or
>> ODP_BUFFER_INVALID
>> + *                     if the operation was not performed
>> + */
>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
>> +
>> +/**
>> + * Copy a buffer, returning an exact copy of it
>> + *
>> + * @param[in]  buf     Buffer handle of buffer to copy
>> + *
>> + * @return             Handle of the copied buffer or ODP_BUFFER_INVALID
>> + *                     if the operation was not performed
>> + */
>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
>> +
>> +
>>
>>  #ifdef __cplusplus
>>  }
>> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
>> b/platform/linux-generic/include/api/odp_buffer_pool.h
>> index fe88898..f85d96c 100644
>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
>> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const char
>> *name,
>>
>>
>>  /**
>> + * Get the next buffer pool from its predecessor
>> + *
>> + * @param[in]  pool            Buffer pool handle
>> + * @param[out] name            Name of the pool
>> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1 chars)
>> + * @param[out] udata_size      Size of user meta data used by this pool.
>> + * @param[out] buf_num         Number of buffers contained in this pool
>> + * @param[out] buf_size        Default size of application data in each
>> buffer
>> + * @param[out] buf_type        Buffer type of the pool
>> + * @param[out] buf_opts        Buffer options for this pool
>> + * @param[out] predef          Predefined (1) or Created (0).
>> + *
>> + * @return                     Buffer pool handle
>> + */
>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
>> +                                      char *name, size_t *udata_size,
>> +                                      size_t *buf_num, size_t *buf_size,
>> +                                      enum odp_buffer_type *buf_type,
>> +                                      enum odp_buffer_opts *buf_opts,
>> +                                      uint32_t *predef);
>> +/**
>>   * Find a buffer pool by name
>>   *
>>   * @param name      Name of the pool
>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t pool);
>>   */
>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
>>
>> +/**
>> +* Allocate a buffer from a buffer pool
>> +*
>> +* @param[in]   pool    Pool handle
>> +* @param[in]   size    Size of object to store in buffer
>> +*
>> +* @return              Buffer handle or ODP_BUFFER_INVALID
>> +*/
>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size);
>>
>>  /**
>>   * Buffer free
>> diff --git a/platform/linux-generic/odp_buffer.c
>> b/platform/linux-generic/odp_buffer.c
>> index e54e0e7..7f4b4f0 100644
>> --- a/platform/linux-generic/odp_buffer.c
>> +++ b/platform/linux-generic/odp_buffer.c
>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
>>  }
>>
>> +int odp_buffer_is_segmented(odp_buffer_t buf)
>> +{
>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>> +
>> +       if (buf_hdr->scatter.num_bufs == 0)
>> +               return 0;
>> +       else
>> +               return 1;
>> +}
>> +
>> +size_t odp_buffer_segment_count(odp_buffer_t buf)
>> +{
>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
>> +}
>>
>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
>>  {
>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
>>         printf("\n%s\n", str);
>>  }
>>
>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
>> +{
>> +       (void)buf;
>> +       (void)udata_size;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +void *odp_buffer_udata_addr(odp_buffer_t buf)
>> +{
>> +       (void)buf;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>> +                                                size_t ndx)
>> +{
>> +       (void)buf;
>> +       (void)ndx;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>> +                                            odp_buffer_segment_t seg)
>> +{
>> +       (void)buf;
>> +       (void)seg;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
>> +                            size_t *seglen)
>> +{
>> +       (void)buf;
>> +       (void)seg;
>> +       (void)seglen;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>> +size_t *seglen)
>> +{
>> +       (void)buf;
>> +       (void)offset;
>> +       (void)seglen;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
>> +{
>> +       (void)buf;
>> +       (void)offset;
>> +       ODP_UNIMPLEMENTED();
>> +       return;
>> +}
>> +
>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t buf_src)
>>  {
>>         (void)buf_dst;
>>         (void)buf_src;
>>  }
>> +
>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
>> +{
>> +       (void)buf;
>> +       (void)offset;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
>> +{
>> +       (void)buf1;
>> +       (void)buf2;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
>> +{
>> +       (void)buf;
>> +       (void)offset;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
>> +{
>> +       (void)buf;
>> +       (void)ext;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
>> +{
>> +       (void)buf;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
>> +{
>> +       (void)buf;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> diff --git a/platform/linux-generic/odp_buffer_pool.c
>> b/platform/linux-generic/odp_buffer_pool.c
>> index a48d7d6..bff4db5 100644
>> --- a/platform/linux-generic/odp_buffer_pool.c
>> +++ b/platform/linux-generic/odp_buffer_pool.c
>> @@ -471,6 +471,13 @@ odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t
>> pool_hdl)
>>         return handle.u32;
>>  }
>>
>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size)
>> +{
>> +       (void)pool;
>> +       (void) size;
>> +       ODP_ERR("%s function is yet to be implemented", __func__);
>> +       return 0;
>> +}
>>
>>  void odp_buffer_free(odp_buffer_t buf)
>>  {
>> --
>> 2.0.1.472.g6f92e5f
>>
>>
>> _______________________________________________
>> lng-odp mailing list
>> lng-odp@lists.linaro.org
>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>
>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
>
Bill Fischofer Oct. 16, 2014, 7:45 p.m. UTC | #3
Reviewed but need the following changes:

   1. odp_buffer_copy() - Add 2nd argument to reflect target buffer pool.
   Syntax should be: odp_buffer_t odp_buffer_copy(odp_buffer_t buf,
   odp_buffer_pool_t pool);

Thanks.

Bill

On Wed, Oct 8, 2014 at 2:50 AM, Balasubramanian Manoharan <
bala.manoharan@linaro.org> wrote:

> This patch contains ODP Buffer Management missing APIs
> The intent of this patch is to port the missing APIs from Buffer
> Management design document into Linux-generic repo.
> The dummy functions will be replaced during linux-generic implementation.
>
> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>
>
    Reviewed-by: Bill Fischofer <bill.fischofer@linaro.org>

> ---
>  platform/linux-generic/include/api/odp_buffer.h    | 203
> ++++++++++++++++++++-
>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
>  platform/linux-generic/odp_buffer.c                | 120 ++++++++++++
>  platform/linux-generic/odp_buffer_pool.c           |   7 +
>  4 files changed, 351 insertions(+), 9 deletions(-)
>
> diff --git a/platform/linux-generic/include/api/odp_buffer.h
> b/platform/linux-generic/include/api/odp_buffer.h
> index d8577fd..aeb75ed 100644
> --- a/platform/linux-generic/include/api/odp_buffer.h
> +++ b/platform/linux-generic/include/api/odp_buffer.h
> @@ -28,8 +28,34 @@ extern "C" {
>   */
>  typedef uint32_t odp_buffer_t;
>
> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
> +/**
> +* ODP buffer segment
> +*/
> +typedef uint32_t odp_buffer_segment_t;
>
> +/**
> +* ODP buffer type
> +*/
> +typedef enum odp_buffer_type {
> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */
> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold any other
> +                                       buffer type */
> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
> +                                       no additional metadata */
> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
> +} odp_buffer_type_e;
> +
> +/**
> +* ODP buffer options
> +*/
> +typedef enum odp_buffer_opts {
> +       ODP_BUFFER_OPTS_NONE,
> +       ODP_BUFFER_OPTS_UNSEGMENTED
> +} odp_buffer_opts_e;
> +
> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
>
>  /**
>   * Buffer start address
> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
>   */
>  int odp_buffer_type(odp_buffer_t buf);
>
> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any other
> -                                         buffer type */
> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional
> metadata */
> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
> -
> -
>  /**
>   * Tests if buffer is valid
>   *
> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
>  int odp_buffer_is_valid(odp_buffer_t buf);
>
>  /**
> + * Tests if buffer is segmented
> + *
> + * @param[in]  buf     Buffer handle
> + *
> + * @return             1 if buffer has more than one segment,
> + *                     otherwise 0
> + */
> +
> +int odp_buffer_is_segmented(odp_buffer_t buf);
> +
> +/**
> + * Get address and size of user meta data associated with a buffer
> + *
> + * @param[in]  buf             Buffer handle
> + * @param[out] udata_size      Number of bytes of user meta data available
> + *                             at the returned address
> + * @return                     Address of the user meta data for this
> buffer
> + *                             or NULL if the buffer has no user meta
> data.
> + */
> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
> +
> +/**
> + * Get address of user meta data associated with a buffer
> + *
> + * @param[in]  buf     Buffer handle
> + *
> + * @return             Address of the user meta data for this buffer
> + *                     or NULL if the buffer has no user meta data.
> + */
> +void *odp_buffer_udata_addr(odp_buffer_t buf);
> +
> +/**
> + * Get count of number of segments in a buffer
> + *
> + * @param[in]  buf     Buffer handle
> + *
> + * @return             Count of the number of segments in buf
> + */
> +size_t odp_buffer_segment_count(odp_buffer_t buf);
> +
> +/**
> + * Get the segment identifier for a buffer segment by index
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  ndx     Segment index of segment of interest
> + *
> + * @return             Segment identifier or ODP_SEGMENT_INVALID if the
> + *                     supplied ndx is out of range.
> + */
> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf, size_t
> ndx);
> +
> +/**
> + * Get the next segment identifier for a buffer segment
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  seg     Segment identifier of the previous segment
> + *
> + * @return             Segment identifier of the next segment,
> +                       or ODP_SEGMENT_INVALID.
> + */
> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
> +                                            odp_buffer_segment_t seg);
> +/**
> + * Get start address for a specified buffer segment
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  seg     Segment identifier of the buffer to be addressed
> + * @param[out] seglen  Returned number of bytes in this buffer
> + *                     segment available at returned address
> + *
> + * @return             Segment start address or NULL
> + */
> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
> +size_t *seglen);
> +
> +/**
> + *Unmap a buffer segment
> + *
> + * @param[in]  seg     Buffer segment handle
> + */
> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
> +
> +/**
> +* Get start address for a specified buffer offset
> +*
> +* @param[in]   buf     Buffer handle
> +* @param[in]   offset  Byte offset within the buffer to be addressed
> +* @param[out]  seglen  Returned number of bytes in this buffer
> +*                      segment available at returned address
> +*
> +* @return              Offset start address or NULL
> +*/
> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
> +size_t *seglen);
> +
> +/**
> + * Unmap a buffer segment by offset
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  offset  Buffer offset
> + */
> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
> +
> +/**
>   * Print buffer metadata to STDOUT
>   *
>   * @param buf      Buffer handle
> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
>   */
>  void odp_buffer_print(odp_buffer_t buf);
>
> +/**
> + * Split a buffer into two buffers at a specified split point
> + *
> + * @param[in]  buf     Handle of buffer to split
> + * @param[in]  offset  Byte offset within buf to split buffer
> + *
> + * @return             Buffer handle of the created split buffer
> + */
> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
> +
> +/**
> + * Join two buffers into a single buffer
> + *
> + * @param[in]  buf1    Buffer handle of first buffer to join
> + * @param[in]  buf2    Buffer handle of second buffer to join
> + *
> + * @return             Buffer handle of the joined buffer
> + */
> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);
> +
> +/**
> + * Trim a buffer at a specified trim point
> + *
> + * @param[in]  buf     Buffer handle of buffer to trim
> + * @param[in]  offset  byte offset within buf to trim
> + *
> + * @return             Handle of the trimmed buffer or
> + *                     ODP_BUFFER_INVALID if the operation was not
> performed
> + */
> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
> +/**
> + * Extend a buffer for a specified number of bytes
> + *
> + * @param[in]  buf     Buffer handle of buffer to expand
> + * @param[in]  ext     size, in bytes, of the extent to add to the
> + *                     existing buffer.
> + *
> + * @return             Handle of the extended buffer or ODP_BUFFER_INVALID
> + *                     if the operation was not performed
> + */
> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
> +
> +/**
> + * Clone a buffer, returning an exact copy of it
> + *
> + * @param[in]  buf     Buffer handle of buffer to duplicate
> + *
> + * @return             Handle of the duplicated buffer or
> ODP_BUFFER_INVALID
> + *                     if the operation was not performed
> + */
> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
> +
> +/**
> + * Copy a buffer, returning an exact copy of it
> + *
> + * @param[in]  buf     Buffer handle of buffer to copy
> + *
> + * @return             Handle of the copied buffer or ODP_BUFFER_INVALID
> + *                     if the operation was not performed
> + */
> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
> +
> +
>
>  #ifdef __cplusplus
>  }
> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
> b/platform/linux-generic/include/api/odp_buffer_pool.h
> index fe88898..f85d96c 100644
> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const char
> *name,
>
>
>  /**
> + * Get the next buffer pool from its predecessor
> + *
> + * @param[in]  pool            Buffer pool handle
> + * @param[out] name            Name of the pool
> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1 chars)
> + * @param[out] udata_size      Size of user meta data used by this pool.
> + * @param[out] buf_num         Number of buffers contained in this pool
> + * @param[out] buf_size        Default size of application data in each
> buffer
> + * @param[out] buf_type        Buffer type of the pool
> + * @param[out] buf_opts        Buffer options for this pool
> + * @param[out] predef          Predefined (1) or Created (0).
> + *
> + * @return                     Buffer pool handle
> + */
> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
> +                                      char *name, size_t *udata_size,
> +                                      size_t *buf_num, size_t *buf_size,
> +                                      enum odp_buffer_type *buf_type,
> +                                      enum odp_buffer_opts *buf_opts,
> +                                      uint32_t *predef);
> +/**
>   * Find a buffer pool by name
>   *
>   * @param name      Name of the pool
> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t pool);
>   */
>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
>
> +/**
> +* Allocate a buffer from a buffer pool
> +*
> +* @param[in]   pool    Pool handle
> +* @param[in]   size    Size of object to store in buffer
> +*
> +* @return              Buffer handle or ODP_BUFFER_INVALID
> +*/
> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size);
>
>  /**
>   * Buffer free
> diff --git a/platform/linux-generic/odp_buffer.c
> b/platform/linux-generic/odp_buffer.c
> index e54e0e7..7f4b4f0 100644
> --- a/platform/linux-generic/odp_buffer.c
> +++ b/platform/linux-generic/odp_buffer.c
> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
>  }
>
> +int odp_buffer_is_segmented(odp_buffer_t buf)
> +{
> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
> +
> +       if (buf_hdr->scatter.num_bufs == 0)
> +               return 0;
> +       else
> +               return 1;
> +}
> +
> +size_t odp_buffer_segment_count(odp_buffer_t buf)
> +{
> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
> +}
>
>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
>  {
> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
>         printf("\n%s\n", str);
>  }
>
> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
> +{
> +       (void)buf;
> +       (void)udata_size;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +void *odp_buffer_udata_addr(odp_buffer_t buf)
> +{
> +       (void)buf;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
> +                                                size_t ndx)
> +{
> +       (void)buf;
> +       (void)ndx;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
> +                                            odp_buffer_segment_t seg)
> +{
> +       (void)buf;
> +       (void)seg;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
> +                            size_t *seglen)
> +{
> +       (void)buf;
> +       (void)seg;
> +       (void)seglen;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
> +size_t *seglen)
> +{
> +       (void)buf;
> +       (void)offset;
> +       (void)seglen;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
> +{
> +       (void)buf;
> +       (void)offset;
> +       ODP_UNIMPLEMENTED();
> +       return;
> +}
> +
>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t buf_src)
>  {
>         (void)buf_dst;
>         (void)buf_src;
>  }
> +
> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
> +{
> +       (void)buf;
> +       (void)offset;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
> +{
> +       (void)buf1;
> +       (void)buf2;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
> +{
> +       (void)buf;
> +       (void)offset;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
> +{
> +       (void)buf;
> +       (void)ext;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
> +{
> +       (void)buf;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
> +{
> +       (void)buf;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> diff --git a/platform/linux-generic/odp_buffer_pool.c
> b/platform/linux-generic/odp_buffer_pool.c
> index a48d7d6..bff4db5 100644
> --- a/platform/linux-generic/odp_buffer_pool.c
> +++ b/platform/linux-generic/odp_buffer_pool.c
> @@ -471,6 +471,13 @@ odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t
> pool_hdl)
>         return handle.u32;
>  }
>
> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size)
> +{
> +       (void)pool;
> +       (void) size;
> +       ODP_ERR("%s function is yet to be implemented", __func__);
> +       return 0;
> +}
>
>  void odp_buffer_free(odp_buffer_t buf)
>  {
> --
> 2.0.1.472.g6f92e5f
>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
Bill Fischofer Oct. 17, 2014, 10:17 a.m. UTC | #4
I'm not sure how to understand these two statements:

1. There's no use case for segmented buffers
2. We should optimize for the common case (with segments)

These seem contradictory.

The use case for segmented buffers is that some platforms have a HW-defined
and managed segmented buffer model. If we insist that the application be
able to specify and control packet segment sizes we are making the decision
to exclude such platforms from supporting ODP.  The optimization suggested
is precisely what is being proposed here.  By default packets are assumed
to be contained in implementation-managed segmented buffers and the first
segment will be large enough to contain all packet headers for
non-pathological cases.  The case where the application wishes to traverse
the entire packet in SW is expected to be rare because in the data plane
you simply do not have the cycles to do this at line rate for all packets.

As for having both odp_buffer_xxx() and odp_packet_xxx() APIs, this is
simply syntax to avoid the constant need for explicit conversion functions
since unlike C++, C does not support generic functions.  So you cannot pass
an odp_packet_t to a function that expects an odp_buffer_t argument without
a conversion call.  Do we really want to force applications to constantly
be writing code like:

odp_buffer_xxx(odp_packet_to_buffer(pkt),...)

rather than

odp_packet_xxx(pkt,...)

Not only is this awkward, it is also inefficient.  By having the explicit
odp_packet_xxx() calls, the implementation is free to optimize these
references in whatever manner is appropriate to that implementation.  For
some this may be a simple preprocessor-type expansion while for others
there may be more sophisticated handling.  But the application should
neither know nor care about how the implementation chooses to do this.

On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN - FI/Espoo) <
petri.savolainen@nsn.com> wrote:

>  Hi,
>
>
>
> This is also my opinion. There’s no use case for segmented buffers in v1.0
> - so let’s keep it simple and define that buffers (and thus buffer pools)
> are always unsegmented. Segmentation comes into play only with packets (and
> only with those packets that cannot fit into a single buffer). For example,
> if implementation has max buffer size 256, any packets larger than that are
> segmented and segments are handled with packet_seg_xxx calls.
>
>
>
> Also, I’d propose that we optimize for the common case (with segments) -
> so that the odp_packet_t handle would refer always to the head of packet
> segment. If the first segment (data/data_len pointed by the odp_packet_t)
> carries all data application is interested in (=protocol headers), the
> application would not have to use the segment API at all. Most applications
> would not see any difference between small/large or segmented/unsegmented
> packets as long as all headers fit into the first segment.
>
>
>
> -Petri
>
>
>
>
>
> *From:* lng-odp-bounces@lists.linaro.org [mailto:
> lng-odp-bounces@lists.linaro.org] *On Behalf Of *ext Jacob, Jerin
> *Sent:* Friday, October 17, 2014 9:34 AM
> *To:* Bill Fischofer
> *Cc:* lng-odp@lists.linaro.org
> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>
>
>
> The need for segment API infrastructure is very clear.The question is, Do
> we need separate APIs for
>
> segment management at odp_buffer_segment* AND odp_packet_segment* levels ?
>
> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always
> unsegmented and if there is a
>
> API for odp_packet_segement* then there will be not be any consumer for
> odp_buffer_segment* API for 1.0​
>
>
>  ------------------------------
>
> *From:* Bill Fischofer <bill.fischofer@linaro.org>
> *Sent:* Thursday, October 16, 2014 9:08 PM
> *To:* Jacob, Jerin
> *Cc:* Ola Liljedahl; Balasubramanian Manoharan; lng-odp@lists.linaro.org
> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>
>
>
> From the buffer design doc (p. 8-9):
>  *Buffer Pool Options*
>
> The *odp_buffer_opts_e* enum is used to specify additional options
> relating to the buffer pool.  Buffer pool options defined are:
>
>
> ·     ODP_BUFFER_OPTS_NONE
>
> ·     ODP_BUFFER_OPTS_UNSEGMENTED
>
>
> These options are additive so an application can simply specify a buf_opts
> by ORing together the options needed.  Note that buffer pool options are
> themselves OPTIONAL and a given implementation MAY fail the buffer pool
> creation request with an appropriate *errno* if the requested option is
> not supported by the underlying ODP implementation, with the exception that
> UNSEGMENTED pools MUST be supported for non-packet types and for packet
> types as long as the requested size is less than the implementation-defined
> native packet segment size.
>
>
> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options with no
> additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies that the
> buffer pool should be unsegmented.
>
>
>   So unsegmented buffer pool support is available.  As far as RAW buffers
> go, again from the doc (p. 14):
>   *ODP_BUFFER_TYPE_RAW*
>
> This is the “basic” buffer type which simply consists of a single
> fixed-sized block of contiguous memory.  Buffers of this type do not
> support user meta data and the only built-in meta data supported for this
> type of buffer are those that are statically computable, such as pool and
> size. This type of buffer is entirely under application control and most of
> the buffer APIs defined in this document are not available.  APIs for this
> type of buffer are described in this document.
>
>
>
> So RAW buffers are always unsegmented.  The intent is that Packets are by
> default segmented but can be unsegmented while the other buffer types are
> by default unsegmented but (with the exception of RAW buffers) can be made
> segmented.  This is because all buffers start out as a single segment and
> hence are unsegmented until they are expanded to overflow that single
> segment.
>
>
>
> Hope that clarifies things.  Again, this is all very straightforward and
> only comes into play when actually needed.
>
>
>
>
>
>
>
> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin <
> Jerin.Jacob@caviumnetworks.com> wrote:
>
> If there is no valid use case for supporting segmentation for raw buffers
> then lets drop it. At least it will reduce the effort of
>
> implementing and testing/verification buffer APIs on  different platforms.
>
>
>   ------------------------------
>
> *From:* lng-odp-bounces@lists.linaro.org <lng-odp-bounces@lists.linaro.org>
> on behalf of Ola Liljedahl <ola.liljedahl@linaro.org>
> *Sent:* Wednesday, October 8, 2014 1:37 PM
> *To:* Balasubramanian Manoharan
> *Cc:* lng-odp@lists.linaro.org
> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>
>
>
> As I wrote in my comment to the architecture discussion yesterday, I am
> against segmentation for buffers. Or at least there must be the possibility
> to create a buffer pool with guaranteed non-segmented buffers. Segmented
> packets are OK but not all usages for buffers relate to packets. A lot of
> internal usages (timeouts, SW messages, internal data structures) will not
> be able to handle segmented buffers so *you must be able to force the
> creation of buffer pools with non-segmented buffers.*
>
>
>
> -- Ola
>
>
>
>
>
> On 8 October 2014 09:50, Balasubramanian Manoharan <
> bala.manoharan@linaro.org> wrote:
>
> This patch contains ODP Buffer Management missing APIs
> The intent of this patch is to port the missing APIs from Buffer
> Management design document into Linux-generic repo.
> The dummy functions will be replaced during linux-generic implementation.
>
> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>
> ---
>  platform/linux-generic/include/api/odp_buffer.h    | 203
> ++++++++++++++++++++-
>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
>  platform/linux-generic/odp_buffer.c                | 120 ++++++++++++
>  platform/linux-generic/odp_buffer_pool.c           |   7 +
>  4 files changed, 351 insertions(+), 9 deletions(-)
>
> diff --git a/platform/linux-generic/include/api/odp_buffer.h
> b/platform/linux-generic/include/api/odp_buffer.h
> index d8577fd..aeb75ed 100644
> --- a/platform/linux-generic/include/api/odp_buffer.h
> +++ b/platform/linux-generic/include/api/odp_buffer.h
> @@ -28,8 +28,34 @@ extern "C" {
>   */
>  typedef uint32_t odp_buffer_t;
>
> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
> +/**
> +* ODP buffer segment
> +*/
> +typedef uint32_t odp_buffer_segment_t;
>
> +/**
> +* ODP buffer type
> +*/
> +typedef enum odp_buffer_type {
> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */
> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold any other
> +                                       buffer type */
> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
> +                                       no additional metadata */
> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
> +} odp_buffer_type_e;
> +
> +/**
> +* ODP buffer options
> +*/
> +typedef enum odp_buffer_opts {
> +       ODP_BUFFER_OPTS_NONE,
> +       ODP_BUFFER_OPTS_UNSEGMENTED
> +} odp_buffer_opts_e;
> +
> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
>
>  /**
>   * Buffer start address
> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
>   */
>  int odp_buffer_type(odp_buffer_t buf);
>
> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any other
> -                                         buffer type */
> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional
> metadata */
> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
> -
> -
>  /**
>   * Tests if buffer is valid
>   *
> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
>  int odp_buffer_is_valid(odp_buffer_t buf);
>
>  /**
> + * Tests if buffer is segmented
> + *
> + * @param[in]  buf     Buffer handle
> + *
> + * @return             1 if buffer has more than one segment,
> + *                     otherwise 0
> + */
> +
> +int odp_buffer_is_segmented(odp_buffer_t buf);
> +
> +/**
> + * Get address and size of user meta data associated with a buffer
> + *
> + * @param[in]  buf             Buffer handle
> + * @param[out] udata_size      Number of bytes of user meta data available
> + *                             at the returned address
> + * @return                     Address of the user meta data for this
> buffer
> + *                             or NULL if the buffer has no user meta
> data.
> + */
> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
> +
> +/**
> + * Get address of user meta data associated with a buffer
> + *
> + * @param[in]  buf     Buffer handle
> + *
> + * @return             Address of the user meta data for this buffer
> + *                     or NULL if the buffer has no user meta data.
> + */
> +void *odp_buffer_udata_addr(odp_buffer_t buf);
> +
> +/**
> + * Get count of number of segments in a buffer
> + *
> + * @param[in]  buf     Buffer handle
> + *
> + * @return             Count of the number of segments in buf
> + */
> +size_t odp_buffer_segment_count(odp_buffer_t buf);
> +
> +/**
> + * Get the segment identifier for a buffer segment by index
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  ndx     Segment index of segment of interest
> + *
> + * @return             Segment identifier or ODP_SEGMENT_INVALID if the
> + *                     supplied ndx is out of range.
> + */
> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf, size_t
> ndx);
> +
> +/**
> + * Get the next segment identifier for a buffer segment
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  seg     Segment identifier of the previous segment
> + *
> + * @return             Segment identifier of the next segment,
> +                       or ODP_SEGMENT_INVALID.
> + */
> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
> +                                            odp_buffer_segment_t seg);
> +/**
> + * Get start address for a specified buffer segment
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  seg     Segment identifier of the buffer to be addressed
> + * @param[out] seglen  Returned number of bytes in this buffer
> + *                     segment available at returned address
> + *
> + * @return             Segment start address or NULL
> + */
> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
> +size_t *seglen);
> +
> +/**
> + *Unmap a buffer segment
> + *
> + * @param[in]  seg     Buffer segment handle
> + */
> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
> +
> +/**
> +* Get start address for a specified buffer offset
> +*
> +* @param[in]   buf     Buffer handle
> +* @param[in]   offset  Byte offset within the buffer to be addressed
> +* @param[out]  seglen  Returned number of bytes in this buffer
> +*                      segment available at returned address
> +*
> +* @return              Offset start address or NULL
> +*/
> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
> +size_t *seglen);
> +
> +/**
> + * Unmap a buffer segment by offset
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  offset  Buffer offset
> + */
> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
> +
> +/**
>   * Print buffer metadata to STDOUT
>   *
>   * @param buf      Buffer handle
> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
>   */
>  void odp_buffer_print(odp_buffer_t buf);
>
> +/**
> + * Split a buffer into two buffers at a specified split point
> + *
> + * @param[in]  buf     Handle of buffer to split
> + * @param[in]  offset  Byte offset within buf to split buffer
> + *
> + * @return             Buffer handle of the created split buffer
> + */
> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
> +
> +/**
> + * Join two buffers into a single buffer
> + *
> + * @param[in]  buf1    Buffer handle of first buffer to join
> + * @param[in]  buf2    Buffer handle of second buffer to join
> + *
> + * @return             Buffer handle of the joined buffer
> + */
> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);
> +
> +/**
> + * Trim a buffer at a specified trim point
> + *
> + * @param[in]  buf     Buffer handle of buffer to trim
> + * @param[in]  offset  byte offset within buf to trim
> + *
> + * @return             Handle of the trimmed buffer or
> + *                     ODP_BUFFER_INVALID if the operation was not
> performed
> + */
> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
> +/**
> + * Extend a buffer for a specified number of bytes
> + *
> + * @param[in]  buf     Buffer handle of buffer to expand
> + * @param[in]  ext     size, in bytes, of the extent to add to the
> + *                     existing buffer.
> + *
> + * @return             Handle of the extended buffer or ODP_BUFFER_INVALID
> + *                     if the operation was not performed
> + */
> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
> +
> +/**
> + * Clone a buffer, returning an exact copy of it
> + *
> + * @param[in]  buf     Buffer handle of buffer to duplicate
> + *
> + * @return             Handle of the duplicated buffer or
> ODP_BUFFER_INVALID
> + *                     if the operation was not performed
> + */
> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
> +
> +/**
> + * Copy a buffer, returning an exact copy of it
> + *
> + * @param[in]  buf     Buffer handle of buffer to copy
> + *
> + * @return             Handle of the copied buffer or ODP_BUFFER_INVALID
> + *                     if the operation was not performed
> + */
> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
> +
> +
>
>  #ifdef __cplusplus
>  }
> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
> b/platform/linux-generic/include/api/odp_buffer_pool.h
> index fe88898..f85d96c 100644
> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const char
> *name,
>
>
>  /**
> + * Get the next buffer pool from its predecessor
> + *
> + * @param[in]  pool            Buffer pool handle
> + * @param[out] name            Name of the pool
> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1 chars)
> + * @param[out] udata_size      Size of user meta data used by this pool.
> + * @param[out] buf_num         Number of buffers contained in this pool
> + * @param[out] buf_size        Default size of application data in each
> buffer
> + * @param[out] buf_type        Buffer type of the pool
> + * @param[out] buf_opts        Buffer options for this pool
> + * @param[out] predef          Predefined (1) or Created (0).
> + *
> + * @return                     Buffer pool handle
> + */
> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
> +                                      char *name, size_t *udata_size,
> +                                      size_t *buf_num, size_t *buf_size,
> +                                      enum odp_buffer_type *buf_type,
> +                                      enum odp_buffer_opts *buf_opts,
> +                                      uint32_t *predef);
> +/**
>   * Find a buffer pool by name
>   *
>   * @param name      Name of the pool
> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t pool);
>   */
>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
>
> +/**
> +* Allocate a buffer from a buffer pool
> +*
> +* @param[in]   pool    Pool handle
> +* @param[in]   size    Size of object to store in buffer
> +*
> +* @return              Buffer handle or ODP_BUFFER_INVALID
> +*/
> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size);
>
>  /**
>   * Buffer free
> diff --git a/platform/linux-generic/odp_buffer.c
> b/platform/linux-generic/odp_buffer.c
> index e54e0e7..7f4b4f0 100644
> --- a/platform/linux-generic/odp_buffer.c
> +++ b/platform/linux-generic/odp_buffer.c
> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
>  }
>
> +int odp_buffer_is_segmented(odp_buffer_t buf)
> +{
> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
> +
> +       if (buf_hdr->scatter.num_bufs == 0)
> +               return 0;
> +       else
> +               return 1;
> +}
> +
> +size_t odp_buffer_segment_count(odp_buffer_t buf)
> +{
> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
> +}
>
>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
>  {
> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
>         printf("\n%s\n", str);
>  }
>
> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
> +{
> +       (void)buf;
> +       (void)udata_size;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +void *odp_buffer_udata_addr(odp_buffer_t buf)
> +{
> +       (void)buf;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
> +                                                size_t ndx)
> +{
> +       (void)buf;
> +       (void)ndx;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
> +                                            odp_buffer_segment_t seg)
> +{
> +       (void)buf;
> +       (void)seg;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
> +                            size_t *seglen)
> +{
> +       (void)buf;
> +       (void)seg;
> +       (void)seglen;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
> +size_t *seglen)
> +{
> +       (void)buf;
> +       (void)offset;
> +       (void)seglen;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
> +{
> +       (void)buf;
> +       (void)offset;
> +       ODP_UNIMPLEMENTED();
> +       return;
> +}
> +
>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t buf_src)
>  {
>         (void)buf_dst;
>         (void)buf_src;
>  }
> +
> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
> +{
> +       (void)buf;
> +       (void)offset;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
> +{
> +       (void)buf1;
> +       (void)buf2;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
> +{
> +       (void)buf;
> +       (void)offset;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
> +{
> +       (void)buf;
> +       (void)ext;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
> +{
> +       (void)buf;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
> +{
> +       (void)buf;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> diff --git a/platform/linux-generic/odp_buffer_pool.c
> b/platform/linux-generic/odp_buffer_pool.c
> index a48d7d6..bff4db5 100644
> --- a/platform/linux-generic/odp_buffer_pool.c
> +++ b/platform/linux-generic/odp_buffer_pool.c
> @@ -471,6 +471,13 @@ odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t
> pool_hdl)
>         return handle.u32;
>  }
>
> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size)
> +{
> +       (void)pool;
> +       (void) size;
> +       ODP_ERR("%s function is yet to be implemented", __func__);
> +       return 0;
> +}
>
>  void odp_buffer_free(odp_buffer_t buf)
>  {
> --
> 2.0.1.472.g6f92e5f
>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
>
>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
>
>
Bill Fischofer Oct. 17, 2014, 12:33 p.m. UTC | #5
I agree that packets are the buffer type that most likely uses segments,
however there are many advantages to putting this support in the base class
rather than the subclass independent of the number of buffer subclasses
that will use this support today.

   - It's simpler
   - It's more extensible
   - It results in cleaner and more efficient application code

Allow me to expand on these points.  First simplicity.  Call the work
required to support segmentation in the implementation X.  That X is going
to be pretty much constant no matter where it is done.  But if the
implementation has a choice between doing X at a low level vs. doing it at
a high level then it's simpler for the implementation to do it once and be
done with it.  If the implementation does it at a higher level then it is
either constrained to map that higher-level implementation to be built on a
set of lower-level functions that may or may not be appropriate or else it
needs to do a completely parallel implementation that is optimal but highly
duplicative.

Extensibility should be clear.  If at some future point we decide
segmentation would be useful for some new buffer type (e.g., IPC) then
that's trivial to do if the base class supports it and awkward if it's only
part of packets.

From an application standpoint, it's cleaner because the packet APIs are
just wrappers around their corresponding buffer APIs and can be mapped
directly.  Otherwise we have a set of APIs that don't map and are not
easily translatable.

With regard to efficient segment access, that's what the odp_packet_addr()
routine provides--one-step fast-path addressability to the first segment of
a packet.  An odp_packet_t is an abstract opaque type.  It is not, and
cannot be treated as an address by the application.

Does that make sense?

Bill




On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN - FI/Espoo) <
petri.savolainen@nsn.com> wrote:

>  Hi,
>
>
>
> 1. The only segmentation use case is for segmented packet, not for
> segmented buffers.
>
>
>
> 2. Common case for packets is that everything application needs is in the
> first segment. Odp_packet_t could refer always into that “first segment”,
> so that application (in the common case) would not need to use
> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.
>
>
>
> When buffer level features are minimized, the need for
> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All packet
> manipulation should happen through odp_packet_xxx(pkt, …) calls.
>
>
>
>
>
> -Petri
>
>
>
>
>
> *From:* ext Bill Fischofer [mailto:bill.fischofer@linaro.org]
> *Sent:* Friday, October 17, 2014 1:17 PM
> *To:* Savolainen, Petri (NSN - FI/Espoo)
> *Cc:* ext Jacob, Jerin; lng-odp@lists.linaro.org
>
> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>
>
>
> I'm not sure how to understand these two statements:
>
>
>
> 1. There's no use case for segmented buffers
>
> 2. We should optimize for the common case (with segments)
>
>
>
> These seem contradictory.
>
>
>
> The use case for segmented buffers is that some platforms have a
> HW-defined and managed segmented buffer model. If we insist that the
> application be able to specify and control packet segment sizes we are
> making the decision to exclude such platforms from supporting ODP.  The
> optimization suggested is precisely what is being proposed here.  By
> default packets are assumed to be contained in implementation-managed
> segmented buffers and the first segment will be large enough to contain all
> packet headers for non-pathological cases.  The case where the application
> wishes to traverse the entire packet in SW is expected to be rare because
> in the data plane you simply do not have the cycles to do this at line rate
> for all packets.
>
>
>
> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs, this is
> simply syntax to avoid the constant need for explicit conversion functions
> since unlike C++, C does not support generic functions.  So you cannot pass
> an odp_packet_t to a function that expects an odp_buffer_t argument without
> a conversion call.  Do we really want to force applications to constantly
> be writing code like:
>
>
>
> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)
>
>
>
> rather than
>
>
>
> odp_packet_xxx(pkt,...)
>
>
>
> Not only is this awkward, it is also inefficient.  By having the explicit
> odp_packet_xxx() calls, the implementation is free to optimize these
> references in whatever manner is appropriate to that implementation.  For
> some this may be a simple preprocessor-type expansion while for others
> there may be more sophisticated handling.  But the application should
> neither know nor care about how the implementation chooses to do this.
>
>
>
> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN - FI/Espoo) <
> petri.savolainen@nsn.com> wrote:
>
> Hi,
>
>
>
> This is also my opinion. There’s no use case for segmented buffers in v1.0
> - so let’s keep it simple and define that buffers (and thus buffer pools)
> are always unsegmented. Segmentation comes into play only with packets (and
> only with those packets that cannot fit into a single buffer). For example,
> if implementation has max buffer size 256, any packets larger than that are
> segmented and segments are handled with packet_seg_xxx calls.
>
>
>
> Also, I’d propose that we optimize for the common case (with segments) -
> so that the odp_packet_t handle would refer always to the head of packet
> segment. If the first segment (data/data_len pointed by the odp_packet_t)
> carries all data application is interested in (=protocol headers), the
> application would not have to use the segment API at all. Most applications
> would not see any difference between small/large or segmented/unsegmented
> packets as long as all headers fit into the first segment.
>
>
>
> -Petri
>
>
>
>
>
> *From:* lng-odp-bounces@lists.linaro.org [mailto:
> lng-odp-bounces@lists.linaro.org] *On Behalf Of *ext Jacob, Jerin
> *Sent:* Friday, October 17, 2014 9:34 AM
> *To:* Bill Fischofer
> *Cc:* lng-odp@lists.linaro.org
> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>
>
>
> The need for segment API infrastructure is very clear.The question is, Do
> we need separate APIs for
>
> segment management at odp_buffer_segment* AND odp_packet_segment* levels ?
>
> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always
> unsegmented and if there is a
>
> API for odp_packet_segement* then there will be not be any consumer for
> odp_buffer_segment* API for 1.0​
>
>
>  ------------------------------
>
> *From:* Bill Fischofer <bill.fischofer@linaro.org>
> *Sent:* Thursday, October 16, 2014 9:08 PM
> *To:* Jacob, Jerin
> *Cc:* Ola Liljedahl; Balasubramanian Manoharan; lng-odp@lists.linaro.org
> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>
>
>
> From the buffer design doc (p. 8-9):
>  *Buffer Pool Options*
>
> The *odp_buffer_opts_e* enum is used to specify additional options
> relating to the buffer pool.  Buffer pool options defined are:
>
>
> ·     ODP_BUFFER_OPTS_NONE
>
> ·     ODP_BUFFER_OPTS_UNSEGMENTED
>
>
> These options are additive so an application can simply specify a buf_opts
> by ORing together the options needed.  Note that buffer pool options are
> themselves OPTIONAL and a given implementation MAY fail the buffer pool
> creation request with an appropriate *errno* if the requested option is
> not supported by the underlying ODP implementation, with the exception that
> UNSEGMENTED pools MUST be supported for non-packet types and for packet
> types as long as the requested size is less than the implementation-defined
> native packet segment size.
>
>
> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options with no
> additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies that the
> buffer pool should be unsegmented.
>
>
> So unsegmented buffer pool support is available.  As far as RAW buffers
> go, again from the doc (p. 14):
>  *ODP_BUFFER_TYPE_RAW*
>
> This is the “basic” buffer type which simply consists of a single
> fixed-sized block of contiguous memory.  Buffers of this type do not
> support user meta data and the only built-in meta data supported for this
> type of buffer are those that are statically computable, such as pool and
> size. This type of buffer is entirely under application control and most of
> the buffer APIs defined in this document are not available.  APIs for this
> type of buffer are described in this document.
>
>
>
> So RAW buffers are always unsegmented.  The intent is that Packets are by
> default segmented but can be unsegmented while the other buffer types are
> by default unsegmented but (with the exception of RAW buffers) can be made
> segmented.  This is because all buffers start out as a single segment and
> hence are unsegmented until they are expanded to overflow that single
> segment.
>
>
>
> Hope that clarifies things.  Again, this is all very straightforward and
> only comes into play when actually needed.
>
>
>
>
>
>
>
> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin <
> Jerin.Jacob@caviumnetworks.com> wrote:
>
> If there is no valid use case for supporting segmentation for raw buffers
> then lets drop it. At least it will reduce the effort of
>
> implementing and testing/verification buffer APIs on  different platforms.
>
>
>   ------------------------------
>
> *From:* lng-odp-bounces@lists.linaro.org <lng-odp-bounces@lists.linaro.org>
> on behalf of Ola Liljedahl <ola.liljedahl@linaro.org>
> *Sent:* Wednesday, October 8, 2014 1:37 PM
> *To:* Balasubramanian Manoharan
> *Cc:* lng-odp@lists.linaro.org
> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>
>
>
> As I wrote in my comment to the architecture discussion yesterday, I am
> against segmentation for buffers. Or at least there must be the possibility
> to create a buffer pool with guaranteed non-segmented buffers. Segmented
> packets are OK but not all usages for buffers relate to packets. A lot of
> internal usages (timeouts, SW messages, internal data structures) will not
> be able to handle segmented buffers so *you must be able to force the
> creation of buffer pools with non-segmented buffers.*
>
>
>
> -- Ola
>
>
>
>
>
> On 8 October 2014 09:50, Balasubramanian Manoharan <
> bala.manoharan@linaro.org> wrote:
>
> This patch contains ODP Buffer Management missing APIs
> The intent of this patch is to port the missing APIs from Buffer
> Management design document into Linux-generic repo.
> The dummy functions will be replaced during linux-generic implementation.
>
> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>
> ---
>  platform/linux-generic/include/api/odp_buffer.h    | 203
> ++++++++++++++++++++-
>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
>  platform/linux-generic/odp_buffer.c                | 120 ++++++++++++
>  platform/linux-generic/odp_buffer_pool.c           |   7 +
>  4 files changed, 351 insertions(+), 9 deletions(-)
>
> diff --git a/platform/linux-generic/include/api/odp_buffer.h
> b/platform/linux-generic/include/api/odp_buffer.h
> index d8577fd..aeb75ed 100644
> --- a/platform/linux-generic/include/api/odp_buffer.h
> +++ b/platform/linux-generic/include/api/odp_buffer.h
> @@ -28,8 +28,34 @@ extern "C" {
>   */
>  typedef uint32_t odp_buffer_t;
>
> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
> +/**
> +* ODP buffer segment
> +*/
> +typedef uint32_t odp_buffer_segment_t;
>
> +/**
> +* ODP buffer type
> +*/
> +typedef enum odp_buffer_type {
> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */
> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold any other
> +                                       buffer type */
> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
> +                                       no additional metadata */
> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
> +} odp_buffer_type_e;
> +
> +/**
> +* ODP buffer options
> +*/
> +typedef enum odp_buffer_opts {
> +       ODP_BUFFER_OPTS_NONE,
> +       ODP_BUFFER_OPTS_UNSEGMENTED
> +} odp_buffer_opts_e;
> +
> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
>
>  /**
>   * Buffer start address
> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
>   */
>  int odp_buffer_type(odp_buffer_t buf);
>
> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any other
> -                                         buffer type */
> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional
> metadata */
> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
> -
> -
>  /**
>   * Tests if buffer is valid
>   *
> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
>  int odp_buffer_is_valid(odp_buffer_t buf);
>
>  /**
> + * Tests if buffer is segmented
> + *
> + * @param[in]  buf     Buffer handle
> + *
> + * @return             1 if buffer has more than one segment,
> + *                     otherwise 0
> + */
> +
> +int odp_buffer_is_segmented(odp_buffer_t buf);
> +
> +/**
> + * Get address and size of user meta data associated with a buffer
> + *
> + * @param[in]  buf             Buffer handle
> + * @param[out] udata_size      Number of bytes of user meta data available
> + *                             at the returned address
> + * @return                     Address of the user meta data for this
> buffer
> + *                             or NULL if the buffer has no user meta
> data.
> + */
> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
> +
> +/**
> + * Get address of user meta data associated with a buffer
> + *
> + * @param[in]  buf     Buffer handle
> + *
> + * @return             Address of the user meta data for this buffer
> + *                     or NULL if the buffer has no user meta data.
> + */
> +void *odp_buffer_udata_addr(odp_buffer_t buf);
> +
> +/**
> + * Get count of number of segments in a buffer
> + *
> + * @param[in]  buf     Buffer handle
> + *
> + * @return             Count of the number of segments in buf
> + */
> +size_t odp_buffer_segment_count(odp_buffer_t buf);
> +
> +/**
> + * Get the segment identifier for a buffer segment by index
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  ndx     Segment index of segment of interest
> + *
> + * @return             Segment identifier or ODP_SEGMENT_INVALID if the
> + *                     supplied ndx is out of range.
> + */
> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf, size_t
> ndx);
> +
> +/**
> + * Get the next segment identifier for a buffer segment
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  seg     Segment identifier of the previous segment
> + *
> + * @return             Segment identifier of the next segment,
> +                       or ODP_SEGMENT_INVALID.
> + */
> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
> +                                            odp_buffer_segment_t seg);
> +/**
> + * Get start address for a specified buffer segment
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  seg     Segment identifier of the buffer to be addressed
> + * @param[out] seglen  Returned number of bytes in this buffer
> + *                     segment available at returned address
> + *
> + * @return             Segment start address or NULL
> + */
> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
> +size_t *seglen);
> +
> +/**
> + *Unmap a buffer segment
> + *
> + * @param[in]  seg     Buffer segment handle
> + */
> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
> +
> +/**
> +* Get start address for a specified buffer offset
> +*
> +* @param[in]   buf     Buffer handle
> +* @param[in]   offset  Byte offset within the buffer to be addressed
> +* @param[out]  seglen  Returned number of bytes in this buffer
> +*                      segment available at returned address
> +*
> +* @return              Offset start address or NULL
> +*/
> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
> +size_t *seglen);
> +
> +/**
> + * Unmap a buffer segment by offset
> + *
> + * @param[in]  buf     Buffer handle
> + * @param[in]  offset  Buffer offset
> + */
> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
> +
> +/**
>   * Print buffer metadata to STDOUT
>   *
>   * @param buf      Buffer handle
> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
>   */
>  void odp_buffer_print(odp_buffer_t buf);
>
> +/**
> + * Split a buffer into two buffers at a specified split point
> + *
> + * @param[in]  buf     Handle of buffer to split
> + * @param[in]  offset  Byte offset within buf to split buffer
> + *
> + * @return             Buffer handle of the created split buffer
> + */
> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
> +
> +/**
> + * Join two buffers into a single buffer
> + *
> + * @param[in]  buf1    Buffer handle of first buffer to join
> + * @param[in]  buf2    Buffer handle of second buffer to join
> + *
> + * @return             Buffer handle of the joined buffer
> + */
> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);
> +
> +/**
> + * Trim a buffer at a specified trim point
> + *
> + * @param[in]  buf     Buffer handle of buffer to trim
> + * @param[in]  offset  byte offset within buf to trim
> + *
> + * @return             Handle of the trimmed buffer or
> + *                     ODP_BUFFER_INVALID if the operation was not
> performed
> + */
> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
> +/**
> + * Extend a buffer for a specified number of bytes
> + *
> + * @param[in]  buf     Buffer handle of buffer to expand
> + * @param[in]  ext     size, in bytes, of the extent to add to the
> + *                     existing buffer.
> + *
> + * @return             Handle of the extended buffer or ODP_BUFFER_INVALID
> + *                     if the operation was not performed
> + */
> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
> +
> +/**
> + * Clone a buffer, returning an exact copy of it
> + *
> + * @param[in]  buf     Buffer handle of buffer to duplicate
> + *
> + * @return             Handle of the duplicated buffer or
> ODP_BUFFER_INVALID
> + *                     if the operation was not performed
> + */
> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
> +
> +/**
> + * Copy a buffer, returning an exact copy of it
> + *
> + * @param[in]  buf     Buffer handle of buffer to copy
> + *
> + * @return             Handle of the copied buffer or ODP_BUFFER_INVALID
> + *                     if the operation was not performed
> + */
> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
> +
> +
>
>  #ifdef __cplusplus
>  }
> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
> b/platform/linux-generic/include/api/odp_buffer_pool.h
> index fe88898..f85d96c 100644
> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const char
> *name,
>
>
>  /**
> + * Get the next buffer pool from its predecessor
> + *
> + * @param[in]  pool            Buffer pool handle
> + * @param[out] name            Name of the pool
> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1 chars)
> + * @param[out] udata_size      Size of user meta data used by this pool.
> + * @param[out] buf_num         Number of buffers contained in this pool
> + * @param[out] buf_size        Default size of application data in each
> buffer
> + * @param[out] buf_type        Buffer type of the pool
> + * @param[out] buf_opts        Buffer options for this pool
> + * @param[out] predef          Predefined (1) or Created (0).
> + *
> + * @return                     Buffer pool handle
> + */
> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
> +                                      char *name, size_t *udata_size,
> +                                      size_t *buf_num, size_t *buf_size,
> +                                      enum odp_buffer_type *buf_type,
> +                                      enum odp_buffer_opts *buf_opts,
> +                                      uint32_t *predef);
> +/**
>   * Find a buffer pool by name
>   *
>   * @param name      Name of the pool
> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t pool);
>   */
>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
>
> +/**
> +* Allocate a buffer from a buffer pool
> +*
> +* @param[in]   pool    Pool handle
> +* @param[in]   size    Size of object to store in buffer
> +*
> +* @return              Buffer handle or ODP_BUFFER_INVALID
> +*/
> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size);
>
>  /**
>   * Buffer free
> diff --git a/platform/linux-generic/odp_buffer.c
> b/platform/linux-generic/odp_buffer.c
> index e54e0e7..7f4b4f0 100644
> --- a/platform/linux-generic/odp_buffer.c
> +++ b/platform/linux-generic/odp_buffer.c
> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
>  }
>
> +int odp_buffer_is_segmented(odp_buffer_t buf)
> +{
> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
> +
> +       if (buf_hdr->scatter.num_bufs == 0)
> +               return 0;
> +       else
> +               return 1;
> +}
> +
> +size_t odp_buffer_segment_count(odp_buffer_t buf)
> +{
> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
> +}
>
>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
>  {
> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
>         printf("\n%s\n", str);
>  }
>
> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
> +{
> +       (void)buf;
> +       (void)udata_size;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +void *odp_buffer_udata_addr(odp_buffer_t buf)
> +{
> +       (void)buf;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
> +                                                size_t ndx)
> +{
> +       (void)buf;
> +       (void)ndx;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
> +                                            odp_buffer_segment_t seg)
> +{
> +       (void)buf;
> +       (void)seg;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
> +                            size_t *seglen)
> +{
> +       (void)buf;
> +       (void)seg;
> +       (void)seglen;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
> +size_t *seglen)
> +{
> +       (void)buf;
> +       (void)offset;
> +       (void)seglen;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
> +{
> +       (void)buf;
> +       (void)offset;
> +       ODP_UNIMPLEMENTED();
> +       return;
> +}
> +
>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t buf_src)
>  {
>         (void)buf_dst;
>         (void)buf_src;
>  }
> +
> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
> +{
> +       (void)buf;
> +       (void)offset;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
> +{
> +       (void)buf1;
> +       (void)buf2;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
> +{
> +       (void)buf;
> +       (void)offset;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
> +{
> +       (void)buf;
> +       (void)ext;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
> +{
> +       (void)buf;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
> +{
> +       (void)buf;
> +       ODP_UNIMPLEMENTED();
> +       return 0;
> +}
> +
> diff --git a/platform/linux-generic/odp_buffer_pool.c
> b/platform/linux-generic/odp_buffer_pool.c
> index a48d7d6..bff4db5 100644
> --- a/platform/linux-generic/odp_buffer_pool.c
> +++ b/platform/linux-generic/odp_buffer_pool.c
> @@ -471,6 +471,13 @@ odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t
> pool_hdl)
>         return handle.u32;
>  }
>
> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size)
> +{
> +       (void)pool;
> +       (void) size;
> +       ODP_ERR("%s function is yet to be implemented", __func__);
> +       return 0;
> +}
>
>  void odp_buffer_free(odp_buffer_t buf)
>  {
> --
> 2.0.1.472.g6f92e5f
>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
>
>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
>
>
>
>
Ola Dahl Oct. 17, 2014, 12:45 p.m. UTC | #6
Hi,

I do not think it is wise to put features in the base class "just in case"
they would be needed in some future (not yet known) subclass.

So if the concept of segmentation is relevant for packets but not for
timers then I think it should be implemented as a feature of packets.

Best regards,

Ola D

On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer <bill.fischofer@linaro.org>
wrote:

> I agree that packets are the buffer type that most likely uses segments,
> however there are many advantages to putting this support in the base class
> rather than the subclass independent of the number of buffer subclasses
> that will use this support today.
>
>    - It's simpler
>    - It's more extensible
>    - It results in cleaner and more efficient application code
>
> Allow me to expand on these points.  First simplicity.  Call the work
> required to support segmentation in the implementation X.  That X is going
> to be pretty much constant no matter where it is done.  But if the
> implementation has a choice between doing X at a low level vs. doing it at
> a high level then it's simpler for the implementation to do it once and be
> done with it.  If the implementation does it at a higher level then it is
> either constrained to map that higher-level implementation to be built on a
> set of lower-level functions that may or may not be appropriate or else it
> needs to do a completely parallel implementation that is optimal but highly
> duplicative.
>
> Extensibility should be clear.  If at some future point we decide
> segmentation would be useful for some new buffer type (e.g., IPC) then
> that's trivial to do if the base class supports it and awkward if it's only
> part of packets.
>
> From an application standpoint, it's cleaner because the packet APIs are
> just wrappers around their corresponding buffer APIs and can be mapped
> directly.  Otherwise we have a set of APIs that don't map and are not
> easily translatable.
>
> With regard to efficient segment access, that's what the odp_packet_addr()
> routine provides--one-step fast-path addressability to the first segment of
> a packet.  An odp_packet_t is an abstract opaque type.  It is not, and
> cannot be treated as an address by the application.
>
> Does that make sense?
>
> Bill
>
>
>
>
> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN - FI/Espoo) <
> petri.savolainen@nsn.com> wrote:
>
>>  Hi,
>>
>>
>>
>> 1. The only segmentation use case is for segmented packet, not for
>> segmented buffers.
>>
>>
>>
>> 2. Common case for packets is that everything application needs is in the
>> first segment. Odp_packet_t could refer always into that “first segment”,
>> so that application (in the common case) would not need to use
>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.
>>
>>
>>
>> When buffer level features are minimized, the need for
>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All packet
>> manipulation should happen through odp_packet_xxx(pkt, …) calls.
>>
>>
>>
>>
>>
>> -Petri
>>
>>
>>
>>
>>
>> *From:* ext Bill Fischofer [mailto:bill.fischofer@linaro.org]
>> *Sent:* Friday, October 17, 2014 1:17 PM
>> *To:* Savolainen, Petri (NSN - FI/Espoo)
>> *Cc:* ext Jacob, Jerin; lng-odp@lists.linaro.org
>>
>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>
>>
>>
>> I'm not sure how to understand these two statements:
>>
>>
>>
>> 1. There's no use case for segmented buffers
>>
>> 2. We should optimize for the common case (with segments)
>>
>>
>>
>> These seem contradictory.
>>
>>
>>
>> The use case for segmented buffers is that some platforms have a
>> HW-defined and managed segmented buffer model. If we insist that the
>> application be able to specify and control packet segment sizes we are
>> making the decision to exclude such platforms from supporting ODP.  The
>> optimization suggested is precisely what is being proposed here.  By
>> default packets are assumed to be contained in implementation-managed
>> segmented buffers and the first segment will be large enough to contain all
>> packet headers for non-pathological cases.  The case where the application
>> wishes to traverse the entire packet in SW is expected to be rare because
>> in the data plane you simply do not have the cycles to do this at line rate
>> for all packets.
>>
>>
>>
>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs, this is
>> simply syntax to avoid the constant need for explicit conversion functions
>> since unlike C++, C does not support generic functions.  So you cannot pass
>> an odp_packet_t to a function that expects an odp_buffer_t argument without
>> a conversion call.  Do we really want to force applications to constantly
>> be writing code like:
>>
>>
>>
>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)
>>
>>
>>
>> rather than
>>
>>
>>
>> odp_packet_xxx(pkt,...)
>>
>>
>>
>> Not only is this awkward, it is also inefficient.  By having the explicit
>> odp_packet_xxx() calls, the implementation is free to optimize these
>> references in whatever manner is appropriate to that implementation.  For
>> some this may be a simple preprocessor-type expansion while for others
>> there may be more sophisticated handling.  But the application should
>> neither know nor care about how the implementation chooses to do this.
>>
>>
>>
>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN - FI/Espoo) <
>> petri.savolainen@nsn.com> wrote:
>>
>> Hi,
>>
>>
>>
>> This is also my opinion. There’s no use case for segmented buffers in
>> v1.0 - so let’s keep it simple and define that buffers (and thus buffer
>> pools) are always unsegmented. Segmentation comes into play only with
>> packets (and only with those packets that cannot fit into a single buffer).
>> For example, if implementation has max buffer size 256, any packets larger
>> than that are segmented and segments are handled with packet_seg_xxx calls.
>>
>>
>>
>> Also, I’d propose that we optimize for the common case (with segments) -
>> so that the odp_packet_t handle would refer always to the head of packet
>> segment. If the first segment (data/data_len pointed by the odp_packet_t)
>> carries all data application is interested in (=protocol headers), the
>> application would not have to use the segment API at all. Most applications
>> would not see any difference between small/large or segmented/unsegmented
>> packets as long as all headers fit into the first segment.
>>
>>
>>
>> -Petri
>>
>>
>>
>>
>>
>> *From:* lng-odp-bounces@lists.linaro.org [mailto:
>> lng-odp-bounces@lists.linaro.org] *On Behalf Of *ext Jacob, Jerin
>> *Sent:* Friday, October 17, 2014 9:34 AM
>> *To:* Bill Fischofer
>> *Cc:* lng-odp@lists.linaro.org
>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>
>>
>>
>> The need for segment API infrastructure is very clear.The question is, Do
>> we need separate APIs for
>>
>> segment management at odp_buffer_segment* AND odp_packet_segment* levels ?
>>
>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always
>> unsegmented and if there is a
>>
>> API for odp_packet_segement* then there will be not be any consumer for
>> odp_buffer_segment* API for 1.0​
>>
>>
>>  ------------------------------
>>
>> *From:* Bill Fischofer <bill.fischofer@linaro.org>
>> *Sent:* Thursday, October 16, 2014 9:08 PM
>> *To:* Jacob, Jerin
>> *Cc:* Ola Liljedahl; Balasubramanian Manoharan; lng-odp@lists.linaro.org
>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>
>>
>>
>> From the buffer design doc (p. 8-9):
>>  *Buffer Pool Options*
>>
>> The *odp_buffer_opts_e* enum is used to specify additional options
>> relating to the buffer pool.  Buffer pool options defined are:
>>
>>
>> ·     ODP_BUFFER_OPTS_NONE
>>
>> ·     ODP_BUFFER_OPTS_UNSEGMENTED
>>
>>
>> These options are additive so an application can simply specify a
>> buf_opts by ORing together the options needed.  Note that buffer pool
>> options are themselves OPTIONAL and a given implementation MAY fail the
>> buffer pool creation request with an appropriate *errno* if the
>> requested option is not supported by the underlying ODP implementation,
>> with the exception that UNSEGMENTED pools MUST be supported for non-packet
>> types and for packet types as long as the requested size is less than the
>> implementation-defined native packet segment size.
>>
>>
>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options with no
>> additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies that the
>> buffer pool should be unsegmented.
>>
>>
>> So unsegmented buffer pool support is available.  As far as RAW buffers
>> go, again from the doc (p. 14):
>>  *ODP_BUFFER_TYPE_RAW*
>>
>> This is the “basic” buffer type which simply consists of a single
>> fixed-sized block of contiguous memory.  Buffers of this type do not
>> support user meta data and the only built-in meta data supported for this
>> type of buffer are those that are statically computable, such as pool and
>> size. This type of buffer is entirely under application control and most of
>> the buffer APIs defined in this document are not available.  APIs for this
>> type of buffer are described in this document.
>>
>>
>>
>> So RAW buffers are always unsegmented.  The intent is that Packets are by
>> default segmented but can be unsegmented while the other buffer types are
>> by default unsegmented but (with the exception of RAW buffers) can be made
>> segmented.  This is because all buffers start out as a single segment and
>> hence are unsegmented until they are expanded to overflow that single
>> segment.
>>
>>
>>
>> Hope that clarifies things.  Again, this is all very straightforward and
>> only comes into play when actually needed.
>>
>>
>>
>>
>>
>>
>>
>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin <
>> Jerin.Jacob@caviumnetworks.com> wrote:
>>
>> If there is no valid use case for supporting segmentation for raw buffers
>> then lets drop it. At least it will reduce the effort of
>>
>> implementing and testing/verification buffer APIs on  different platforms.
>>
>>
>>   ------------------------------
>>
>> *From:* lng-odp-bounces@lists.linaro.org <
>> lng-odp-bounces@lists.linaro.org> on behalf of Ola Liljedahl <
>> ola.liljedahl@linaro.org>
>> *Sent:* Wednesday, October 8, 2014 1:37 PM
>> *To:* Balasubramanian Manoharan
>> *Cc:* lng-odp@lists.linaro.org
>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>
>>
>>
>> As I wrote in my comment to the architecture discussion yesterday, I am
>> against segmentation for buffers. Or at least there must be the possibility
>> to create a buffer pool with guaranteed non-segmented buffers. Segmented
>> packets are OK but not all usages for buffers relate to packets. A lot of
>> internal usages (timeouts, SW messages, internal data structures) will not
>> be able to handle segmented buffers so *you must be able to force the
>> creation of buffer pools with non-segmented buffers.*
>>
>>
>>
>> -- Ola
>>
>>
>>
>>
>>
>> On 8 October 2014 09:50, Balasubramanian Manoharan <
>> bala.manoharan@linaro.org> wrote:
>>
>> This patch contains ODP Buffer Management missing APIs
>> The intent of this patch is to port the missing APIs from Buffer
>> Management design document into Linux-generic repo.
>> The dummy functions will be replaced during linux-generic implementation.
>>
>> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>
>> ---
>>  platform/linux-generic/include/api/odp_buffer.h    | 203
>> ++++++++++++++++++++-
>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
>>  platform/linux-generic/odp_buffer.c                | 120 ++++++++++++
>>  platform/linux-generic/odp_buffer_pool.c           |   7 +
>>  4 files changed, 351 insertions(+), 9 deletions(-)
>>
>> diff --git a/platform/linux-generic/include/api/odp_buffer.h
>> b/platform/linux-generic/include/api/odp_buffer.h
>> index d8577fd..aeb75ed 100644
>> --- a/platform/linux-generic/include/api/odp_buffer.h
>> +++ b/platform/linux-generic/include/api/odp_buffer.h
>> @@ -28,8 +28,34 @@ extern "C" {
>>   */
>>  typedef uint32_t odp_buffer_t;
>>
>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>> +/**
>> +* ODP buffer segment
>> +*/
>> +typedef uint32_t odp_buffer_segment_t;
>>
>> +/**
>> +* ODP buffer type
>> +*/
>> +typedef enum odp_buffer_type {
>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */
>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold any
>> other
>> +                                       buffer type */
>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
>> +                                       no additional metadata */
>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
>> +} odp_buffer_type_e;
>> +
>> +/**
>> +* ODP buffer options
>> +*/
>> +typedef enum odp_buffer_opts {
>> +       ODP_BUFFER_OPTS_NONE,
>> +       ODP_BUFFER_OPTS_UNSEGMENTED
>> +} odp_buffer_opts_e;
>> +
>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
>>
>>  /**
>>   * Buffer start address
>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
>>   */
>>  int odp_buffer_type(odp_buffer_t buf);
>>
>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any other
>> -                                         buffer type */
>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional
>> metadata */
>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
>> -
>> -
>>  /**
>>   * Tests if buffer is valid
>>   *
>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
>>  int odp_buffer_is_valid(odp_buffer_t buf);
>>
>>  /**
>> + * Tests if buffer is segmented
>> + *
>> + * @param[in]  buf     Buffer handle
>> + *
>> + * @return             1 if buffer has more than one segment,
>> + *                     otherwise 0
>> + */
>> +
>> +int odp_buffer_is_segmented(odp_buffer_t buf);
>> +
>> +/**
>> + * Get address and size of user meta data associated with a buffer
>> + *
>> + * @param[in]  buf             Buffer handle
>> + * @param[out] udata_size      Number of bytes of user meta data
>> available
>> + *                             at the returned address
>> + * @return                     Address of the user meta data for this
>> buffer
>> + *                             or NULL if the buffer has no user meta
>> data.
>> + */
>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
>> +
>> +/**
>> + * Get address of user meta data associated with a buffer
>> + *
>> + * @param[in]  buf     Buffer handle
>> + *
>> + * @return             Address of the user meta data for this buffer
>> + *                     or NULL if the buffer has no user meta data.
>> + */
>> +void *odp_buffer_udata_addr(odp_buffer_t buf);
>> +
>> +/**
>> + * Get count of number of segments in a buffer
>> + *
>> + * @param[in]  buf     Buffer handle
>> + *
>> + * @return             Count of the number of segments in buf
>> + */
>> +size_t odp_buffer_segment_count(odp_buffer_t buf);
>> +
>> +/**
>> + * Get the segment identifier for a buffer segment by index
>> + *
>> + * @param[in]  buf     Buffer handle
>> + * @param[in]  ndx     Segment index of segment of interest
>> + *
>> + * @return             Segment identifier or ODP_SEGMENT_INVALID if the
>> + *                     supplied ndx is out of range.
>> + */
>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>> size_t ndx);
>> +
>> +/**
>> + * Get the next segment identifier for a buffer segment
>> + *
>> + * @param[in]  buf     Buffer handle
>> + * @param[in]  seg     Segment identifier of the previous segment
>> + *
>> + * @return             Segment identifier of the next segment,
>> +                       or ODP_SEGMENT_INVALID.
>> + */
>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>> +                                            odp_buffer_segment_t seg);
>> +/**
>> + * Get start address for a specified buffer segment
>> + *
>> + * @param[in]  buf     Buffer handle
>> + * @param[in]  seg     Segment identifier of the buffer to be addressed
>> + * @param[out] seglen  Returned number of bytes in this buffer
>> + *                     segment available at returned address
>> + *
>> + * @return             Segment start address or NULL
>> + */
>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
>> +size_t *seglen);
>> +
>> +/**
>> + *Unmap a buffer segment
>> + *
>> + * @param[in]  seg     Buffer segment handle
>> + */
>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
>> +
>> +/**
>> +* Get start address for a specified buffer offset
>> +*
>> +* @param[in]   buf     Buffer handle
>> +* @param[in]   offset  Byte offset within the buffer to be addressed
>> +* @param[out]  seglen  Returned number of bytes in this buffer
>> +*                      segment available at returned address
>> +*
>> +* @return              Offset start address or NULL
>> +*/
>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>> +size_t *seglen);
>> +
>> +/**
>> + * Unmap a buffer segment by offset
>> + *
>> + * @param[in]  buf     Buffer handle
>> + * @param[in]  offset  Buffer offset
>> + */
>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
>> +
>> +/**
>>   * Print buffer metadata to STDOUT
>>   *
>>   * @param buf      Buffer handle
>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
>>   */
>>  void odp_buffer_print(odp_buffer_t buf);
>>
>> +/**
>> + * Split a buffer into two buffers at a specified split point
>> + *
>> + * @param[in]  buf     Handle of buffer to split
>> + * @param[in]  offset  Byte offset within buf to split buffer
>> + *
>> + * @return             Buffer handle of the created split buffer
>> + */
>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
>> +
>> +/**
>> + * Join two buffers into a single buffer
>> + *
>> + * @param[in]  buf1    Buffer handle of first buffer to join
>> + * @param[in]  buf2    Buffer handle of second buffer to join
>> + *
>> + * @return             Buffer handle of the joined buffer
>> + */
>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);
>> +
>> +/**
>> + * Trim a buffer at a specified trim point
>> + *
>> + * @param[in]  buf     Buffer handle of buffer to trim
>> + * @param[in]  offset  byte offset within buf to trim
>> + *
>> + * @return             Handle of the trimmed buffer or
>> + *                     ODP_BUFFER_INVALID if the operation was not
>> performed
>> + */
>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
>> +/**
>> + * Extend a buffer for a specified number of bytes
>> + *
>> + * @param[in]  buf     Buffer handle of buffer to expand
>> + * @param[in]  ext     size, in bytes, of the extent to add to the
>> + *                     existing buffer.
>> + *
>> + * @return             Handle of the extended buffer or
>> ODP_BUFFER_INVALID
>> + *                     if the operation was not performed
>> + */
>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
>> +
>> +/**
>> + * Clone a buffer, returning an exact copy of it
>> + *
>> + * @param[in]  buf     Buffer handle of buffer to duplicate
>> + *
>> + * @return             Handle of the duplicated buffer or
>> ODP_BUFFER_INVALID
>> + *                     if the operation was not performed
>> + */
>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
>> +
>> +/**
>> + * Copy a buffer, returning an exact copy of it
>> + *
>> + * @param[in]  buf     Buffer handle of buffer to copy
>> + *
>> + * @return             Handle of the copied buffer or ODP_BUFFER_INVALID
>> + *                     if the operation was not performed
>> + */
>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
>> +
>> +
>>
>>  #ifdef __cplusplus
>>  }
>> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
>> b/platform/linux-generic/include/api/odp_buffer_pool.h
>> index fe88898..f85d96c 100644
>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
>> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const char
>> *name,
>>
>>
>>  /**
>> + * Get the next buffer pool from its predecessor
>> + *
>> + * @param[in]  pool            Buffer pool handle
>> + * @param[out] name            Name of the pool
>> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1 chars)
>> + * @param[out] udata_size      Size of user meta data used by this pool.
>> + * @param[out] buf_num         Number of buffers contained in this pool
>> + * @param[out] buf_size        Default size of application data in each
>> buffer
>> + * @param[out] buf_type        Buffer type of the pool
>> + * @param[out] buf_opts        Buffer options for this pool
>> + * @param[out] predef          Predefined (1) or Created (0).
>> + *
>> + * @return                     Buffer pool handle
>> + */
>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
>> +                                      char *name, size_t *udata_size,
>> +                                      size_t *buf_num, size_t *buf_size,
>> +                                      enum odp_buffer_type *buf_type,
>> +                                      enum odp_buffer_opts *buf_opts,
>> +                                      uint32_t *predef);
>> +/**
>>   * Find a buffer pool by name
>>   *
>>   * @param name      Name of the pool
>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t pool);
>>   */
>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
>>
>> +/**
>> +* Allocate a buffer from a buffer pool
>> +*
>> +* @param[in]   pool    Pool handle
>> +* @param[in]   size    Size of object to store in buffer
>> +*
>> +* @return              Buffer handle or ODP_BUFFER_INVALID
>> +*/
>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size);
>>
>>  /**
>>   * Buffer free
>> diff --git a/platform/linux-generic/odp_buffer.c
>> b/platform/linux-generic/odp_buffer.c
>> index e54e0e7..7f4b4f0 100644
>> --- a/platform/linux-generic/odp_buffer.c
>> +++ b/platform/linux-generic/odp_buffer.c
>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
>>  }
>>
>> +int odp_buffer_is_segmented(odp_buffer_t buf)
>> +{
>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>> +
>> +       if (buf_hdr->scatter.num_bufs == 0)
>> +               return 0;
>> +       else
>> +               return 1;
>> +}
>> +
>> +size_t odp_buffer_segment_count(odp_buffer_t buf)
>> +{
>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
>> +}
>>
>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
>>  {
>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
>>         printf("\n%s\n", str);
>>  }
>>
>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
>> +{
>> +       (void)buf;
>> +       (void)udata_size;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +void *odp_buffer_udata_addr(odp_buffer_t buf)
>> +{
>> +       (void)buf;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>> +                                                size_t ndx)
>> +{
>> +       (void)buf;
>> +       (void)ndx;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>> +                                            odp_buffer_segment_t seg)
>> +{
>> +       (void)buf;
>> +       (void)seg;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
>> +                            size_t *seglen)
>> +{
>> +       (void)buf;
>> +       (void)seg;
>> +       (void)seglen;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>> +size_t *seglen)
>> +{
>> +       (void)buf;
>> +       (void)offset;
>> +       (void)seglen;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
>> +{
>> +       (void)buf;
>> +       (void)offset;
>> +       ODP_UNIMPLEMENTED();
>> +       return;
>> +}
>> +
>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t buf_src)
>>  {
>>         (void)buf_dst;
>>         (void)buf_src;
>>  }
>> +
>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
>> +{
>> +       (void)buf;
>> +       (void)offset;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
>> +{
>> +       (void)buf1;
>> +       (void)buf2;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
>> +{
>> +       (void)buf;
>> +       (void)offset;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
>> +{
>> +       (void)buf;
>> +       (void)ext;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
>> +{
>> +       (void)buf;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
>> +{
>> +       (void)buf;
>> +       ODP_UNIMPLEMENTED();
>> +       return 0;
>> +}
>> +
>> diff --git a/platform/linux-generic/odp_buffer_pool.c
>> b/platform/linux-generic/odp_buffer_pool.c
>> index a48d7d6..bff4db5 100644
>> --- a/platform/linux-generic/odp_buffer_pool.c
>> +++ b/platform/linux-generic/odp_buffer_pool.c
>> @@ -471,6 +471,13 @@ odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t
>> pool_hdl)
>>         return handle.u32;
>>  }
>>
>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size)
>> +{
>> +       (void)pool;
>> +       (void) size;
>> +       ODP_ERR("%s function is yet to be implemented", __func__);
>> +       return 0;
>> +}
>>
>>  void odp_buffer_free(odp_buffer_t buf)
>>  {
>> --
>> 2.0.1.472.g6f92e5f
>>
>>
>> _______________________________________________
>> lng-odp mailing list
>> lng-odp@lists.linaro.org
>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>
>>
>>
>>
>> _______________________________________________
>> lng-odp mailing list
>> lng-odp@lists.linaro.org
>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>
>>
>>
>>
>>
>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
>
Ola Liljedahl Oct. 17, 2014, 1:03 p.m. UTC | #7
But segmentation is already needed in a current and known subclass (i.e.
packets). We are not talking about some other feature which we don't know
if it will be needed. So this is not a case of "just in case".

-- Ola#1


On 17 October 2014 14:45, Ola Dahl <dahl.ola@gmail.com> wrote:

> Hi,
>
> I do not think it is wise to put features in the base class "just in case"
> they would be needed in some future (not yet known) subclass.
>
> So if the concept of segmentation is relevant for packets but not for
> timers then I think it should be implemented as a feature of packets.
>
> Best regards,
>
> Ola D
>
> On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer <bill.fischofer@linaro.org
> > wrote:
>
>> I agree that packets are the buffer type that most likely uses segments,
>> however there are many advantages to putting this support in the base class
>> rather than the subclass independent of the number of buffer subclasses
>> that will use this support today.
>>
>>    - It's simpler
>>    - It's more extensible
>>    - It results in cleaner and more efficient application code
>>
>> Allow me to expand on these points.  First simplicity.  Call the work
>> required to support segmentation in the implementation X.  That X is going
>> to be pretty much constant no matter where it is done.  But if the
>> implementation has a choice between doing X at a low level vs. doing it at
>> a high level then it's simpler for the implementation to do it once and be
>> done with it.  If the implementation does it at a higher level then it is
>> either constrained to map that higher-level implementation to be built on a
>> set of lower-level functions that may or may not be appropriate or else it
>> needs to do a completely parallel implementation that is optimal but highly
>> duplicative.
>>
>> Extensibility should be clear.  If at some future point we decide
>> segmentation would be useful for some new buffer type (e.g., IPC) then
>> that's trivial to do if the base class supports it and awkward if it's only
>> part of packets.
>>
>> From an application standpoint, it's cleaner because the packet APIs are
>> just wrappers around their corresponding buffer APIs and can be mapped
>> directly.  Otherwise we have a set of APIs that don't map and are not
>> easily translatable.
>>
>> With regard to efficient segment access, that's what the
>> odp_packet_addr() routine provides--one-step fast-path addressability to
>> the first segment of a packet.  An odp_packet_t is an abstract opaque
>> type.  It is not, and cannot be treated as an address by the application.
>>
>> Does that make sense?
>>
>> Bill
>>
>>
>>
>>
>> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN - FI/Espoo) <
>> petri.savolainen@nsn.com> wrote:
>>
>>>  Hi,
>>>
>>>
>>>
>>> 1. The only segmentation use case is for segmented packet, not for
>>> segmented buffers.
>>>
>>>
>>>
>>> 2. Common case for packets is that everything application needs is in
>>> the first segment. Odp_packet_t could refer always into that “first
>>> segment”, so that application (in the common case) would not need to use
>>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.
>>>
>>>
>>>
>>> When buffer level features are minimized, the need for
>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All packet
>>> manipulation should happen through odp_packet_xxx(pkt, …) calls.
>>>
>>>
>>>
>>>
>>>
>>> -Petri
>>>
>>>
>>>
>>>
>>>
>>> *From:* ext Bill Fischofer [mailto:bill.fischofer@linaro.org]
>>> *Sent:* Friday, October 17, 2014 1:17 PM
>>> *To:* Savolainen, Petri (NSN - FI/Espoo)
>>> *Cc:* ext Jacob, Jerin; lng-odp@lists.linaro.org
>>>
>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>
>>>
>>>
>>> I'm not sure how to understand these two statements:
>>>
>>>
>>>
>>> 1. There's no use case for segmented buffers
>>>
>>> 2. We should optimize for the common case (with segments)
>>>
>>>
>>>
>>> These seem contradictory.
>>>
>>>
>>>
>>> The use case for segmented buffers is that some platforms have a
>>> HW-defined and managed segmented buffer model. If we insist that the
>>> application be able to specify and control packet segment sizes we are
>>> making the decision to exclude such platforms from supporting ODP.  The
>>> optimization suggested is precisely what is being proposed here.  By
>>> default packets are assumed to be contained in implementation-managed
>>> segmented buffers and the first segment will be large enough to contain all
>>> packet headers for non-pathological cases.  The case where the application
>>> wishes to traverse the entire packet in SW is expected to be rare because
>>> in the data plane you simply do not have the cycles to do this at line rate
>>> for all packets.
>>>
>>>
>>>
>>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs, this is
>>> simply syntax to avoid the constant need for explicit conversion functions
>>> since unlike C++, C does not support generic functions.  So you cannot pass
>>> an odp_packet_t to a function that expects an odp_buffer_t argument without
>>> a conversion call.  Do we really want to force applications to constantly
>>> be writing code like:
>>>
>>>
>>>
>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)
>>>
>>>
>>>
>>> rather than
>>>
>>>
>>>
>>> odp_packet_xxx(pkt,...)
>>>
>>>
>>>
>>> Not only is this awkward, it is also inefficient.  By having the
>>> explicit odp_packet_xxx() calls, the implementation is free to optimize
>>> these references in whatever manner is appropriate to that implementation.
>>> For some this may be a simple preprocessor-type expansion while for others
>>> there may be more sophisticated handling.  But the application should
>>> neither know nor care about how the implementation chooses to do this.
>>>
>>>
>>>
>>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN - FI/Espoo) <
>>> petri.savolainen@nsn.com> wrote:
>>>
>>> Hi,
>>>
>>>
>>>
>>> This is also my opinion. There’s no use case for segmented buffers in
>>> v1.0 - so let’s keep it simple and define that buffers (and thus buffer
>>> pools) are always unsegmented. Segmentation comes into play only with
>>> packets (and only with those packets that cannot fit into a single buffer).
>>> For example, if implementation has max buffer size 256, any packets larger
>>> than that are segmented and segments are handled with packet_seg_xxx calls.
>>>
>>>
>>>
>>> Also, I’d propose that we optimize for the common case (with segments) -
>>> so that the odp_packet_t handle would refer always to the head of packet
>>> segment. If the first segment (data/data_len pointed by the odp_packet_t)
>>> carries all data application is interested in (=protocol headers), the
>>> application would not have to use the segment API at all. Most applications
>>> would not see any difference between small/large or segmented/unsegmented
>>> packets as long as all headers fit into the first segment.
>>>
>>>
>>>
>>> -Petri
>>>
>>>
>>>
>>>
>>>
>>> *From:* lng-odp-bounces@lists.linaro.org [mailto:
>>> lng-odp-bounces@lists.linaro.org] *On Behalf Of *ext Jacob, Jerin
>>> *Sent:* Friday, October 17, 2014 9:34 AM
>>> *To:* Bill Fischofer
>>> *Cc:* lng-odp@lists.linaro.org
>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>
>>>
>>>
>>> The need for segment API infrastructure is very clear.The question is,
>>> Do we need separate APIs for
>>>
>>> segment management at odp_buffer_segment* AND odp_packet_segment* levels
>>> ?
>>>
>>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always
>>> unsegmented and if there is a
>>>
>>> API for odp_packet_segement* then there will be not be any consumer for
>>> odp_buffer_segment* API for 1.0​
>>>
>>>
>>>  ------------------------------
>>>
>>> *From:* Bill Fischofer <bill.fischofer@linaro.org>
>>> *Sent:* Thursday, October 16, 2014 9:08 PM
>>> *To:* Jacob, Jerin
>>> *Cc:* Ola Liljedahl; Balasubramanian Manoharan; lng-odp@lists.linaro.org
>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>
>>>
>>>
>>> From the buffer design doc (p. 8-9):
>>>  *Buffer Pool Options*
>>>
>>> The *odp_buffer_opts_e* enum is used to specify additional options
>>> relating to the buffer pool.  Buffer pool options defined are:
>>>
>>>
>>> ·     ODP_BUFFER_OPTS_NONE
>>>
>>> ·     ODP_BUFFER_OPTS_UNSEGMENTED
>>>
>>>
>>> These options are additive so an application can simply specify a
>>> buf_opts by ORing together the options needed.  Note that buffer pool
>>> options are themselves OPTIONAL and a given implementation MAY fail the
>>> buffer pool creation request with an appropriate *errno* if the
>>> requested option is not supported by the underlying ODP implementation,
>>> with the exception that UNSEGMENTED pools MUST be supported for non-packet
>>> types and for packet types as long as the requested size is less than the
>>> implementation-defined native packet segment size.
>>>
>>>
>>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options with no
>>> additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies that the
>>> buffer pool should be unsegmented.
>>>
>>>
>>> So unsegmented buffer pool support is available.  As far as RAW buffers
>>> go, again from the doc (p. 14):
>>>  *ODP_BUFFER_TYPE_RAW*
>>>
>>> This is the “basic” buffer type which simply consists of a single
>>> fixed-sized block of contiguous memory.  Buffers of this type do not
>>> support user meta data and the only built-in meta data supported for this
>>> type of buffer are those that are statically computable, such as pool and
>>> size. This type of buffer is entirely under application control and most of
>>> the buffer APIs defined in this document are not available.  APIs for this
>>> type of buffer are described in this document.
>>>
>>>
>>>
>>> So RAW buffers are always unsegmented.  The intent is that Packets are
>>> by default segmented but can be unsegmented while the other buffer types
>>> are by default unsegmented but (with the exception of RAW buffers) can be
>>> made segmented.  This is because all buffers start out as a single segment
>>> and hence are unsegmented until they are expanded to overflow that single
>>> segment.
>>>
>>>
>>>
>>> Hope that clarifies things.  Again, this is all very straightforward and
>>> only comes into play when actually needed.
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin <
>>> Jerin.Jacob@caviumnetworks.com> wrote:
>>>
>>> If there is no valid use case for supporting segmentation for raw
>>> buffers then lets drop it. At least it will reduce the effort of
>>>
>>> implementing and testing/verification buffer APIs on  different
>>> platforms.
>>>
>>>
>>>   ------------------------------
>>>
>>> *From:* lng-odp-bounces@lists.linaro.org <
>>> lng-odp-bounces@lists.linaro.org> on behalf of Ola Liljedahl <
>>> ola.liljedahl@linaro.org>
>>> *Sent:* Wednesday, October 8, 2014 1:37 PM
>>> *To:* Balasubramanian Manoharan
>>> *Cc:* lng-odp@lists.linaro.org
>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>
>>>
>>>
>>> As I wrote in my comment to the architecture discussion yesterday, I am
>>> against segmentation for buffers. Or at least there must be the possibility
>>> to create a buffer pool with guaranteed non-segmented buffers. Segmented
>>> packets are OK but not all usages for buffers relate to packets. A lot of
>>> internal usages (timeouts, SW messages, internal data structures) will not
>>> be able to handle segmented buffers so *you must be able to force the
>>> creation of buffer pools with non-segmented buffers.*
>>>
>>>
>>>
>>> -- Ola
>>>
>>>
>>>
>>>
>>>
>>> On 8 October 2014 09:50, Balasubramanian Manoharan <
>>> bala.manoharan@linaro.org> wrote:
>>>
>>> This patch contains ODP Buffer Management missing APIs
>>> The intent of this patch is to port the missing APIs from Buffer
>>> Management design document into Linux-generic repo.
>>> The dummy functions will be replaced during linux-generic implementation.
>>>
>>> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>
>>> ---
>>>  platform/linux-generic/include/api/odp_buffer.h    | 203
>>> ++++++++++++++++++++-
>>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
>>>  platform/linux-generic/odp_buffer.c                | 120 ++++++++++++
>>>  platform/linux-generic/odp_buffer_pool.c           |   7 +
>>>  4 files changed, 351 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/platform/linux-generic/include/api/odp_buffer.h
>>> b/platform/linux-generic/include/api/odp_buffer.h
>>> index d8577fd..aeb75ed 100644
>>> --- a/platform/linux-generic/include/api/odp_buffer.h
>>> +++ b/platform/linux-generic/include/api/odp_buffer.h
>>> @@ -28,8 +28,34 @@ extern "C" {
>>>   */
>>>  typedef uint32_t odp_buffer_t;
>>>
>>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>>> +/**
>>> +* ODP buffer segment
>>> +*/
>>> +typedef uint32_t odp_buffer_segment_t;
>>>
>>> +/**
>>> +* ODP buffer type
>>> +*/
>>> +typedef enum odp_buffer_type {
>>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */
>>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold any
>>> other
>>> +                                       buffer type */
>>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
>>> +                                       no additional metadata */
>>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
>>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
>>> +} odp_buffer_type_e;
>>> +
>>> +/**
>>> +* ODP buffer options
>>> +*/
>>> +typedef enum odp_buffer_opts {
>>> +       ODP_BUFFER_OPTS_NONE,
>>> +       ODP_BUFFER_OPTS_UNSEGMENTED
>>> +} odp_buffer_opts_e;
>>> +
>>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
>>>
>>>  /**
>>>   * Buffer start address
>>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
>>>   */
>>>  int odp_buffer_type(odp_buffer_t buf);
>>>
>>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
>>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any other
>>> -                                         buffer type */
>>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional
>>> metadata */
>>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
>>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
>>> -
>>> -
>>>  /**
>>>   * Tests if buffer is valid
>>>   *
>>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
>>>  int odp_buffer_is_valid(odp_buffer_t buf);
>>>
>>>  /**
>>> + * Tests if buffer is segmented
>>> + *
>>> + * @param[in]  buf     Buffer handle
>>> + *
>>> + * @return             1 if buffer has more than one segment,
>>> + *                     otherwise 0
>>> + */
>>> +
>>> +int odp_buffer_is_segmented(odp_buffer_t buf);
>>> +
>>> +/**
>>> + * Get address and size of user meta data associated with a buffer
>>> + *
>>> + * @param[in]  buf             Buffer handle
>>> + * @param[out] udata_size      Number of bytes of user meta data
>>> available
>>> + *                             at the returned address
>>> + * @return                     Address of the user meta data for this
>>> buffer
>>> + *                             or NULL if the buffer has no user meta
>>> data.
>>> + */
>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
>>> +
>>> +/**
>>> + * Get address of user meta data associated with a buffer
>>> + *
>>> + * @param[in]  buf     Buffer handle
>>> + *
>>> + * @return             Address of the user meta data for this buffer
>>> + *                     or NULL if the buffer has no user meta data.
>>> + */
>>> +void *odp_buffer_udata_addr(odp_buffer_t buf);
>>> +
>>> +/**
>>> + * Get count of number of segments in a buffer
>>> + *
>>> + * @param[in]  buf     Buffer handle
>>> + *
>>> + * @return             Count of the number of segments in buf
>>> + */
>>> +size_t odp_buffer_segment_count(odp_buffer_t buf);
>>> +
>>> +/**
>>> + * Get the segment identifier for a buffer segment by index
>>> + *
>>> + * @param[in]  buf     Buffer handle
>>> + * @param[in]  ndx     Segment index of segment of interest
>>> + *
>>> + * @return             Segment identifier or ODP_SEGMENT_INVALID if the
>>> + *                     supplied ndx is out of range.
>>> + */
>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>>> size_t ndx);
>>> +
>>> +/**
>>> + * Get the next segment identifier for a buffer segment
>>> + *
>>> + * @param[in]  buf     Buffer handle
>>> + * @param[in]  seg     Segment identifier of the previous segment
>>> + *
>>> + * @return             Segment identifier of the next segment,
>>> +                       or ODP_SEGMENT_INVALID.
>>> + */
>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>>> +                                            odp_buffer_segment_t seg);
>>> +/**
>>> + * Get start address for a specified buffer segment
>>> + *
>>> + * @param[in]  buf     Buffer handle
>>> + * @param[in]  seg     Segment identifier of the buffer to be addressed
>>> + * @param[out] seglen  Returned number of bytes in this buffer
>>> + *                     segment available at returned address
>>> + *
>>> + * @return             Segment start address or NULL
>>> + */
>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
>>> +size_t *seglen);
>>> +
>>> +/**
>>> + *Unmap a buffer segment
>>> + *
>>> + * @param[in]  seg     Buffer segment handle
>>> + */
>>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
>>> +
>>> +/**
>>> +* Get start address for a specified buffer offset
>>> +*
>>> +* @param[in]   buf     Buffer handle
>>> +* @param[in]   offset  Byte offset within the buffer to be addressed
>>> +* @param[out]  seglen  Returned number of bytes in this buffer
>>> +*                      segment available at returned address
>>> +*
>>> +* @return              Offset start address or NULL
>>> +*/
>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>>> +size_t *seglen);
>>> +
>>> +/**
>>> + * Unmap a buffer segment by offset
>>> + *
>>> + * @param[in]  buf     Buffer handle
>>> + * @param[in]  offset  Buffer offset
>>> + */
>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
>>> +
>>> +/**
>>>   * Print buffer metadata to STDOUT
>>>   *
>>>   * @param buf      Buffer handle
>>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
>>>   */
>>>  void odp_buffer_print(odp_buffer_t buf);
>>>
>>> +/**
>>> + * Split a buffer into two buffers at a specified split point
>>> + *
>>> + * @param[in]  buf     Handle of buffer to split
>>> + * @param[in]  offset  Byte offset within buf to split buffer
>>> + *
>>> + * @return             Buffer handle of the created split buffer
>>> + */
>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
>>> +
>>> +/**
>>> + * Join two buffers into a single buffer
>>> + *
>>> + * @param[in]  buf1    Buffer handle of first buffer to join
>>> + * @param[in]  buf2    Buffer handle of second buffer to join
>>> + *
>>> + * @return             Buffer handle of the joined buffer
>>> + */
>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);
>>> +
>>> +/**
>>> + * Trim a buffer at a specified trim point
>>> + *
>>> + * @param[in]  buf     Buffer handle of buffer to trim
>>> + * @param[in]  offset  byte offset within buf to trim
>>> + *
>>> + * @return             Handle of the trimmed buffer or
>>> + *                     ODP_BUFFER_INVALID if the operation was not
>>> performed
>>> + */
>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
>>> +/**
>>> + * Extend a buffer for a specified number of bytes
>>> + *
>>> + * @param[in]  buf     Buffer handle of buffer to expand
>>> + * @param[in]  ext     size, in bytes, of the extent to add to the
>>> + *                     existing buffer.
>>> + *
>>> + * @return             Handle of the extended buffer or
>>> ODP_BUFFER_INVALID
>>> + *                     if the operation was not performed
>>> + */
>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
>>> +
>>> +/**
>>> + * Clone a buffer, returning an exact copy of it
>>> + *
>>> + * @param[in]  buf     Buffer handle of buffer to duplicate
>>> + *
>>> + * @return             Handle of the duplicated buffer or
>>> ODP_BUFFER_INVALID
>>> + *                     if the operation was not performed
>>> + */
>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
>>> +
>>> +/**
>>> + * Copy a buffer, returning an exact copy of it
>>> + *
>>> + * @param[in]  buf     Buffer handle of buffer to copy
>>> + *
>>> + * @return             Handle of the copied buffer or ODP_BUFFER_INVALID
>>> + *                     if the operation was not performed
>>> + */
>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
>>> +
>>> +
>>>
>>>  #ifdef __cplusplus
>>>  }
>>> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
>>> b/platform/linux-generic/include/api/odp_buffer_pool.h
>>> index fe88898..f85d96c 100644
>>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
>>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
>>> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const char
>>> *name,
>>>
>>>
>>>  /**
>>> + * Get the next buffer pool from its predecessor
>>> + *
>>> + * @param[in]  pool            Buffer pool handle
>>> + * @param[out] name            Name of the pool
>>> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1 chars)
>>> + * @param[out] udata_size      Size of user meta data used by this pool.
>>> + * @param[out] buf_num         Number of buffers contained in this pool
>>> + * @param[out] buf_size        Default size of application data in each
>>> buffer
>>> + * @param[out] buf_type        Buffer type of the pool
>>> + * @param[out] buf_opts        Buffer options for this pool
>>> + * @param[out] predef          Predefined (1) or Created (0).
>>> + *
>>> + * @return                     Buffer pool handle
>>> + */
>>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
>>> +                                      char *name, size_t *udata_size,
>>> +                                      size_t *buf_num, size_t *buf_size,
>>> +                                      enum odp_buffer_type *buf_type,
>>> +                                      enum odp_buffer_opts *buf_opts,
>>> +                                      uint32_t *predef);
>>> +/**
>>>   * Find a buffer pool by name
>>>   *
>>>   * @param name      Name of the pool
>>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t pool);
>>>   */
>>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
>>>
>>> +/**
>>> +* Allocate a buffer from a buffer pool
>>> +*
>>> +* @param[in]   pool    Pool handle
>>> +* @param[in]   size    Size of object to store in buffer
>>> +*
>>> +* @return              Buffer handle or ODP_BUFFER_INVALID
>>> +*/
>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size);
>>>
>>>  /**
>>>   * Buffer free
>>> diff --git a/platform/linux-generic/odp_buffer.c
>>> b/platform/linux-generic/odp_buffer.c
>>> index e54e0e7..7f4b4f0 100644
>>> --- a/platform/linux-generic/odp_buffer.c
>>> +++ b/platform/linux-generic/odp_buffer.c
>>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
>>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
>>>  }
>>>
>>> +int odp_buffer_is_segmented(odp_buffer_t buf)
>>> +{
>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>>> +
>>> +       if (buf_hdr->scatter.num_bufs == 0)
>>> +               return 0;
>>> +       else
>>> +               return 1;
>>> +}
>>> +
>>> +size_t odp_buffer_segment_count(odp_buffer_t buf)
>>> +{
>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
>>> +}
>>>
>>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
>>>  {
>>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
>>>         printf("\n%s\n", str);
>>>  }
>>>
>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
>>> +{
>>> +       (void)buf;
>>> +       (void)udata_size;
>>> +       ODP_UNIMPLEMENTED();
>>> +       return 0;
>>> +}
>>> +
>>> +void *odp_buffer_udata_addr(odp_buffer_t buf)
>>> +{
>>> +       (void)buf;
>>> +       ODP_UNIMPLEMENTED();
>>> +       return 0;
>>> +}
>>> +
>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>>> +                                                size_t ndx)
>>> +{
>>> +       (void)buf;
>>> +       (void)ndx;
>>> +       ODP_UNIMPLEMENTED();
>>> +       return 0;
>>> +}
>>> +
>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>>> +                                            odp_buffer_segment_t seg)
>>> +{
>>> +       (void)buf;
>>> +       (void)seg;
>>> +       ODP_UNIMPLEMENTED();
>>> +       return 0;
>>> +}
>>> +
>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
>>> +                            size_t *seglen)
>>> +{
>>> +       (void)buf;
>>> +       (void)seg;
>>> +       (void)seglen;
>>> +       ODP_UNIMPLEMENTED();
>>> +       return 0;
>>> +}
>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>>> +size_t *seglen)
>>> +{
>>> +       (void)buf;
>>> +       (void)offset;
>>> +       (void)seglen;
>>> +       ODP_UNIMPLEMENTED();
>>> +       return 0;
>>> +}
>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
>>> +{
>>> +       (void)buf;
>>> +       (void)offset;
>>> +       ODP_UNIMPLEMENTED();
>>> +       return;
>>> +}
>>> +
>>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t buf_src)
>>>  {
>>>         (void)buf_dst;
>>>         (void)buf_src;
>>>  }
>>> +
>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
>>> +{
>>> +       (void)buf;
>>> +       (void)offset;
>>> +       ODP_UNIMPLEMENTED();
>>> +       return 0;
>>> +}
>>> +
>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
>>> +{
>>> +       (void)buf1;
>>> +       (void)buf2;
>>> +       ODP_UNIMPLEMENTED();
>>> +       return 0;
>>> +}
>>> +
>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
>>> +{
>>> +       (void)buf;
>>> +       (void)offset;
>>> +       ODP_UNIMPLEMENTED();
>>> +       return 0;
>>> +}
>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
>>> +{
>>> +       (void)buf;
>>> +       (void)ext;
>>> +       ODP_UNIMPLEMENTED();
>>> +       return 0;
>>> +}
>>> +
>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
>>> +{
>>> +       (void)buf;
>>> +       ODP_UNIMPLEMENTED();
>>> +       return 0;
>>> +}
>>> +
>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
>>> +{
>>> +       (void)buf;
>>> +       ODP_UNIMPLEMENTED();
>>> +       return 0;
>>> +}
>>> +
>>> diff --git a/platform/linux-generic/odp_buffer_pool.c
>>> b/platform/linux-generic/odp_buffer_pool.c
>>> index a48d7d6..bff4db5 100644
>>> --- a/platform/linux-generic/odp_buffer_pool.c
>>> +++ b/platform/linux-generic/odp_buffer_pool.c
>>> @@ -471,6 +471,13 @@ odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t
>>> pool_hdl)
>>>         return handle.u32;
>>>  }
>>>
>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size)
>>> +{
>>> +       (void)pool;
>>> +       (void) size;
>>> +       ODP_ERR("%s function is yet to be implemented", __func__);
>>> +       return 0;
>>> +}
>>>
>>>  void odp_buffer_free(odp_buffer_t buf)
>>>  {
>>> --
>>> 2.0.1.472.g6f92e5f
>>>
>>>
>>> _______________________________________________
>>> lng-odp mailing list
>>> lng-odp@lists.linaro.org
>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>
>>>
>>>
>>>
>>> _______________________________________________
>>> lng-odp mailing list
>>> lng-odp@lists.linaro.org
>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>
>>>
>>>
>>>
>>>
>>
>>
>> _______________________________________________
>> lng-odp mailing list
>> lng-odp@lists.linaro.org
>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>
>>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
>
Ola Liljedahl Oct. 17, 2014, 1:05 p.m. UTC | #8
Personally I don't see any need for segmentation support in buffers. I am
just trying to shoot down what I think is flawed reasoning.

-- Ola#1

On 17 October 2014 15:03, Ola Liljedahl <ola.liljedahl@linaro.org> wrote:

> But segmentation is already needed in a current and known subclass (i.e.
> packets). We are not talking about some other feature which we don't know
> if it will be needed. So this is not a case of "just in case".
>
> -- Ola#1
>
>
> On 17 October 2014 14:45, Ola Dahl <dahl.ola@gmail.com> wrote:
>
>> Hi,
>>
>> I do not think it is wise to put features in the base class "just in
>> case" they would be needed in some future (not yet known) subclass.
>>
>> So if the concept of segmentation is relevant for packets but not for
>> timers then I think it should be implemented as a feature of packets.
>>
>> Best regards,
>>
>> Ola D
>>
>> On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer <
>> bill.fischofer@linaro.org> wrote:
>>
>>> I agree that packets are the buffer type that most likely uses segments,
>>> however there are many advantages to putting this support in the base class
>>> rather than the subclass independent of the number of buffer subclasses
>>> that will use this support today.
>>>
>>>    - It's simpler
>>>    - It's more extensible
>>>    - It results in cleaner and more efficient application code
>>>
>>> Allow me to expand on these points.  First simplicity.  Call the work
>>> required to support segmentation in the implementation X.  That X is going
>>> to be pretty much constant no matter where it is done.  But if the
>>> implementation has a choice between doing X at a low level vs. doing it at
>>> a high level then it's simpler for the implementation to do it once and be
>>> done with it.  If the implementation does it at a higher level then it is
>>> either constrained to map that higher-level implementation to be built on a
>>> set of lower-level functions that may or may not be appropriate or else it
>>> needs to do a completely parallel implementation that is optimal but highly
>>> duplicative.
>>>
>>> Extensibility should be clear.  If at some future point we decide
>>> segmentation would be useful for some new buffer type (e.g., IPC) then
>>> that's trivial to do if the base class supports it and awkward if it's only
>>> part of packets.
>>>
>>> From an application standpoint, it's cleaner because the packet APIs are
>>> just wrappers around their corresponding buffer APIs and can be mapped
>>> directly.  Otherwise we have a set of APIs that don't map and are not
>>> easily translatable.
>>>
>>> With regard to efficient segment access, that's what the
>>> odp_packet_addr() routine provides--one-step fast-path addressability to
>>> the first segment of a packet.  An odp_packet_t is an abstract opaque
>>> type.  It is not, and cannot be treated as an address by the application.
>>>
>>> Does that make sense?
>>>
>>> Bill
>>>
>>>
>>>
>>>
>>> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN - FI/Espoo) <
>>> petri.savolainen@nsn.com> wrote:
>>>
>>>>  Hi,
>>>>
>>>>
>>>>
>>>> 1. The only segmentation use case is for segmented packet, not for
>>>> segmented buffers.
>>>>
>>>>
>>>>
>>>> 2. Common case for packets is that everything application needs is in
>>>> the first segment. Odp_packet_t could refer always into that “first
>>>> segment”, so that application (in the common case) would not need to use
>>>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.
>>>>
>>>>
>>>>
>>>> When buffer level features are minimized, the need for
>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All packet
>>>> manipulation should happen through odp_packet_xxx(pkt, …) calls.
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> -Petri
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> *From:* ext Bill Fischofer [mailto:bill.fischofer@linaro.org]
>>>> *Sent:* Friday, October 17, 2014 1:17 PM
>>>> *To:* Savolainen, Petri (NSN - FI/Espoo)
>>>> *Cc:* ext Jacob, Jerin; lng-odp@lists.linaro.org
>>>>
>>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>
>>>>
>>>>
>>>> I'm not sure how to understand these two statements:
>>>>
>>>>
>>>>
>>>> 1. There's no use case for segmented buffers
>>>>
>>>> 2. We should optimize for the common case (with segments)
>>>>
>>>>
>>>>
>>>> These seem contradictory.
>>>>
>>>>
>>>>
>>>> The use case for segmented buffers is that some platforms have a
>>>> HW-defined and managed segmented buffer model. If we insist that the
>>>> application be able to specify and control packet segment sizes we are
>>>> making the decision to exclude such platforms from supporting ODP.  The
>>>> optimization suggested is precisely what is being proposed here.  By
>>>> default packets are assumed to be contained in implementation-managed
>>>> segmented buffers and the first segment will be large enough to contain all
>>>> packet headers for non-pathological cases.  The case where the application
>>>> wishes to traverse the entire packet in SW is expected to be rare because
>>>> in the data plane you simply do not have the cycles to do this at line rate
>>>> for all packets.
>>>>
>>>>
>>>>
>>>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs, this is
>>>> simply syntax to avoid the constant need for explicit conversion functions
>>>> since unlike C++, C does not support generic functions.  So you cannot pass
>>>> an odp_packet_t to a function that expects an odp_buffer_t argument without
>>>> a conversion call.  Do we really want to force applications to constantly
>>>> be writing code like:
>>>>
>>>>
>>>>
>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)
>>>>
>>>>
>>>>
>>>> rather than
>>>>
>>>>
>>>>
>>>> odp_packet_xxx(pkt,...)
>>>>
>>>>
>>>>
>>>> Not only is this awkward, it is also inefficient.  By having the
>>>> explicit odp_packet_xxx() calls, the implementation is free to optimize
>>>> these references in whatever manner is appropriate to that implementation.
>>>> For some this may be a simple preprocessor-type expansion while for others
>>>> there may be more sophisticated handling.  But the application should
>>>> neither know nor care about how the implementation chooses to do this.
>>>>
>>>>
>>>>
>>>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN - FI/Espoo) <
>>>> petri.savolainen@nsn.com> wrote:
>>>>
>>>> Hi,
>>>>
>>>>
>>>>
>>>> This is also my opinion. There’s no use case for segmented buffers in
>>>> v1.0 - so let’s keep it simple and define that buffers (and thus buffer
>>>> pools) are always unsegmented. Segmentation comes into play only with
>>>> packets (and only with those packets that cannot fit into a single buffer).
>>>> For example, if implementation has max buffer size 256, any packets larger
>>>> than that are segmented and segments are handled with packet_seg_xxx calls.
>>>>
>>>>
>>>>
>>>> Also, I’d propose that we optimize for the common case (with segments)
>>>> - so that the odp_packet_t handle would refer always to the head of packet
>>>> segment. If the first segment (data/data_len pointed by the odp_packet_t)
>>>> carries all data application is interested in (=protocol headers), the
>>>> application would not have to use the segment API at all. Most applications
>>>> would not see any difference between small/large or segmented/unsegmented
>>>> packets as long as all headers fit into the first segment.
>>>>
>>>>
>>>>
>>>> -Petri
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> *From:* lng-odp-bounces@lists.linaro.org [mailto:
>>>> lng-odp-bounces@lists.linaro.org] *On Behalf Of *ext Jacob, Jerin
>>>> *Sent:* Friday, October 17, 2014 9:34 AM
>>>> *To:* Bill Fischofer
>>>> *Cc:* lng-odp@lists.linaro.org
>>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>
>>>>
>>>>
>>>> The need for segment API infrastructure is very clear.The question is,
>>>> Do we need separate APIs for
>>>>
>>>> segment management at odp_buffer_segment* AND odp_packet_segment*
>>>> levels ?
>>>>
>>>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always
>>>> unsegmented and if there is a
>>>>
>>>> API for odp_packet_segement* then there will be not be any consumer for
>>>> odp_buffer_segment* API for 1.0​
>>>>
>>>>
>>>>  ------------------------------
>>>>
>>>> *From:* Bill Fischofer <bill.fischofer@linaro.org>
>>>> *Sent:* Thursday, October 16, 2014 9:08 PM
>>>> *To:* Jacob, Jerin
>>>> *Cc:* Ola Liljedahl; Balasubramanian Manoharan;
>>>> lng-odp@lists.linaro.org
>>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>
>>>>
>>>>
>>>> From the buffer design doc (p. 8-9):
>>>>  *Buffer Pool Options*
>>>>
>>>> The *odp_buffer_opts_e* enum is used to specify additional options
>>>> relating to the buffer pool.  Buffer pool options defined are:
>>>>
>>>>
>>>> ·     ODP_BUFFER_OPTS_NONE
>>>>
>>>> ·     ODP_BUFFER_OPTS_UNSEGMENTED
>>>>
>>>>
>>>> These options are additive so an application can simply specify a
>>>> buf_opts by ORing together the options needed.  Note that buffer pool
>>>> options are themselves OPTIONAL and a given implementation MAY fail the
>>>> buffer pool creation request with an appropriate *errno* if the
>>>> requested option is not supported by the underlying ODP implementation,
>>>> with the exception that UNSEGMENTED pools MUST be supported for non-packet
>>>> types and for packet types as long as the requested size is less than the
>>>> implementation-defined native packet segment size.
>>>>
>>>>
>>>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options with
>>>> no additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies that
>>>> the buffer pool should be unsegmented.
>>>>
>>>>
>>>> So unsegmented buffer pool support is available.  As far as RAW buffers
>>>> go, again from the doc (p. 14):
>>>>  *ODP_BUFFER_TYPE_RAW*
>>>>
>>>> This is the “basic” buffer type which simply consists of a single
>>>> fixed-sized block of contiguous memory.  Buffers of this type do not
>>>> support user meta data and the only built-in meta data supported for this
>>>> type of buffer are those that are statically computable, such as pool and
>>>> size. This type of buffer is entirely under application control and most of
>>>> the buffer APIs defined in this document are not available.  APIs for this
>>>> type of buffer are described in this document.
>>>>
>>>>
>>>>
>>>> So RAW buffers are always unsegmented.  The intent is that Packets are
>>>> by default segmented but can be unsegmented while the other buffer types
>>>> are by default unsegmented but (with the exception of RAW buffers) can be
>>>> made segmented.  This is because all buffers start out as a single segment
>>>> and hence are unsegmented until they are expanded to overflow that single
>>>> segment.
>>>>
>>>>
>>>>
>>>> Hope that clarifies things.  Again, this is all very straightforward
>>>> and only comes into play when actually needed.
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin <
>>>> Jerin.Jacob@caviumnetworks.com> wrote:
>>>>
>>>> If there is no valid use case for supporting segmentation for raw
>>>> buffers then lets drop it. At least it will reduce the effort of
>>>>
>>>> implementing and testing/verification buffer APIs on  different
>>>> platforms.
>>>>
>>>>
>>>>   ------------------------------
>>>>
>>>> *From:* lng-odp-bounces@lists.linaro.org <
>>>> lng-odp-bounces@lists.linaro.org> on behalf of Ola Liljedahl <
>>>> ola.liljedahl@linaro.org>
>>>> *Sent:* Wednesday, October 8, 2014 1:37 PM
>>>> *To:* Balasubramanian Manoharan
>>>> *Cc:* lng-odp@lists.linaro.org
>>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>
>>>>
>>>>
>>>> As I wrote in my comment to the architecture discussion yesterday, I am
>>>> against segmentation for buffers. Or at least there must be the possibility
>>>> to create a buffer pool with guaranteed non-segmented buffers. Segmented
>>>> packets are OK but not all usages for buffers relate to packets. A lot of
>>>> internal usages (timeouts, SW messages, internal data structures) will not
>>>> be able to handle segmented buffers so *you must be able to force the
>>>> creation of buffer pools with non-segmented buffers.*
>>>>
>>>>
>>>>
>>>> -- Ola
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> On 8 October 2014 09:50, Balasubramanian Manoharan <
>>>> bala.manoharan@linaro.org> wrote:
>>>>
>>>> This patch contains ODP Buffer Management missing APIs
>>>> The intent of this patch is to port the missing APIs from Buffer
>>>> Management design document into Linux-generic repo.
>>>> The dummy functions will be replaced during linux-generic
>>>> implementation.
>>>>
>>>> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>
>>>> ---
>>>>  platform/linux-generic/include/api/odp_buffer.h    | 203
>>>> ++++++++++++++++++++-
>>>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
>>>>  platform/linux-generic/odp_buffer.c                | 120 ++++++++++++
>>>>  platform/linux-generic/odp_buffer_pool.c           |   7 +
>>>>  4 files changed, 351 insertions(+), 9 deletions(-)
>>>>
>>>> diff --git a/platform/linux-generic/include/api/odp_buffer.h
>>>> b/platform/linux-generic/include/api/odp_buffer.h
>>>> index d8577fd..aeb75ed 100644
>>>> --- a/platform/linux-generic/include/api/odp_buffer.h
>>>> +++ b/platform/linux-generic/include/api/odp_buffer.h
>>>> @@ -28,8 +28,34 @@ extern "C" {
>>>>   */
>>>>  typedef uint32_t odp_buffer_t;
>>>>
>>>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>>>> +/**
>>>> +* ODP buffer segment
>>>> +*/
>>>> +typedef uint32_t odp_buffer_segment_t;
>>>>
>>>> +/**
>>>> +* ODP buffer type
>>>> +*/
>>>> +typedef enum odp_buffer_type {
>>>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */
>>>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold any
>>>> other
>>>> +                                       buffer type */
>>>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
>>>> +                                       no additional metadata */
>>>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
>>>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
>>>> +} odp_buffer_type_e;
>>>> +
>>>> +/**
>>>> +* ODP buffer options
>>>> +*/
>>>> +typedef enum odp_buffer_opts {
>>>> +       ODP_BUFFER_OPTS_NONE,
>>>> +       ODP_BUFFER_OPTS_UNSEGMENTED
>>>> +} odp_buffer_opts_e;
>>>> +
>>>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>>>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
>>>>
>>>>  /**
>>>>   * Buffer start address
>>>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
>>>>   */
>>>>  int odp_buffer_type(odp_buffer_t buf);
>>>>
>>>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
>>>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any
>>>> other
>>>> -                                         buffer type */
>>>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional
>>>> metadata */
>>>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
>>>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
>>>> -
>>>> -
>>>>  /**
>>>>   * Tests if buffer is valid
>>>>   *
>>>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
>>>>  int odp_buffer_is_valid(odp_buffer_t buf);
>>>>
>>>>  /**
>>>> + * Tests if buffer is segmented
>>>> + *
>>>> + * @param[in]  buf     Buffer handle
>>>> + *
>>>> + * @return             1 if buffer has more than one segment,
>>>> + *                     otherwise 0
>>>> + */
>>>> +
>>>> +int odp_buffer_is_segmented(odp_buffer_t buf);
>>>> +
>>>> +/**
>>>> + * Get address and size of user meta data associated with a buffer
>>>> + *
>>>> + * @param[in]  buf             Buffer handle
>>>> + * @param[out] udata_size      Number of bytes of user meta data
>>>> available
>>>> + *                             at the returned address
>>>> + * @return                     Address of the user meta data for this
>>>> buffer
>>>> + *                             or NULL if the buffer has no user meta
>>>> data.
>>>> + */
>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
>>>> +
>>>> +/**
>>>> + * Get address of user meta data associated with a buffer
>>>> + *
>>>> + * @param[in]  buf     Buffer handle
>>>> + *
>>>> + * @return             Address of the user meta data for this buffer
>>>> + *                     or NULL if the buffer has no user meta data.
>>>> + */
>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf);
>>>> +
>>>> +/**
>>>> + * Get count of number of segments in a buffer
>>>> + *
>>>> + * @param[in]  buf     Buffer handle
>>>> + *
>>>> + * @return             Count of the number of segments in buf
>>>> + */
>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf);
>>>> +
>>>> +/**
>>>> + * Get the segment identifier for a buffer segment by index
>>>> + *
>>>> + * @param[in]  buf     Buffer handle
>>>> + * @param[in]  ndx     Segment index of segment of interest
>>>> + *
>>>> + * @return             Segment identifier or ODP_SEGMENT_INVALID if the
>>>> + *                     supplied ndx is out of range.
>>>> + */
>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>>>> size_t ndx);
>>>> +
>>>> +/**
>>>> + * Get the next segment identifier for a buffer segment
>>>> + *
>>>> + * @param[in]  buf     Buffer handle
>>>> + * @param[in]  seg     Segment identifier of the previous segment
>>>> + *
>>>> + * @return             Segment identifier of the next segment,
>>>> +                       or ODP_SEGMENT_INVALID.
>>>> + */
>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>>>> +                                            odp_buffer_segment_t seg);
>>>> +/**
>>>> + * Get start address for a specified buffer segment
>>>> + *
>>>> + * @param[in]  buf     Buffer handle
>>>> + * @param[in]  seg     Segment identifier of the buffer to be addressed
>>>> + * @param[out] seglen  Returned number of bytes in this buffer
>>>> + *                     segment available at returned address
>>>> + *
>>>> + * @return             Segment start address or NULL
>>>> + */
>>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t
>>>> seg,
>>>> +size_t *seglen);
>>>> +
>>>> +/**
>>>> + *Unmap a buffer segment
>>>> + *
>>>> + * @param[in]  seg     Buffer segment handle
>>>> + */
>>>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
>>>> +
>>>> +/**
>>>> +* Get start address for a specified buffer offset
>>>> +*
>>>> +* @param[in]   buf     Buffer handle
>>>> +* @param[in]   offset  Byte offset within the buffer to be addressed
>>>> +* @param[out]  seglen  Returned number of bytes in this buffer
>>>> +*                      segment available at returned address
>>>> +*
>>>> +* @return              Offset start address or NULL
>>>> +*/
>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>>>> +size_t *seglen);
>>>> +
>>>> +/**
>>>> + * Unmap a buffer segment by offset
>>>> + *
>>>> + * @param[in]  buf     Buffer handle
>>>> + * @param[in]  offset  Buffer offset
>>>> + */
>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
>>>> +
>>>> +/**
>>>>   * Print buffer metadata to STDOUT
>>>>   *
>>>>   * @param buf      Buffer handle
>>>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
>>>>   */
>>>>  void odp_buffer_print(odp_buffer_t buf);
>>>>
>>>> +/**
>>>> + * Split a buffer into two buffers at a specified split point
>>>> + *
>>>> + * @param[in]  buf     Handle of buffer to split
>>>> + * @param[in]  offset  Byte offset within buf to split buffer
>>>> + *
>>>> + * @return             Buffer handle of the created split buffer
>>>> + */
>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
>>>> +
>>>> +/**
>>>> + * Join two buffers into a single buffer
>>>> + *
>>>> + * @param[in]  buf1    Buffer handle of first buffer to join
>>>> + * @param[in]  buf2    Buffer handle of second buffer to join
>>>> + *
>>>> + * @return             Buffer handle of the joined buffer
>>>> + */
>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);
>>>> +
>>>> +/**
>>>> + * Trim a buffer at a specified trim point
>>>> + *
>>>> + * @param[in]  buf     Buffer handle of buffer to trim
>>>> + * @param[in]  offset  byte offset within buf to trim
>>>> + *
>>>> + * @return             Handle of the trimmed buffer or
>>>> + *                     ODP_BUFFER_INVALID if the operation was not
>>>> performed
>>>> + */
>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
>>>> +/**
>>>> + * Extend a buffer for a specified number of bytes
>>>> + *
>>>> + * @param[in]  buf     Buffer handle of buffer to expand
>>>> + * @param[in]  ext     size, in bytes, of the extent to add to the
>>>> + *                     existing buffer.
>>>> + *
>>>> + * @return             Handle of the extended buffer or
>>>> ODP_BUFFER_INVALID
>>>> + *                     if the operation was not performed
>>>> + */
>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
>>>> +
>>>> +/**
>>>> + * Clone a buffer, returning an exact copy of it
>>>> + *
>>>> + * @param[in]  buf     Buffer handle of buffer to duplicate
>>>> + *
>>>> + * @return             Handle of the duplicated buffer or
>>>> ODP_BUFFER_INVALID
>>>> + *                     if the operation was not performed
>>>> + */
>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
>>>> +
>>>> +/**
>>>> + * Copy a buffer, returning an exact copy of it
>>>> + *
>>>> + * @param[in]  buf     Buffer handle of buffer to copy
>>>> + *
>>>> + * @return             Handle of the copied buffer or
>>>> ODP_BUFFER_INVALID
>>>> + *                     if the operation was not performed
>>>> + */
>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
>>>> +
>>>> +
>>>>
>>>>  #ifdef __cplusplus
>>>>  }
>>>> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
>>>> b/platform/linux-generic/include/api/odp_buffer_pool.h
>>>> index fe88898..f85d96c 100644
>>>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
>>>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
>>>> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const char
>>>> *name,
>>>>
>>>>
>>>>  /**
>>>> + * Get the next buffer pool from its predecessor
>>>> + *
>>>> + * @param[in]  pool            Buffer pool handle
>>>> + * @param[out] name            Name of the pool
>>>> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1 chars)
>>>> + * @param[out] udata_size      Size of user meta data used by this
>>>> pool.
>>>> + * @param[out] buf_num         Number of buffers contained in this pool
>>>> + * @param[out] buf_size        Default size of application data in
>>>> each buffer
>>>> + * @param[out] buf_type        Buffer type of the pool
>>>> + * @param[out] buf_opts        Buffer options for this pool
>>>> + * @param[out] predef          Predefined (1) or Created (0).
>>>> + *
>>>> + * @return                     Buffer pool handle
>>>> + */
>>>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
>>>> +                                      char *name, size_t *udata_size,
>>>> +                                      size_t *buf_num, size_t
>>>> *buf_size,
>>>> +                                      enum odp_buffer_type *buf_type,
>>>> +                                      enum odp_buffer_opts *buf_opts,
>>>> +                                      uint32_t *predef);
>>>> +/**
>>>>   * Find a buffer pool by name
>>>>   *
>>>>   * @param name      Name of the pool
>>>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t pool);
>>>>   */
>>>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
>>>>
>>>> +/**
>>>> +* Allocate a buffer from a buffer pool
>>>> +*
>>>> +* @param[in]   pool    Pool handle
>>>> +* @param[in]   size    Size of object to store in buffer
>>>> +*
>>>> +* @return              Buffer handle or ODP_BUFFER_INVALID
>>>> +*/
>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t
>>>> size);
>>>>
>>>>  /**
>>>>   * Buffer free
>>>> diff --git a/platform/linux-generic/odp_buffer.c
>>>> b/platform/linux-generic/odp_buffer.c
>>>> index e54e0e7..7f4b4f0 100644
>>>> --- a/platform/linux-generic/odp_buffer.c
>>>> +++ b/platform/linux-generic/odp_buffer.c
>>>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
>>>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
>>>>  }
>>>>
>>>> +int odp_buffer_is_segmented(odp_buffer_t buf)
>>>> +{
>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>>>> +
>>>> +       if (buf_hdr->scatter.num_bufs == 0)
>>>> +               return 0;
>>>> +       else
>>>> +               return 1;
>>>> +}
>>>> +
>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf)
>>>> +{
>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>>>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
>>>> +}
>>>>
>>>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
>>>>  {
>>>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
>>>>         printf("\n%s\n", str);
>>>>  }
>>>>
>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)udata_size;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf)
>>>> +{
>>>> +       (void)buf;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>>>> +                                                size_t ndx)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)ndx;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>>>> +                                            odp_buffer_segment_t seg)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)seg;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t
>>>> seg,
>>>> +                            size_t *seglen)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)seg;
>>>> +       (void)seglen;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>>>> +size_t *seglen)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)offset;
>>>> +       (void)seglen;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)offset;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return;
>>>> +}
>>>> +
>>>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t
>>>> buf_src)
>>>>  {
>>>>         (void)buf_dst;
>>>>         (void)buf_src;
>>>>  }
>>>> +
>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)offset;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
>>>> +{
>>>> +       (void)buf1;
>>>> +       (void)buf2;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)offset;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)ext;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
>>>> +{
>>>> +       (void)buf;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
>>>> +{
>>>> +       (void)buf;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> diff --git a/platform/linux-generic/odp_buffer_pool.c
>>>> b/platform/linux-generic/odp_buffer_pool.c
>>>> index a48d7d6..bff4db5 100644
>>>> --- a/platform/linux-generic/odp_buffer_pool.c
>>>> +++ b/platform/linux-generic/odp_buffer_pool.c
>>>> @@ -471,6 +471,13 @@ odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t
>>>> pool_hdl)
>>>>         return handle.u32;
>>>>  }
>>>>
>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size)
>>>> +{
>>>> +       (void)pool;
>>>> +       (void) size;
>>>> +       ODP_ERR("%s function is yet to be implemented", __func__);
>>>> +       return 0;
>>>> +}
>>>>
>>>>  void odp_buffer_free(odp_buffer_t buf)
>>>>  {
>>>> --
>>>> 2.0.1.472.g6f92e5f
>>>>
>>>>
>>>> _______________________________________________
>>>> lng-odp mailing list
>>>> lng-odp@lists.linaro.org
>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> lng-odp mailing list
>>>> lng-odp@lists.linaro.org
>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>
>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>> _______________________________________________
>>> lng-odp mailing list
>>> lng-odp@lists.linaro.org
>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>
>>>
>>
>> _______________________________________________
>> lng-odp mailing list
>> lng-odp@lists.linaro.org
>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>
>>
>
Anders Roxell Oct. 17, 2014, 1:12 p.m. UTC | #9
On 17 October 2014 15:03, Ola Liljedahl <ola.liljedahl@linaro.org> wrote:

> But segmentation is already needed in a current and known subclass (i.e.
> packets). We are not talking about some other feature which we don't know
> if it will be needed. So this is not a case of "just in case".
>

I agree with Petri, that it should be in the packet and not in the buffer.
Why put stuff in the buffer when it only belongs to one subclass (packets)
as of today?

Cheers,
Anders


>
> -- Ola#1
>
>
> On 17 October 2014 14:45, Ola Dahl <dahl.ola@gmail.com> wrote:
>
>> Hi,
>>
>> I do not think it is wise to put features in the base class "just in
>> case" they would be needed in some future (not yet known) subclass.
>>
>> So if the concept of segmentation is relevant for packets but not for
>> timers then I think it should be implemented as a feature of packets.
>>
>> Best regards,
>>
>> Ola D
>>
>> On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer <
>> bill.fischofer@linaro.org> wrote:
>>
>>> I agree that packets are the buffer type that most likely uses segments,
>>> however there are many advantages to putting this support in the base class
>>> rather than the subclass independent of the number of buffer subclasses
>>> that will use this support today.
>>>
>>>    - It's simpler
>>>    - It's more extensible
>>>    - It results in cleaner and more efficient application code
>>>
>>> Allow me to expand on these points.  First simplicity.  Call the work
>>> required to support segmentation in the implementation X.  That X is going
>>> to be pretty much constant no matter where it is done.  But if the
>>> implementation has a choice between doing X at a low level vs. doing it at
>>> a high level then it's simpler for the implementation to do it once and be
>>> done with it.  If the implementation does it at a higher level then it is
>>> either constrained to map that higher-level implementation to be built on a
>>> set of lower-level functions that may or may not be appropriate or else it
>>> needs to do a completely parallel implementation that is optimal but highly
>>> duplicative.
>>>
>>> Extensibility should be clear.  If at some future point we decide
>>> segmentation would be useful for some new buffer type (e.g., IPC) then
>>> that's trivial to do if the base class supports it and awkward if it's only
>>> part of packets.
>>>
>>> From an application standpoint, it's cleaner because the packet APIs are
>>> just wrappers around their corresponding buffer APIs and can be mapped
>>> directly.  Otherwise we have a set of APIs that don't map and are not
>>> easily translatable.
>>>
>>> With regard to efficient segment access, that's what the
>>> odp_packet_addr() routine provides--one-step fast-path addressability to
>>> the first segment of a packet.  An odp_packet_t is an abstract opaque
>>> type.  It is not, and cannot be treated as an address by the application.
>>>
>>> Does that make sense?
>>>
>>> Bill
>>>
>>>
>>>
>>>
>>> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN - FI/Espoo) <
>>> petri.savolainen@nsn.com> wrote:
>>>
>>>>  Hi,
>>>>
>>>>
>>>>
>>>> 1. The only segmentation use case is for segmented packet, not for
>>>> segmented buffers.
>>>>
>>>>
>>>>
>>>> 2. Common case for packets is that everything application needs is in
>>>> the first segment. Odp_packet_t could refer always into that “first
>>>> segment”, so that application (in the common case) would not need to use
>>>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.
>>>>
>>>>
>>>>
>>>> When buffer level features are minimized, the need for
>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All packet
>>>> manipulation should happen through odp_packet_xxx(pkt, …) calls.
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> -Petri
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> *From:* ext Bill Fischofer [mailto:bill.fischofer@linaro.org]
>>>> *Sent:* Friday, October 17, 2014 1:17 PM
>>>> *To:* Savolainen, Petri (NSN - FI/Espoo)
>>>> *Cc:* ext Jacob, Jerin; lng-odp@lists.linaro.org
>>>>
>>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>
>>>>
>>>>
>>>> I'm not sure how to understand these two statements:
>>>>
>>>>
>>>>
>>>> 1. There's no use case for segmented buffers
>>>>
>>>> 2. We should optimize for the common case (with segments)
>>>>
>>>>
>>>>
>>>> These seem contradictory.
>>>>
>>>>
>>>>
>>>> The use case for segmented buffers is that some platforms have a
>>>> HW-defined and managed segmented buffer model. If we insist that the
>>>> application be able to specify and control packet segment sizes we are
>>>> making the decision to exclude such platforms from supporting ODP.  The
>>>> optimization suggested is precisely what is being proposed here.  By
>>>> default packets are assumed to be contained in implementation-managed
>>>> segmented buffers and the first segment will be large enough to contain all
>>>> packet headers for non-pathological cases.  The case where the application
>>>> wishes to traverse the entire packet in SW is expected to be rare because
>>>> in the data plane you simply do not have the cycles to do this at line rate
>>>> for all packets.
>>>>
>>>>
>>>>
>>>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs, this is
>>>> simply syntax to avoid the constant need for explicit conversion functions
>>>> since unlike C++, C does not support generic functions.  So you cannot pass
>>>> an odp_packet_t to a function that expects an odp_buffer_t argument without
>>>> a conversion call.  Do we really want to force applications to constantly
>>>> be writing code like:
>>>>
>>>>
>>>>
>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)
>>>>
>>>>
>>>>
>>>> rather than
>>>>
>>>>
>>>>
>>>> odp_packet_xxx(pkt,...)
>>>>
>>>>
>>>>
>>>> Not only is this awkward, it is also inefficient.  By having the
>>>> explicit odp_packet_xxx() calls, the implementation is free to optimize
>>>> these references in whatever manner is appropriate to that implementation.
>>>> For some this may be a simple preprocessor-type expansion while for others
>>>> there may be more sophisticated handling.  But the application should
>>>> neither know nor care about how the implementation chooses to do this.
>>>>
>>>>
>>>>
>>>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN - FI/Espoo) <
>>>> petri.savolainen@nsn.com> wrote:
>>>>
>>>> Hi,
>>>>
>>>>
>>>>
>>>> This is also my opinion. There’s no use case for segmented buffers in
>>>> v1.0 - so let’s keep it simple and define that buffers (and thus buffer
>>>> pools) are always unsegmented. Segmentation comes into play only with
>>>> packets (and only with those packets that cannot fit into a single buffer).
>>>> For example, if implementation has max buffer size 256, any packets larger
>>>> than that are segmented and segments are handled with packet_seg_xxx calls.
>>>>
>>>>
>>>>
>>>> Also, I’d propose that we optimize for the common case (with segments)
>>>> - so that the odp_packet_t handle would refer always to the head of packet
>>>> segment. If the first segment (data/data_len pointed by the odp_packet_t)
>>>> carries all data application is interested in (=protocol headers), the
>>>> application would not have to use the segment API at all. Most applications
>>>> would not see any difference between small/large or segmented/unsegmented
>>>> packets as long as all headers fit into the first segment.
>>>>
>>>>
>>>>
>>>> -Petri
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> *From:* lng-odp-bounces@lists.linaro.org [mailto:
>>>> lng-odp-bounces@lists.linaro.org] *On Behalf Of *ext Jacob, Jerin
>>>> *Sent:* Friday, October 17, 2014 9:34 AM
>>>> *To:* Bill Fischofer
>>>> *Cc:* lng-odp@lists.linaro.org
>>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>
>>>>
>>>>
>>>> The need for segment API infrastructure is very clear.The question is,
>>>> Do we need separate APIs for
>>>>
>>>> segment management at odp_buffer_segment* AND odp_packet_segment*
>>>> levels ?
>>>>
>>>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always
>>>> unsegmented and if there is a
>>>>
>>>> API for odp_packet_segement* then there will be not be any consumer for
>>>> odp_buffer_segment* API for 1.0​
>>>>
>>>>
>>>>  ------------------------------
>>>>
>>>> *From:* Bill Fischofer <bill.fischofer@linaro.org>
>>>> *Sent:* Thursday, October 16, 2014 9:08 PM
>>>> *To:* Jacob, Jerin
>>>> *Cc:* Ola Liljedahl; Balasubramanian Manoharan;
>>>> lng-odp@lists.linaro.org
>>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>
>>>>
>>>>
>>>> From the buffer design doc (p. 8-9):
>>>>  *Buffer Pool Options*
>>>>
>>>> The *odp_buffer_opts_e* enum is used to specify additional options
>>>> relating to the buffer pool.  Buffer pool options defined are:
>>>>
>>>>
>>>> ·     ODP_BUFFER_OPTS_NONE
>>>>
>>>> ·     ODP_BUFFER_OPTS_UNSEGMENTED
>>>>
>>>>
>>>> These options are additive so an application can simply specify a
>>>> buf_opts by ORing together the options needed.  Note that buffer pool
>>>> options are themselves OPTIONAL and a given implementation MAY fail the
>>>> buffer pool creation request with an appropriate *errno* if the
>>>> requested option is not supported by the underlying ODP implementation,
>>>> with the exception that UNSEGMENTED pools MUST be supported for non-packet
>>>> types and for packet types as long as the requested size is less than the
>>>> implementation-defined native packet segment size.
>>>>
>>>>
>>>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options with
>>>> no additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies that
>>>> the buffer pool should be unsegmented.
>>>>
>>>>
>>>> So unsegmented buffer pool support is available.  As far as RAW buffers
>>>> go, again from the doc (p. 14):
>>>>  *ODP_BUFFER_TYPE_RAW*
>>>>
>>>> This is the “basic” buffer type which simply consists of a single
>>>> fixed-sized block of contiguous memory.  Buffers of this type do not
>>>> support user meta data and the only built-in meta data supported for this
>>>> type of buffer are those that are statically computable, such as pool and
>>>> size. This type of buffer is entirely under application control and most of
>>>> the buffer APIs defined in this document are not available.  APIs for this
>>>> type of buffer are described in this document.
>>>>
>>>>
>>>>
>>>> So RAW buffers are always unsegmented.  The intent is that Packets are
>>>> by default segmented but can be unsegmented while the other buffer types
>>>> are by default unsegmented but (with the exception of RAW buffers) can be
>>>> made segmented.  This is because all buffers start out as a single segment
>>>> and hence are unsegmented until they are expanded to overflow that single
>>>> segment.
>>>>
>>>>
>>>>
>>>> Hope that clarifies things.  Again, this is all very straightforward
>>>> and only comes into play when actually needed.
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin <
>>>> Jerin.Jacob@caviumnetworks.com> wrote:
>>>>
>>>> If there is no valid use case for supporting segmentation for raw
>>>> buffers then lets drop it. At least it will reduce the effort of
>>>>
>>>> implementing and testing/verification buffer APIs on  different
>>>> platforms.
>>>>
>>>>
>>>>   ------------------------------
>>>>
>>>> *From:* lng-odp-bounces@lists.linaro.org <
>>>> lng-odp-bounces@lists.linaro.org> on behalf of Ola Liljedahl <
>>>> ola.liljedahl@linaro.org>
>>>> *Sent:* Wednesday, October 8, 2014 1:37 PM
>>>> *To:* Balasubramanian Manoharan
>>>> *Cc:* lng-odp@lists.linaro.org
>>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>
>>>>
>>>>
>>>> As I wrote in my comment to the architecture discussion yesterday, I am
>>>> against segmentation for buffers. Or at least there must be the possibility
>>>> to create a buffer pool with guaranteed non-segmented buffers. Segmented
>>>> packets are OK but not all usages for buffers relate to packets. A lot of
>>>> internal usages (timeouts, SW messages, internal data structures) will not
>>>> be able to handle segmented buffers so *you must be able to force the
>>>> creation of buffer pools with non-segmented buffers.*
>>>>
>>>>
>>>>
>>>> -- Ola
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> On 8 October 2014 09:50, Balasubramanian Manoharan <
>>>> bala.manoharan@linaro.org> wrote:
>>>>
>>>> This patch contains ODP Buffer Management missing APIs
>>>> The intent of this patch is to port the missing APIs from Buffer
>>>> Management design document into Linux-generic repo.
>>>> The dummy functions will be replaced during linux-generic
>>>> implementation.
>>>>
>>>> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>
>>>> ---
>>>>  platform/linux-generic/include/api/odp_buffer.h    | 203
>>>> ++++++++++++++++++++-
>>>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
>>>>  platform/linux-generic/odp_buffer.c                | 120 ++++++++++++
>>>>  platform/linux-generic/odp_buffer_pool.c           |   7 +
>>>>  4 files changed, 351 insertions(+), 9 deletions(-)
>>>>
>>>> diff --git a/platform/linux-generic/include/api/odp_buffer.h
>>>> b/platform/linux-generic/include/api/odp_buffer.h
>>>> index d8577fd..aeb75ed 100644
>>>> --- a/platform/linux-generic/include/api/odp_buffer.h
>>>> +++ b/platform/linux-generic/include/api/odp_buffer.h
>>>> @@ -28,8 +28,34 @@ extern "C" {
>>>>   */
>>>>  typedef uint32_t odp_buffer_t;
>>>>
>>>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>>>> +/**
>>>> +* ODP buffer segment
>>>> +*/
>>>> +typedef uint32_t odp_buffer_segment_t;
>>>>
>>>> +/**
>>>> +* ODP buffer type
>>>> +*/
>>>> +typedef enum odp_buffer_type {
>>>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */
>>>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold any
>>>> other
>>>> +                                       buffer type */
>>>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
>>>> +                                       no additional metadata */
>>>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
>>>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
>>>> +} odp_buffer_type_e;
>>>> +
>>>> +/**
>>>> +* ODP buffer options
>>>> +*/
>>>> +typedef enum odp_buffer_opts {
>>>> +       ODP_BUFFER_OPTS_NONE,
>>>> +       ODP_BUFFER_OPTS_UNSEGMENTED
>>>> +} odp_buffer_opts_e;
>>>> +
>>>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>>>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
>>>>
>>>>  /**
>>>>   * Buffer start address
>>>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
>>>>   */
>>>>  int odp_buffer_type(odp_buffer_t buf);
>>>>
>>>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
>>>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any
>>>> other
>>>> -                                         buffer type */
>>>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional
>>>> metadata */
>>>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
>>>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
>>>> -
>>>> -
>>>>  /**
>>>>   * Tests if buffer is valid
>>>>   *
>>>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
>>>>  int odp_buffer_is_valid(odp_buffer_t buf);
>>>>
>>>>  /**
>>>> + * Tests if buffer is segmented
>>>> + *
>>>> + * @param[in]  buf     Buffer handle
>>>> + *
>>>> + * @return             1 if buffer has more than one segment,
>>>> + *                     otherwise 0
>>>> + */
>>>> +
>>>> +int odp_buffer_is_segmented(odp_buffer_t buf);
>>>> +
>>>> +/**
>>>> + * Get address and size of user meta data associated with a buffer
>>>> + *
>>>> + * @param[in]  buf             Buffer handle
>>>> + * @param[out] udata_size      Number of bytes of user meta data
>>>> available
>>>> + *                             at the returned address
>>>> + * @return                     Address of the user meta data for this
>>>> buffer
>>>> + *                             or NULL if the buffer has no user meta
>>>> data.
>>>> + */
>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
>>>> +
>>>> +/**
>>>> + * Get address of user meta data associated with a buffer
>>>> + *
>>>> + * @param[in]  buf     Buffer handle
>>>> + *
>>>> + * @return             Address of the user meta data for this buffer
>>>> + *                     or NULL if the buffer has no user meta data.
>>>> + */
>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf);
>>>> +
>>>> +/**
>>>> + * Get count of number of segments in a buffer
>>>> + *
>>>> + * @param[in]  buf     Buffer handle
>>>> + *
>>>> + * @return             Count of the number of segments in buf
>>>> + */
>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf);
>>>> +
>>>> +/**
>>>> + * Get the segment identifier for a buffer segment by index
>>>> + *
>>>> + * @param[in]  buf     Buffer handle
>>>> + * @param[in]  ndx     Segment index of segment of interest
>>>> + *
>>>> + * @return             Segment identifier or ODP_SEGMENT_INVALID if the
>>>> + *                     supplied ndx is out of range.
>>>> + */
>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>>>> size_t ndx);
>>>> +
>>>> +/**
>>>> + * Get the next segment identifier for a buffer segment
>>>> + *
>>>> + * @param[in]  buf     Buffer handle
>>>> + * @param[in]  seg     Segment identifier of the previous segment
>>>> + *
>>>> + * @return             Segment identifier of the next segment,
>>>> +                       or ODP_SEGMENT_INVALID.
>>>> + */
>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>>>> +                                            odp_buffer_segment_t seg);
>>>> +/**
>>>> + * Get start address for a specified buffer segment
>>>> + *
>>>> + * @param[in]  buf     Buffer handle
>>>> + * @param[in]  seg     Segment identifier of the buffer to be addressed
>>>> + * @param[out] seglen  Returned number of bytes in this buffer
>>>> + *                     segment available at returned address
>>>> + *
>>>> + * @return             Segment start address or NULL
>>>> + */
>>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t
>>>> seg,
>>>> +size_t *seglen);
>>>> +
>>>> +/**
>>>> + *Unmap a buffer segment
>>>> + *
>>>> + * @param[in]  seg     Buffer segment handle
>>>> + */
>>>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
>>>> +
>>>> +/**
>>>> +* Get start address for a specified buffer offset
>>>> +*
>>>> +* @param[in]   buf     Buffer handle
>>>> +* @param[in]   offset  Byte offset within the buffer to be addressed
>>>> +* @param[out]  seglen  Returned number of bytes in this buffer
>>>> +*                      segment available at returned address
>>>> +*
>>>> +* @return              Offset start address or NULL
>>>> +*/
>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>>>> +size_t *seglen);
>>>> +
>>>> +/**
>>>> + * Unmap a buffer segment by offset
>>>> + *
>>>> + * @param[in]  buf     Buffer handle
>>>> + * @param[in]  offset  Buffer offset
>>>> + */
>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
>>>> +
>>>> +/**
>>>>   * Print buffer metadata to STDOUT
>>>>   *
>>>>   * @param buf      Buffer handle
>>>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
>>>>   */
>>>>  void odp_buffer_print(odp_buffer_t buf);
>>>>
>>>> +/**
>>>> + * Split a buffer into two buffers at a specified split point
>>>> + *
>>>> + * @param[in]  buf     Handle of buffer to split
>>>> + * @param[in]  offset  Byte offset within buf to split buffer
>>>> + *
>>>> + * @return             Buffer handle of the created split buffer
>>>> + */
>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
>>>> +
>>>> +/**
>>>> + * Join two buffers into a single buffer
>>>> + *
>>>> + * @param[in]  buf1    Buffer handle of first buffer to join
>>>> + * @param[in]  buf2    Buffer handle of second buffer to join
>>>> + *
>>>> + * @return             Buffer handle of the joined buffer
>>>> + */
>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);
>>>> +
>>>> +/**
>>>> + * Trim a buffer at a specified trim point
>>>> + *
>>>> + * @param[in]  buf     Buffer handle of buffer to trim
>>>> + * @param[in]  offset  byte offset within buf to trim
>>>> + *
>>>> + * @return             Handle of the trimmed buffer or
>>>> + *                     ODP_BUFFER_INVALID if the operation was not
>>>> performed
>>>> + */
>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
>>>> +/**
>>>> + * Extend a buffer for a specified number of bytes
>>>> + *
>>>> + * @param[in]  buf     Buffer handle of buffer to expand
>>>> + * @param[in]  ext     size, in bytes, of the extent to add to the
>>>> + *                     existing buffer.
>>>> + *
>>>> + * @return             Handle of the extended buffer or
>>>> ODP_BUFFER_INVALID
>>>> + *                     if the operation was not performed
>>>> + */
>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
>>>> +
>>>> +/**
>>>> + * Clone a buffer, returning an exact copy of it
>>>> + *
>>>> + * @param[in]  buf     Buffer handle of buffer to duplicate
>>>> + *
>>>> + * @return             Handle of the duplicated buffer or
>>>> ODP_BUFFER_INVALID
>>>> + *                     if the operation was not performed
>>>> + */
>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
>>>> +
>>>> +/**
>>>> + * Copy a buffer, returning an exact copy of it
>>>> + *
>>>> + * @param[in]  buf     Buffer handle of buffer to copy
>>>> + *
>>>> + * @return             Handle of the copied buffer or
>>>> ODP_BUFFER_INVALID
>>>> + *                     if the operation was not performed
>>>> + */
>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
>>>> +
>>>> +
>>>>
>>>>  #ifdef __cplusplus
>>>>  }
>>>> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
>>>> b/platform/linux-generic/include/api/odp_buffer_pool.h
>>>> index fe88898..f85d96c 100644
>>>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
>>>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
>>>> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const char
>>>> *name,
>>>>
>>>>
>>>>  /**
>>>> + * Get the next buffer pool from its predecessor
>>>> + *
>>>> + * @param[in]  pool            Buffer pool handle
>>>> + * @param[out] name            Name of the pool
>>>> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1 chars)
>>>> + * @param[out] udata_size      Size of user meta data used by this
>>>> pool.
>>>> + * @param[out] buf_num         Number of buffers contained in this pool
>>>> + * @param[out] buf_size        Default size of application data in
>>>> each buffer
>>>> + * @param[out] buf_type        Buffer type of the pool
>>>> + * @param[out] buf_opts        Buffer options for this pool
>>>> + * @param[out] predef          Predefined (1) or Created (0).
>>>> + *
>>>> + * @return                     Buffer pool handle
>>>> + */
>>>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
>>>> +                                      char *name, size_t *udata_size,
>>>> +                                      size_t *buf_num, size_t
>>>> *buf_size,
>>>> +                                      enum odp_buffer_type *buf_type,
>>>> +                                      enum odp_buffer_opts *buf_opts,
>>>> +                                      uint32_t *predef);
>>>> +/**
>>>>   * Find a buffer pool by name
>>>>   *
>>>>   * @param name      Name of the pool
>>>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t pool);
>>>>   */
>>>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
>>>>
>>>> +/**
>>>> +* Allocate a buffer from a buffer pool
>>>> +*
>>>> +* @param[in]   pool    Pool handle
>>>> +* @param[in]   size    Size of object to store in buffer
>>>> +*
>>>> +* @return              Buffer handle or ODP_BUFFER_INVALID
>>>> +*/
>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t
>>>> size);
>>>>
>>>>  /**
>>>>   * Buffer free
>>>> diff --git a/platform/linux-generic/odp_buffer.c
>>>> b/platform/linux-generic/odp_buffer.c
>>>> index e54e0e7..7f4b4f0 100644
>>>> --- a/platform/linux-generic/odp_buffer.c
>>>> +++ b/platform/linux-generic/odp_buffer.c
>>>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
>>>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
>>>>  }
>>>>
>>>> +int odp_buffer_is_segmented(odp_buffer_t buf)
>>>> +{
>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>>>> +
>>>> +       if (buf_hdr->scatter.num_bufs == 0)
>>>> +               return 0;
>>>> +       else
>>>> +               return 1;
>>>> +}
>>>> +
>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf)
>>>> +{
>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>>>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
>>>> +}
>>>>
>>>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
>>>>  {
>>>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
>>>>         printf("\n%s\n", str);
>>>>  }
>>>>
>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)udata_size;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf)
>>>> +{
>>>> +       (void)buf;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>>>> +                                                size_t ndx)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)ndx;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>>>> +                                            odp_buffer_segment_t seg)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)seg;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t
>>>> seg,
>>>> +                            size_t *seglen)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)seg;
>>>> +       (void)seglen;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>>>> +size_t *seglen)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)offset;
>>>> +       (void)seglen;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)offset;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return;
>>>> +}
>>>> +
>>>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t
>>>> buf_src)
>>>>  {
>>>>         (void)buf_dst;
>>>>         (void)buf_src;
>>>>  }
>>>> +
>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)offset;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
>>>> +{
>>>> +       (void)buf1;
>>>> +       (void)buf2;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)offset;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
>>>> +{
>>>> +       (void)buf;
>>>> +       (void)ext;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
>>>> +{
>>>> +       (void)buf;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
>>>> +{
>>>> +       (void)buf;
>>>> +       ODP_UNIMPLEMENTED();
>>>> +       return 0;
>>>> +}
>>>> +
>>>> diff --git a/platform/linux-generic/odp_buffer_pool.c
>>>> b/platform/linux-generic/odp_buffer_pool.c
>>>> index a48d7d6..bff4db5 100644
>>>> --- a/platform/linux-generic/odp_buffer_pool.c
>>>> +++ b/platform/linux-generic/odp_buffer_pool.c
>>>> @@ -471,6 +471,13 @@ odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t
>>>> pool_hdl)
>>>>         return handle.u32;
>>>>  }
>>>>
>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size)
>>>> +{
>>>> +       (void)pool;
>>>> +       (void) size;
>>>> +       ODP_ERR("%s function is yet to be implemented", __func__);
>>>> +       return 0;
>>>> +}
>>>>
>>>>  void odp_buffer_free(odp_buffer_t buf)
>>>>  {
>>>> --
>>>> 2.0.1.472.g6f92e5f
>>>>
>>>>
>>>> _______________________________________________
>>>> lng-odp mailing list
>>>> lng-odp@lists.linaro.org
>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> lng-odp mailing list
>>>> lng-odp@lists.linaro.org
>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>
>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>> _______________________________________________
>>> lng-odp mailing list
>>> lng-odp@lists.linaro.org
>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>
>>>
>>
>> _______________________________________________
>> lng-odp mailing list
>> lng-odp@lists.linaro.org
>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>
>>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
>
Bill Fischofer Oct. 17, 2014, 1:33 p.m. UTC | #10
Let's consider the implications of removing segmentation support from
buffers and only having that concept be part of packets.

The first question that arises is what is the relationship between the
abstract types odp_packet_t and odp_buffer_t? This is important because
currently we say that packets are allocated from ODP buffer pools, not from
packet pools.  Do we need a separate odp_packet_pool_t that is used for
packets?

Today, when I allocate a packet I'm allocating a single object that happens
to be a single buffer object of type ODP_BUFFER_TYPE_PACKET.  But that only
works if the two objects have compatible semantics (including
segmentation).  If the semantics are not compatible, then an odp_packet_t
may in fact be composed of multiple odp_buffer_t's because the packet may
consist of multiple segments and buffers no longer recognize the concept of
segments so a single buffer can only be a single segment.

So now an odp_packet_segment_t may be an odp_buffer_t but an odp_packet_t
in fact is some meta-object that is constructed (by whom?) from multiple
odp_packet_segment_ts that are themselves odp_buffer_ts.  So
odp_packet_to_buffer() no longer makes sense since there is no longer a
one-to-one correspondence between packets and buffers.  We could have an
odp_packet_segment_to_buffer() routine instead.

Next question: What about meta data?  If an odp_packet_t is a type of an
odp_buffer_t then this is very straightforward since all buffer meta data
is reusable as packet meta data and the packet type can just add its own
specific meta data to this set.  But if an odp_packet_t is now a separate
object then where does the storage for its meta data come from? If we try
to map it into an odp_buffer_t that doesn't work since an odp_packet_t may
consist of multiple underlying odp_buffer_ts, one for each
odp_packet_segment_t.  Is the packet meta data duplicated in each segment?
Is the first segment of a packet special (odp_packet_first_segment_t)?  And
what about user meta data, since this is of potentially variable size?

I submit that there are a lot of implications to this that need to be fully
thought through, which is why I believe it's simpler to keep segmentation
as part of buffers that (for now) only happens to be used by a particular
type of buffer, namely packets.

Bill

On Fri, Oct 17, 2014 at 8:05 AM, Ola Liljedahl <ola.liljedahl@linaro.org>
wrote:

> Personally I don't see any need for segmentation support in buffers. I am
> just trying to shoot down what I think is flawed reasoning.
>
> -- Ola#1
>
> On 17 October 2014 15:03, Ola Liljedahl <ola.liljedahl@linaro.org> wrote:
>
>> But segmentation is already needed in a current and known subclass (i.e.
>> packets). We are not talking about some other feature which we don't know
>> if it will be needed. So this is not a case of "just in case".
>>
>> -- Ola#1
>>
>>
>> On 17 October 2014 14:45, Ola Dahl <dahl.ola@gmail.com> wrote:
>>
>>> Hi,
>>>
>>> I do not think it is wise to put features in the base class "just in
>>> case" they would be needed in some future (not yet known) subclass.
>>>
>>> So if the concept of segmentation is relevant for packets but not for
>>> timers then I think it should be implemented as a feature of packets.
>>>
>>> Best regards,
>>>
>>> Ola D
>>>
>>> On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer <
>>> bill.fischofer@linaro.org> wrote:
>>>
>>>> I agree that packets are the buffer type that most likely uses
>>>> segments, however there are many advantages to putting this support in the
>>>> base class rather than the subclass independent of the number of buffer
>>>> subclasses that will use this support today.
>>>>
>>>>    - It's simpler
>>>>    - It's more extensible
>>>>    - It results in cleaner and more efficient application code
>>>>
>>>> Allow me to expand on these points.  First simplicity.  Call the work
>>>> required to support segmentation in the implementation X.  That X is going
>>>> to be pretty much constant no matter where it is done.  But if the
>>>> implementation has a choice between doing X at a low level vs. doing it at
>>>> a high level then it's simpler for the implementation to do it once and be
>>>> done with it.  If the implementation does it at a higher level then it is
>>>> either constrained to map that higher-level implementation to be built on a
>>>> set of lower-level functions that may or may not be appropriate or else it
>>>> needs to do a completely parallel implementation that is optimal but highly
>>>> duplicative.
>>>>
>>>> Extensibility should be clear.  If at some future point we decide
>>>> segmentation would be useful for some new buffer type (e.g., IPC) then
>>>> that's trivial to do if the base class supports it and awkward if it's only
>>>> part of packets.
>>>>
>>>> From an application standpoint, it's cleaner because the packet APIs
>>>> are just wrappers around their corresponding buffer APIs and can be mapped
>>>> directly.  Otherwise we have a set of APIs that don't map and are not
>>>> easily translatable.
>>>>
>>>> With regard to efficient segment access, that's what the
>>>> odp_packet_addr() routine provides--one-step fast-path addressability to
>>>> the first segment of a packet.  An odp_packet_t is an abstract opaque
>>>> type.  It is not, and cannot be treated as an address by the application.
>>>>
>>>> Does that make sense?
>>>>
>>>> Bill
>>>>
>>>>
>>>>
>>>>
>>>> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN - FI/Espoo) <
>>>> petri.savolainen@nsn.com> wrote:
>>>>
>>>>>  Hi,
>>>>>
>>>>>
>>>>>
>>>>> 1. The only segmentation use case is for segmented packet, not for
>>>>> segmented buffers.
>>>>>
>>>>>
>>>>>
>>>>> 2. Common case for packets is that everything application needs is in
>>>>> the first segment. Odp_packet_t could refer always into that “first
>>>>> segment”, so that application (in the common case) would not need to use
>>>>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.
>>>>>
>>>>>
>>>>>
>>>>> When buffer level features are minimized, the need for
>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All packet
>>>>> manipulation should happen through odp_packet_xxx(pkt, …) calls.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> -Petri
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> *From:* ext Bill Fischofer [mailto:bill.fischofer@linaro.org]
>>>>> *Sent:* Friday, October 17, 2014 1:17 PM
>>>>> *To:* Savolainen, Petri (NSN - FI/Espoo)
>>>>> *Cc:* ext Jacob, Jerin; lng-odp@lists.linaro.org
>>>>>
>>>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>>
>>>>>
>>>>>
>>>>> I'm not sure how to understand these two statements:
>>>>>
>>>>>
>>>>>
>>>>> 1. There's no use case for segmented buffers
>>>>>
>>>>> 2. We should optimize for the common case (with segments)
>>>>>
>>>>>
>>>>>
>>>>> These seem contradictory.
>>>>>
>>>>>
>>>>>
>>>>> The use case for segmented buffers is that some platforms have a
>>>>> HW-defined and managed segmented buffer model. If we insist that the
>>>>> application be able to specify and control packet segment sizes we are
>>>>> making the decision to exclude such platforms from supporting ODP.  The
>>>>> optimization suggested is precisely what is being proposed here.  By
>>>>> default packets are assumed to be contained in implementation-managed
>>>>> segmented buffers and the first segment will be large enough to contain all
>>>>> packet headers for non-pathological cases.  The case where the application
>>>>> wishes to traverse the entire packet in SW is expected to be rare because
>>>>> in the data plane you simply do not have the cycles to do this at line rate
>>>>> for all packets.
>>>>>
>>>>>
>>>>>
>>>>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs, this is
>>>>> simply syntax to avoid the constant need for explicit conversion functions
>>>>> since unlike C++, C does not support generic functions.  So you cannot pass
>>>>> an odp_packet_t to a function that expects an odp_buffer_t argument without
>>>>> a conversion call.  Do we really want to force applications to constantly
>>>>> be writing code like:
>>>>>
>>>>>
>>>>>
>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)
>>>>>
>>>>>
>>>>>
>>>>> rather than
>>>>>
>>>>>
>>>>>
>>>>> odp_packet_xxx(pkt,...)
>>>>>
>>>>>
>>>>>
>>>>> Not only is this awkward, it is also inefficient.  By having the
>>>>> explicit odp_packet_xxx() calls, the implementation is free to optimize
>>>>> these references in whatever manner is appropriate to that implementation.
>>>>> For some this may be a simple preprocessor-type expansion while for others
>>>>> there may be more sophisticated handling.  But the application should
>>>>> neither know nor care about how the implementation chooses to do this.
>>>>>
>>>>>
>>>>>
>>>>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN - FI/Espoo) <
>>>>> petri.savolainen@nsn.com> wrote:
>>>>>
>>>>> Hi,
>>>>>
>>>>>
>>>>>
>>>>> This is also my opinion. There’s no use case for segmented buffers in
>>>>> v1.0 - so let’s keep it simple and define that buffers (and thus buffer
>>>>> pools) are always unsegmented. Segmentation comes into play only with
>>>>> packets (and only with those packets that cannot fit into a single buffer).
>>>>> For example, if implementation has max buffer size 256, any packets larger
>>>>> than that are segmented and segments are handled with packet_seg_xxx calls.
>>>>>
>>>>>
>>>>>
>>>>> Also, I’d propose that we optimize for the common case (with segments)
>>>>> - so that the odp_packet_t handle would refer always to the head of packet
>>>>> segment. If the first segment (data/data_len pointed by the odp_packet_t)
>>>>> carries all data application is interested in (=protocol headers), the
>>>>> application would not have to use the segment API at all. Most applications
>>>>> would not see any difference between small/large or segmented/unsegmented
>>>>> packets as long as all headers fit into the first segment.
>>>>>
>>>>>
>>>>>
>>>>> -Petri
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> *From:* lng-odp-bounces@lists.linaro.org [mailto:
>>>>> lng-odp-bounces@lists.linaro.org] *On Behalf Of *ext Jacob, Jerin
>>>>> *Sent:* Friday, October 17, 2014 9:34 AM
>>>>> *To:* Bill Fischofer
>>>>> *Cc:* lng-odp@lists.linaro.org
>>>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>>
>>>>>
>>>>>
>>>>> The need for segment API infrastructure is very clear.The question is,
>>>>> Do we need separate APIs for
>>>>>
>>>>> segment management at odp_buffer_segment* AND odp_packet_segment*
>>>>> levels ?
>>>>>
>>>>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always
>>>>> unsegmented and if there is a
>>>>>
>>>>> API for odp_packet_segement* then there will be not be any consumer
>>>>> for odp_buffer_segment* API for 1.0​
>>>>>
>>>>>
>>>>>  ------------------------------
>>>>>
>>>>> *From:* Bill Fischofer <bill.fischofer@linaro.org>
>>>>> *Sent:* Thursday, October 16, 2014 9:08 PM
>>>>> *To:* Jacob, Jerin
>>>>> *Cc:* Ola Liljedahl; Balasubramanian Manoharan;
>>>>> lng-odp@lists.linaro.org
>>>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>>
>>>>>
>>>>>
>>>>> From the buffer design doc (p. 8-9):
>>>>>  *Buffer Pool Options*
>>>>>
>>>>> The *odp_buffer_opts_e* enum is used to specify additional options
>>>>> relating to the buffer pool.  Buffer pool options defined are:
>>>>>
>>>>>
>>>>> ·     ODP_BUFFER_OPTS_NONE
>>>>>
>>>>> ·     ODP_BUFFER_OPTS_UNSEGMENTED
>>>>>
>>>>>
>>>>> These options are additive so an application can simply specify a
>>>>> buf_opts by ORing together the options needed.  Note that buffer pool
>>>>> options are themselves OPTIONAL and a given implementation MAY fail the
>>>>> buffer pool creation request with an appropriate *errno* if the
>>>>> requested option is not supported by the underlying ODP implementation,
>>>>> with the exception that UNSEGMENTED pools MUST be supported for non-packet
>>>>> types and for packet types as long as the requested size is less than the
>>>>> implementation-defined native packet segment size.
>>>>>
>>>>>
>>>>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options with
>>>>> no additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies that
>>>>> the buffer pool should be unsegmented.
>>>>>
>>>>>
>>>>> So unsegmented buffer pool support is available.  As far as RAW
>>>>> buffers go, again from the doc (p. 14):
>>>>>  *ODP_BUFFER_TYPE_RAW*
>>>>>
>>>>> This is the “basic” buffer type which simply consists of a single
>>>>> fixed-sized block of contiguous memory.  Buffers of this type do not
>>>>> support user meta data and the only built-in meta data supported for this
>>>>> type of buffer are those that are statically computable, such as pool and
>>>>> size. This type of buffer is entirely under application control and most of
>>>>> the buffer APIs defined in this document are not available.  APIs for this
>>>>> type of buffer are described in this document.
>>>>>
>>>>>
>>>>>
>>>>> So RAW buffers are always unsegmented.  The intent is that Packets are
>>>>> by default segmented but can be unsegmented while the other buffer types
>>>>> are by default unsegmented but (with the exception of RAW buffers) can be
>>>>> made segmented.  This is because all buffers start out as a single segment
>>>>> and hence are unsegmented until they are expanded to overflow that single
>>>>> segment.
>>>>>
>>>>>
>>>>>
>>>>> Hope that clarifies things.  Again, this is all very straightforward
>>>>> and only comes into play when actually needed.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin <
>>>>> Jerin.Jacob@caviumnetworks.com> wrote:
>>>>>
>>>>> If there is no valid use case for supporting segmentation for raw
>>>>> buffers then lets drop it. At least it will reduce the effort of
>>>>>
>>>>> implementing and testing/verification buffer APIs on  different
>>>>> platforms.
>>>>>
>>>>>
>>>>>   ------------------------------
>>>>>
>>>>> *From:* lng-odp-bounces@lists.linaro.org <
>>>>> lng-odp-bounces@lists.linaro.org> on behalf of Ola Liljedahl <
>>>>> ola.liljedahl@linaro.org>
>>>>> *Sent:* Wednesday, October 8, 2014 1:37 PM
>>>>> *To:* Balasubramanian Manoharan
>>>>> *Cc:* lng-odp@lists.linaro.org
>>>>> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>>
>>>>>
>>>>>
>>>>> As I wrote in my comment to the architecture discussion yesterday, I
>>>>> am against segmentation for buffers. Or at least there must be the
>>>>> possibility to create a buffer pool with guaranteed non-segmented buffers.
>>>>> Segmented packets are OK but not all usages for buffers relate to packets.
>>>>> A lot of internal usages (timeouts, SW messages, internal data structures)
>>>>> will not be able to handle segmented buffers so *you must be able to
>>>>> force the creation of buffer pools with non-segmented buffers.*
>>>>>
>>>>>
>>>>>
>>>>> -- Ola
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On 8 October 2014 09:50, Balasubramanian Manoharan <
>>>>> bala.manoharan@linaro.org> wrote:
>>>>>
>>>>> This patch contains ODP Buffer Management missing APIs
>>>>> The intent of this patch is to port the missing APIs from Buffer
>>>>> Management design document into Linux-generic repo.
>>>>> The dummy functions will be replaced during linux-generic
>>>>> implementation.
>>>>>
>>>>> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>
>>>>> ---
>>>>>  platform/linux-generic/include/api/odp_buffer.h    | 203
>>>>> ++++++++++++++++++++-
>>>>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
>>>>>  platform/linux-generic/odp_buffer.c                | 120 ++++++++++++
>>>>>  platform/linux-generic/odp_buffer_pool.c           |   7 +
>>>>>  4 files changed, 351 insertions(+), 9 deletions(-)
>>>>>
>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer.h
>>>>> b/platform/linux-generic/include/api/odp_buffer.h
>>>>> index d8577fd..aeb75ed 100644
>>>>> --- a/platform/linux-generic/include/api/odp_buffer.h
>>>>> +++ b/platform/linux-generic/include/api/odp_buffer.h
>>>>> @@ -28,8 +28,34 @@ extern "C" {
>>>>>   */
>>>>>  typedef uint32_t odp_buffer_t;
>>>>>
>>>>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>>>>> +/**
>>>>> +* ODP buffer segment
>>>>> +*/
>>>>> +typedef uint32_t odp_buffer_segment_t;
>>>>>
>>>>> +/**
>>>>> +* ODP buffer type
>>>>> +*/
>>>>> +typedef enum odp_buffer_type {
>>>>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */
>>>>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold any
>>>>> other
>>>>> +                                       buffer type */
>>>>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
>>>>> +                                       no additional metadata */
>>>>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
>>>>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
>>>>> +} odp_buffer_type_e;
>>>>> +
>>>>> +/**
>>>>> +* ODP buffer options
>>>>> +*/
>>>>> +typedef enum odp_buffer_opts {
>>>>> +       ODP_BUFFER_OPTS_NONE,
>>>>> +       ODP_BUFFER_OPTS_UNSEGMENTED
>>>>> +} odp_buffer_opts_e;
>>>>> +
>>>>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>>>>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
>>>>>
>>>>>  /**
>>>>>   * Buffer start address
>>>>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
>>>>>   */
>>>>>  int odp_buffer_type(odp_buffer_t buf);
>>>>>
>>>>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
>>>>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any
>>>>> other
>>>>> -                                         buffer type */
>>>>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional
>>>>> metadata */
>>>>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
>>>>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
>>>>> -
>>>>> -
>>>>>  /**
>>>>>   * Tests if buffer is valid
>>>>>   *
>>>>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
>>>>>  int odp_buffer_is_valid(odp_buffer_t buf);
>>>>>
>>>>>  /**
>>>>> + * Tests if buffer is segmented
>>>>> + *
>>>>> + * @param[in]  buf     Buffer handle
>>>>> + *
>>>>> + * @return             1 if buffer has more than one segment,
>>>>> + *                     otherwise 0
>>>>> + */
>>>>> +
>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf);
>>>>> +
>>>>> +/**
>>>>> + * Get address and size of user meta data associated with a buffer
>>>>> + *
>>>>> + * @param[in]  buf             Buffer handle
>>>>> + * @param[out] udata_size      Number of bytes of user meta data
>>>>> available
>>>>> + *                             at the returned address
>>>>> + * @return                     Address of the user meta data for this
>>>>> buffer
>>>>> + *                             or NULL if the buffer has no user meta
>>>>> data.
>>>>> + */
>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
>>>>> +
>>>>> +/**
>>>>> + * Get address of user meta data associated with a buffer
>>>>> + *
>>>>> + * @param[in]  buf     Buffer handle
>>>>> + *
>>>>> + * @return             Address of the user meta data for this buffer
>>>>> + *                     or NULL if the buffer has no user meta data.
>>>>> + */
>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf);
>>>>> +
>>>>> +/**
>>>>> + * Get count of number of segments in a buffer
>>>>> + *
>>>>> + * @param[in]  buf     Buffer handle
>>>>> + *
>>>>> + * @return             Count of the number of segments in buf
>>>>> + */
>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf);
>>>>> +
>>>>> +/**
>>>>> + * Get the segment identifier for a buffer segment by index
>>>>> + *
>>>>> + * @param[in]  buf     Buffer handle
>>>>> + * @param[in]  ndx     Segment index of segment of interest
>>>>> + *
>>>>> + * @return             Segment identifier or ODP_SEGMENT_INVALID if
>>>>> the
>>>>> + *                     supplied ndx is out of range.
>>>>> + */
>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>>>>> size_t ndx);
>>>>> +
>>>>> +/**
>>>>> + * Get the next segment identifier for a buffer segment
>>>>> + *
>>>>> + * @param[in]  buf     Buffer handle
>>>>> + * @param[in]  seg     Segment identifier of the previous segment
>>>>> + *
>>>>> + * @return             Segment identifier of the next segment,
>>>>> +                       or ODP_SEGMENT_INVALID.
>>>>> + */
>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>>>>> +                                            odp_buffer_segment_t seg);
>>>>> +/**
>>>>> + * Get start address for a specified buffer segment
>>>>> + *
>>>>> + * @param[in]  buf     Buffer handle
>>>>> + * @param[in]  seg     Segment identifier of the buffer to be
>>>>> addressed
>>>>> + * @param[out] seglen  Returned number of bytes in this buffer
>>>>> + *                     segment available at returned address
>>>>> + *
>>>>> + * @return             Segment start address or NULL
>>>>> + */
>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t
>>>>> seg,
>>>>> +size_t *seglen);
>>>>> +
>>>>> +/**
>>>>> + *Unmap a buffer segment
>>>>> + *
>>>>> + * @param[in]  seg     Buffer segment handle
>>>>> + */
>>>>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
>>>>> +
>>>>> +/**
>>>>> +* Get start address for a specified buffer offset
>>>>> +*
>>>>> +* @param[in]   buf     Buffer handle
>>>>> +* @param[in]   offset  Byte offset within the buffer to be addressed
>>>>> +* @param[out]  seglen  Returned number of bytes in this buffer
>>>>> +*                      segment available at returned address
>>>>> +*
>>>>> +* @return              Offset start address or NULL
>>>>> +*/
>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>>>>> +size_t *seglen);
>>>>> +
>>>>> +/**
>>>>> + * Unmap a buffer segment by offset
>>>>> + *
>>>>> + * @param[in]  buf     Buffer handle
>>>>> + * @param[in]  offset  Buffer offset
>>>>> + */
>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
>>>>> +
>>>>> +/**
>>>>>   * Print buffer metadata to STDOUT
>>>>>   *
>>>>>   * @param buf      Buffer handle
>>>>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
>>>>>   */
>>>>>  void odp_buffer_print(odp_buffer_t buf);
>>>>>
>>>>> +/**
>>>>> + * Split a buffer into two buffers at a specified split point
>>>>> + *
>>>>> + * @param[in]  buf     Handle of buffer to split
>>>>> + * @param[in]  offset  Byte offset within buf to split buffer
>>>>> + *
>>>>> + * @return             Buffer handle of the created split buffer
>>>>> + */
>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
>>>>> +
>>>>> +/**
>>>>> + * Join two buffers into a single buffer
>>>>> + *
>>>>> + * @param[in]  buf1    Buffer handle of first buffer to join
>>>>> + * @param[in]  buf2    Buffer handle of second buffer to join
>>>>> + *
>>>>> + * @return             Buffer handle of the joined buffer
>>>>> + */
>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);
>>>>> +
>>>>> +/**
>>>>> + * Trim a buffer at a specified trim point
>>>>> + *
>>>>> + * @param[in]  buf     Buffer handle of buffer to trim
>>>>> + * @param[in]  offset  byte offset within buf to trim
>>>>> + *
>>>>> + * @return             Handle of the trimmed buffer or
>>>>> + *                     ODP_BUFFER_INVALID if the operation was not
>>>>> performed
>>>>> + */
>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
>>>>> +/**
>>>>> + * Extend a buffer for a specified number of bytes
>>>>> + *
>>>>> + * @param[in]  buf     Buffer handle of buffer to expand
>>>>> + * @param[in]  ext     size, in bytes, of the extent to add to the
>>>>> + *                     existing buffer.
>>>>> + *
>>>>> + * @return             Handle of the extended buffer or
>>>>> ODP_BUFFER_INVALID
>>>>> + *                     if the operation was not performed
>>>>> + */
>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
>>>>> +
>>>>> +/**
>>>>> + * Clone a buffer, returning an exact copy of it
>>>>> + *
>>>>> + * @param[in]  buf     Buffer handle of buffer to duplicate
>>>>> + *
>>>>> + * @return             Handle of the duplicated buffer or
>>>>> ODP_BUFFER_INVALID
>>>>> + *                     if the operation was not performed
>>>>> + */
>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
>>>>> +
>>>>> +/**
>>>>> + * Copy a buffer, returning an exact copy of it
>>>>> + *
>>>>> + * @param[in]  buf     Buffer handle of buffer to copy
>>>>> + *
>>>>> + * @return             Handle of the copied buffer or
>>>>> ODP_BUFFER_INVALID
>>>>> + *                     if the operation was not performed
>>>>> + */
>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
>>>>> +
>>>>> +
>>>>>
>>>>>  #ifdef __cplusplus
>>>>>  }
>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
>>>>> b/platform/linux-generic/include/api/odp_buffer_pool.h
>>>>> index fe88898..f85d96c 100644
>>>>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
>>>>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
>>>>> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const char
>>>>> *name,
>>>>>
>>>>>
>>>>>  /**
>>>>> + * Get the next buffer pool from its predecessor
>>>>> + *
>>>>> + * @param[in]  pool            Buffer pool handle
>>>>> + * @param[out] name            Name of the pool
>>>>> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1
>>>>> chars)
>>>>> + * @param[out] udata_size      Size of user meta data used by this
>>>>> pool.
>>>>> + * @param[out] buf_num         Number of buffers contained in this
>>>>> pool
>>>>> + * @param[out] buf_size        Default size of application data in
>>>>> each buffer
>>>>> + * @param[out] buf_type        Buffer type of the pool
>>>>> + * @param[out] buf_opts        Buffer options for this pool
>>>>> + * @param[out] predef          Predefined (1) or Created (0).
>>>>> + *
>>>>> + * @return                     Buffer pool handle
>>>>> + */
>>>>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
>>>>> +                                      char *name, size_t *udata_size,
>>>>> +                                      size_t *buf_num, size_t
>>>>> *buf_size,
>>>>> +                                      enum odp_buffer_type *buf_type,
>>>>> +                                      enum odp_buffer_opts *buf_opts,
>>>>> +                                      uint32_t *predef);
>>>>> +/**
>>>>>   * Find a buffer pool by name
>>>>>   *
>>>>>   * @param name      Name of the pool
>>>>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t pool);
>>>>>   */
>>>>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
>>>>>
>>>>> +/**
>>>>> +* Allocate a buffer from a buffer pool
>>>>> +*
>>>>> +* @param[in]   pool    Pool handle
>>>>> +* @param[in]   size    Size of object to store in buffer
>>>>> +*
>>>>> +* @return              Buffer handle or ODP_BUFFER_INVALID
>>>>> +*/
>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t
>>>>> size);
>>>>>
>>>>>  /**
>>>>>   * Buffer free
>>>>> diff --git a/platform/linux-generic/odp_buffer.c
>>>>> b/platform/linux-generic/odp_buffer.c
>>>>> index e54e0e7..7f4b4f0 100644
>>>>> --- a/platform/linux-generic/odp_buffer.c
>>>>> +++ b/platform/linux-generic/odp_buffer.c
>>>>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
>>>>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
>>>>>  }
>>>>>
>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf)
>>>>> +{
>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>>>>> +
>>>>> +       if (buf_hdr->scatter.num_bufs == 0)
>>>>> +               return 0;
>>>>> +       else
>>>>> +               return 1;
>>>>> +}
>>>>> +
>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf)
>>>>> +{
>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>>>>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
>>>>> +}
>>>>>
>>>>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
>>>>>  {
>>>>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
>>>>>         printf("\n%s\n", str);
>>>>>  }
>>>>>
>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
>>>>> +{
>>>>> +       (void)buf;
>>>>> +       (void)udata_size;
>>>>> +       ODP_UNIMPLEMENTED();
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf)
>>>>> +{
>>>>> +       (void)buf;
>>>>> +       ODP_UNIMPLEMENTED();
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>>>>> +                                                size_t ndx)
>>>>> +{
>>>>> +       (void)buf;
>>>>> +       (void)ndx;
>>>>> +       ODP_UNIMPLEMENTED();
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>>>>> +                                            odp_buffer_segment_t seg)
>>>>> +{
>>>>> +       (void)buf;
>>>>> +       (void)seg;
>>>>> +       ODP_UNIMPLEMENTED();
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t
>>>>> seg,
>>>>> +                            size_t *seglen)
>>>>> +{
>>>>> +       (void)buf;
>>>>> +       (void)seg;
>>>>> +       (void)seglen;
>>>>> +       ODP_UNIMPLEMENTED();
>>>>> +       return 0;
>>>>> +}
>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>>>>> +size_t *seglen)
>>>>> +{
>>>>> +       (void)buf;
>>>>> +       (void)offset;
>>>>> +       (void)seglen;
>>>>> +       ODP_UNIMPLEMENTED();
>>>>> +       return 0;
>>>>> +}
>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
>>>>> +{
>>>>> +       (void)buf;
>>>>> +       (void)offset;
>>>>> +       ODP_UNIMPLEMENTED();
>>>>> +       return;
>>>>> +}
>>>>> +
>>>>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t
>>>>> buf_src)
>>>>>  {
>>>>>         (void)buf_dst;
>>>>>         (void)buf_src;
>>>>>  }
>>>>> +
>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
>>>>> +{
>>>>> +       (void)buf;
>>>>> +       (void)offset;
>>>>> +       ODP_UNIMPLEMENTED();
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
>>>>> +{
>>>>> +       (void)buf1;
>>>>> +       (void)buf2;
>>>>> +       ODP_UNIMPLEMENTED();
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
>>>>> +{
>>>>> +       (void)buf;
>>>>> +       (void)offset;
>>>>> +       ODP_UNIMPLEMENTED();
>>>>> +       return 0;
>>>>> +}
>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
>>>>> +{
>>>>> +       (void)buf;
>>>>> +       (void)ext;
>>>>> +       ODP_UNIMPLEMENTED();
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
>>>>> +{
>>>>> +       (void)buf;
>>>>> +       ODP_UNIMPLEMENTED();
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
>>>>> +{
>>>>> +       (void)buf;
>>>>> +       ODP_UNIMPLEMENTED();
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> diff --git a/platform/linux-generic/odp_buffer_pool.c
>>>>> b/platform/linux-generic/odp_buffer_pool.c
>>>>> index a48d7d6..bff4db5 100644
>>>>> --- a/platform/linux-generic/odp_buffer_pool.c
>>>>> +++ b/platform/linux-generic/odp_buffer_pool.c
>>>>> @@ -471,6 +471,13 @@ odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t
>>>>> pool_hdl)
>>>>>         return handle.u32;
>>>>>  }
>>>>>
>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t
>>>>> size)
>>>>> +{
>>>>> +       (void)pool;
>>>>> +       (void) size;
>>>>> +       ODP_ERR("%s function is yet to be implemented", __func__);
>>>>> +       return 0;
>>>>> +}
>>>>>
>>>>>  void odp_buffer_free(odp_buffer_t buf)
>>>>>  {
>>>>> --
>>>>> 2.0.1.472.g6f92e5f
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> lng-odp mailing list
>>>>> lng-odp@lists.linaro.org
>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> lng-odp mailing list
>>>>> lng-odp@lists.linaro.org
>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> lng-odp mailing list
>>>> lng-odp@lists.linaro.org
>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>
>>>>
>>>
>>> _______________________________________________
>>> lng-odp mailing list
>>> lng-odp@lists.linaro.org
>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>
>>>
>>
>
Ciprian Barbu Oct. 22, 2014, 11:47 a.m. UTC | #11
This thread has been cold for 5 days, so the assumption is that we can
go forward with the design right now. This patch series proposed by
Bala updates some part of the API to the final form of the Buffer
Design Document, we should have it merged if there are no more
objections. For that more people with the right expertise should have
a look at it and get the thread back on track.

I for example have observed the following issue. All the examples
create buffer pools over shared memory, which doesn't make sense for
some platforms, linux-dpdk for example, which ignores the base_addr
argument altogether. I think we need more clarity on this subject, for
sure the creation of buffer pools will differ from platform to
platform, which migrates to the application responsibility.

I think we should have a helper function to easily create buffer pools
without worrying too much about the difference in buffer management
between platforms, so that one can write a simple portable application
with no sweat. For the hardcore programmers the API still gives fine
control to buffer management that depending on the platform could
involve additional prerequisites, like creating a shared memory
segment to hold the buffer pool.

On Fri, Oct 17, 2014 at 4:33 PM, Bill Fischofer
<bill.fischofer@linaro.org> wrote:
> Let's consider the implications of removing segmentation support from
> buffers and only having that concept be part of packets.
>
> The first question that arises is what is the relationship between the
> abstract types odp_packet_t and odp_buffer_t? This is important because
> currently we say that packets are allocated from ODP buffer pools, not from
> packet pools.  Do we need a separate odp_packet_pool_t that is used for
> packets?
>
> Today, when I allocate a packet I'm allocating a single object that happens
> to be a single buffer object of type ODP_BUFFER_TYPE_PACKET.  But that only
> works if the two objects have compatible semantics (including segmentation).
> If the semantics are not compatible, then an odp_packet_t may in fact be
> composed of multiple odp_buffer_t's because the packet may consist of
> multiple segments and buffers no longer recognize the concept of segments so
> a single buffer can only be a single segment.
>
> So now an odp_packet_segment_t may be an odp_buffer_t but an odp_packet_t in
> fact is some meta-object that is constructed (by whom?) from multiple
> odp_packet_segment_ts that are themselves odp_buffer_ts.  So
> odp_packet_to_buffer() no longer makes sense since there is no longer a
> one-to-one correspondence between packets and buffers.  We could have an
> odp_packet_segment_to_buffer() routine instead.
>
> Next question: What about meta data?  If an odp_packet_t is a type of an
> odp_buffer_t then this is very straightforward since all buffer meta data is
> reusable as packet meta data and the packet type can just add its own
> specific meta data to this set.  But if an odp_packet_t is now a separate
> object then where does the storage for its meta data come from? If we try to
> map it into an odp_buffer_t that doesn't work since an odp_packet_t may
> consist of multiple underlying odp_buffer_ts, one for each
> odp_packet_segment_t.  Is the packet meta data duplicated in each segment?
> Is the first segment of a packet special (odp_packet_first_segment_t)?  And
> what about user meta data, since this is of potentially variable size?
>
> I submit that there are a lot of implications to this that need to be fully
> thought through, which is why I believe it's simpler to keep segmentation as
> part of buffers that (for now) only happens to be used by a particular type
> of buffer, namely packets.
>
> Bill
>
> On Fri, Oct 17, 2014 at 8:05 AM, Ola Liljedahl <ola.liljedahl@linaro.org>
> wrote:
>>
>> Personally I don't see any need for segmentation support in buffers. I am
>> just trying to shoot down what I think is flawed reasoning.
>>
>> -- Ola#1
>>
>> On 17 October 2014 15:03, Ola Liljedahl <ola.liljedahl@linaro.org> wrote:
>>>
>>> But segmentation is already needed in a current and known subclass (i.e.
>>> packets). We are not talking about some other feature which we don't know if
>>> it will be needed. So this is not a case of "just in case".
>>>
>>> -- Ola#1
>>>
>>>
>>> On 17 October 2014 14:45, Ola Dahl <dahl.ola@gmail.com> wrote:
>>>>
>>>> Hi,
>>>>
>>>> I do not think it is wise to put features in the base class "just in
>>>> case" they would be needed in some future (not yet known) subclass.
>>>>
>>>> So if the concept of segmentation is relevant for packets but not for
>>>> timers then I think it should be implemented as a feature of packets.
>>>>
>>>> Best regards,
>>>>
>>>> Ola D
>>>>
>>>> On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer
>>>> <bill.fischofer@linaro.org> wrote:
>>>>>
>>>>> I agree that packets are the buffer type that most likely uses
>>>>> segments, however there are many advantages to putting this support in the
>>>>> base class rather than the subclass independent of the number of buffer
>>>>> subclasses that will use this support today.
>>>>>
>>>>> It's simpler
>>>>> It's more extensible
>>>>> It results in cleaner and more efficient application code
>>>>>
>>>>> Allow me to expand on these points.  First simplicity.  Call the work
>>>>> required to support segmentation in the implementation X.  That X is going
>>>>> to be pretty much constant no matter where it is done.  But if the
>>>>> implementation has a choice between doing X at a low level vs. doing it at a
>>>>> high level then it's simpler for the implementation to do it once and be
>>>>> done with it.  If the implementation does it at a higher level then it is
>>>>> either constrained to map that higher-level implementation to be built on a
>>>>> set of lower-level functions that may or may not be appropriate or else it
>>>>> needs to do a completely parallel implementation that is optimal but highly
>>>>> duplicative.
>>>>>
>>>>> Extensibility should be clear.  If at some future point we decide
>>>>> segmentation would be useful for some new buffer type (e.g., IPC) then
>>>>> that's trivial to do if the base class supports it and awkward if it's only
>>>>> part of packets.
>>>>>
>>>>> From an application standpoint, it's cleaner because the packet APIs
>>>>> are just wrappers around their corresponding buffer APIs and can be mapped
>>>>> directly.  Otherwise we have a set of APIs that don't map and are not easily
>>>>> translatable.
>>>>>
>>>>> With regard to efficient segment access, that's what the
>>>>> odp_packet_addr() routine provides--one-step fast-path addressability to the
>>>>> first segment of a packet.  An odp_packet_t is an abstract opaque type.  It
>>>>> is not, and cannot be treated as an address by the application.
>>>>>
>>>>> Does that make sense?
>>>>>
>>>>> Bill
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN - FI/Espoo)
>>>>> <petri.savolainen@nsn.com> wrote:
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>>
>>>>>>
>>>>>> 1. The only segmentation use case is for segmented packet, not for
>>>>>> segmented buffers.
>>>>>>
>>>>>>
>>>>>>
>>>>>> 2. Common case for packets is that everything application needs is in
>>>>>> the first segment. Odp_packet_t could refer always into that “first
>>>>>> segment”, so that application (in the common case) would not need to use
>>>>>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.
>>>>>>
>>>>>>
>>>>>>
>>>>>> When buffer level features are minimized, the need for
>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All packet
>>>>>> manipulation should happen through odp_packet_xxx(pkt, …) calls.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> -Petri
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> From: ext Bill Fischofer [mailto:bill.fischofer@linaro.org]
>>>>>> Sent: Friday, October 17, 2014 1:17 PM
>>>>>> To: Savolainen, Petri (NSN - FI/Espoo)
>>>>>> Cc: ext Jacob, Jerin; lng-odp@lists.linaro.org
>>>>>>
>>>>>>
>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>>>
>>>>>>
>>>>>>
>>>>>> I'm not sure how to understand these two statements:
>>>>>>
>>>>>>
>>>>>>
>>>>>> 1. There's no use case for segmented buffers
>>>>>>
>>>>>> 2. We should optimize for the common case (with segments)
>>>>>>
>>>>>>
>>>>>>
>>>>>> These seem contradictory.
>>>>>>
>>>>>>
>>>>>>
>>>>>> The use case for segmented buffers is that some platforms have a
>>>>>> HW-defined and managed segmented buffer model. If we insist that the
>>>>>> application be able to specify and control packet segment sizes we are
>>>>>> making the decision to exclude such platforms from supporting ODP.  The
>>>>>> optimization suggested is precisely what is being proposed here.  By default
>>>>>> packets are assumed to be contained in implementation-managed segmented
>>>>>> buffers and the first segment will be large enough to contain all packet
>>>>>> headers for non-pathological cases.  The case where the application wishes
>>>>>> to traverse the entire packet in SW is expected to be rare because in the
>>>>>> data plane you simply do not have the cycles to do this at line rate for all
>>>>>> packets.
>>>>>>
>>>>>>
>>>>>>
>>>>>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs, this is
>>>>>> simply syntax to avoid the constant need for explicit conversion functions
>>>>>> since unlike C++, C does not support generic functions.  So you cannot pass
>>>>>> an odp_packet_t to a function that expects an odp_buffer_t argument without
>>>>>> a conversion call.  Do we really want to force applications to constantly be
>>>>>> writing code like:
>>>>>>
>>>>>>
>>>>>>
>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)
>>>>>>
>>>>>>
>>>>>>
>>>>>> rather than
>>>>>>
>>>>>>
>>>>>>
>>>>>> odp_packet_xxx(pkt,...)
>>>>>>
>>>>>>
>>>>>>
>>>>>> Not only is this awkward, it is also inefficient.  By having the
>>>>>> explicit odp_packet_xxx() calls, the implementation is free to optimize
>>>>>> these references in whatever manner is appropriate to that implementation.
>>>>>> For some this may be a simple preprocessor-type expansion while for others
>>>>>> there may be more sophisticated handling.  But the application should
>>>>>> neither know nor care about how the implementation chooses to do this.
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN - FI/Espoo)
>>>>>> <petri.savolainen@nsn.com> wrote:
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>>
>>>>>>
>>>>>> This is also my opinion. There’s no use case for segmented buffers in
>>>>>> v1.0 - so let’s keep it simple and define that buffers (and thus buffer
>>>>>> pools) are always unsegmented. Segmentation comes into play only with
>>>>>> packets (and only with those packets that cannot fit into a single buffer).
>>>>>> For example, if implementation has max buffer size 256, any packets larger
>>>>>> than that are segmented and segments are handled with packet_seg_xxx calls.
>>>>>>
>>>>>>
>>>>>>
>>>>>> Also, I’d propose that we optimize for the common case (with segments)
>>>>>> - so that the odp_packet_t handle would refer always to the head of packet
>>>>>> segment. If the first segment (data/data_len pointed by the odp_packet_t)
>>>>>> carries all data application is interested in (=protocol headers), the
>>>>>> application would not have to use the segment API at all. Most applications
>>>>>> would not see any difference between small/large or segmented/unsegmented
>>>>>> packets as long as all headers fit into the first segment.
>>>>>>
>>>>>>
>>>>>>
>>>>>> -Petri
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> From: lng-odp-bounces@lists.linaro.org
>>>>>> [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of ext Jacob, Jerin
>>>>>> Sent: Friday, October 17, 2014 9:34 AM
>>>>>> To: Bill Fischofer
>>>>>> Cc: lng-odp@lists.linaro.org
>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>>>
>>>>>>
>>>>>>
>>>>>> The need for segment API infrastructure is very clear.The question is,
>>>>>> Do we need separate APIs for
>>>>>>
>>>>>> segment management at odp_buffer_segment* AND odp_packet_segment*
>>>>>> levels ?
>>>>>>
>>>>>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always
>>>>>> unsegmented and if there is a
>>>>>>
>>>>>> API for odp_packet_segement* then there will be not be any consumer
>>>>>> for odp_buffer_segment* API for 1.0
>>>>>>
>>>>>>
>>>>>>
>>>>>> ________________________________
>>>>>>
>>>>>> From: Bill Fischofer <bill.fischofer@linaro.org>
>>>>>> Sent: Thursday, October 16, 2014 9:08 PM
>>>>>> To: Jacob, Jerin
>>>>>> Cc: Ola Liljedahl; Balasubramanian Manoharan; lng-odp@lists.linaro.org
>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>>>
>>>>>>
>>>>>>
>>>>>> From the buffer design doc (p. 8-9):
>>>>>>
>>>>>> Buffer Pool Options
>>>>>>
>>>>>> The odp_buffer_opts_e enum is used to specify additional options
>>>>>> relating to the buffer pool.  Buffer pool options defined are:
>>>>>>
>>>>>>
>>>>>>
>>>>>> ·     ODP_BUFFER_OPTS_NONE
>>>>>>
>>>>>> ·     ODP_BUFFER_OPTS_UNSEGMENTED
>>>>>>
>>>>>>
>>>>>>
>>>>>> These options are additive so an application can simply specify a
>>>>>> buf_opts by ORing together the options needed.  Note that buffer pool
>>>>>> options are themselves OPTIONAL and a given implementation MAY fail the
>>>>>> buffer pool creation request with an appropriate errno if the requested
>>>>>> option is not supported by the underlying ODP implementation, with the
>>>>>> exception that UNSEGMENTED pools MUST be supported for non-packet types and
>>>>>> for packet types as long as the requested size is less than the
>>>>>> implementation-defined native packet segment size.
>>>>>>
>>>>>>
>>>>>>
>>>>>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options with
>>>>>> no additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies that the
>>>>>> buffer pool should be unsegmented.
>>>>>>
>>>>>>
>>>>>>
>>>>>> So unsegmented buffer pool support is available.  As far as RAW
>>>>>> buffers go, again from the doc (p. 14):
>>>>>>
>>>>>> ODP_BUFFER_TYPE_RAW
>>>>>>
>>>>>> This is the “basic” buffer type which simply consists of a single
>>>>>> fixed-sized block of contiguous memory.  Buffers of this type do not support
>>>>>> user meta data and the only built-in meta data supported for this type of
>>>>>> buffer are those that are statically computable, such as pool and size. This
>>>>>> type of buffer is entirely under application control and most of the buffer
>>>>>> APIs defined in this document are not available.  APIs for this type of
>>>>>> buffer are described in this document.
>>>>>>
>>>>>>
>>>>>>
>>>>>> So RAW buffers are always unsegmented.  The intent is that Packets are
>>>>>> by default segmented but can be unsegmented while the other buffer types are
>>>>>> by default unsegmented but (with the exception of RAW buffers) can be made
>>>>>> segmented.  This is because all buffers start out as a single segment and
>>>>>> hence are unsegmented until they are expanded to overflow that single
>>>>>> segment.
>>>>>>
>>>>>>
>>>>>>
>>>>>> Hope that clarifies things.  Again, this is all very straightforward
>>>>>> and only comes into play when actually needed.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin
>>>>>> <Jerin.Jacob@caviumnetworks.com> wrote:
>>>>>>
>>>>>> If there is no valid use case for supporting segmentation for raw
>>>>>> buffers then lets drop it. At least it will reduce the effort of
>>>>>>
>>>>>> implementing and testing/verification buffer APIs on  different
>>>>>> platforms.
>>>>>>
>>>>>>
>>>>>>
>>>>>> ________________________________
>>>>>>
>>>>>> From: lng-odp-bounces@lists.linaro.org
>>>>>> <lng-odp-bounces@lists.linaro.org> on behalf of Ola Liljedahl
>>>>>> <ola.liljedahl@linaro.org>
>>>>>> Sent: Wednesday, October 8, 2014 1:37 PM
>>>>>> To: Balasubramanian Manoharan
>>>>>> Cc: lng-odp@lists.linaro.org
>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>>>
>>>>>>
>>>>>>
>>>>>> As I wrote in my comment to the architecture discussion yesterday, I
>>>>>> am against segmentation for buffers. Or at least there must be the
>>>>>> possibility to create a buffer pool with guaranteed non-segmented buffers.
>>>>>> Segmented packets are OK but not all usages for buffers relate to packets. A
>>>>>> lot of internal usages (timeouts, SW messages, internal data structures)
>>>>>> will not be able to handle segmented buffers so you must be able to force
>>>>>> the creation of buffer pools with non-segmented buffers.
>>>>>>
>>>>>>
>>>>>>
>>>>>> -- Ola
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> On 8 October 2014 09:50, Balasubramanian Manoharan
>>>>>> <bala.manoharan@linaro.org> wrote:
>>>>>>
>>>>>> This patch contains ODP Buffer Management missing APIs
>>>>>> The intent of this patch is to port the missing APIs from Buffer
>>>>>> Management design document into Linux-generic repo.
>>>>>> The dummy functions will be replaced during linux-generic
>>>>>> implementation.
>>>>>>
>>>>>> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>
>>>>>> ---
>>>>>>  platform/linux-generic/include/api/odp_buffer.h    | 203
>>>>>> ++++++++++++++++++++-
>>>>>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
>>>>>>  platform/linux-generic/odp_buffer.c                | 120 ++++++++++++
>>>>>>  platform/linux-generic/odp_buffer_pool.c           |   7 +
>>>>>>  4 files changed, 351 insertions(+), 9 deletions(-)
>>>>>>
>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer.h
>>>>>> b/platform/linux-generic/include/api/odp_buffer.h
>>>>>> index d8577fd..aeb75ed 100644
>>>>>> --- a/platform/linux-generic/include/api/odp_buffer.h
>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer.h
>>>>>> @@ -28,8 +28,34 @@ extern "C" {
>>>>>>   */
>>>>>>  typedef uint32_t odp_buffer_t;
>>>>>>
>>>>>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>>>>>> +/**
>>>>>> +* ODP buffer segment
>>>>>> +*/
>>>>>> +typedef uint32_t odp_buffer_segment_t;
>>>>>>
>>>>>> +/**
>>>>>> +* ODP buffer type
>>>>>> +*/
>>>>>> +typedef enum odp_buffer_type {
>>>>>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */
>>>>>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold any
>>>>>> other
>>>>>> +                                       buffer type */
>>>>>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
>>>>>> +                                       no additional metadata */
>>>>>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
>>>>>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
>>>>>> +} odp_buffer_type_e;
>>>>>> +
>>>>>> +/**
>>>>>> +* ODP buffer options
>>>>>> +*/
>>>>>> +typedef enum odp_buffer_opts {
>>>>>> +       ODP_BUFFER_OPTS_NONE,
>>>>>> +       ODP_BUFFER_OPTS_UNSEGMENTED
>>>>>> +} odp_buffer_opts_e;
>>>>>> +
>>>>>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>>>>>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
>>>>>>
>>>>>>  /**
>>>>>>   * Buffer start address
>>>>>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
>>>>>>   */
>>>>>>  int odp_buffer_type(odp_buffer_t buf);
>>>>>>
>>>>>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
>>>>>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any
>>>>>> other
>>>>>> -                                         buffer type */
>>>>>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional
>>>>>> metadata */
>>>>>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
>>>>>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
>>>>>> -
>>>>>> -
>>>>>>  /**
>>>>>>   * Tests if buffer is valid
>>>>>>   *
>>>>>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
>>>>>>  int odp_buffer_is_valid(odp_buffer_t buf);
>>>>>>
>>>>>>  /**
>>>>>> + * Tests if buffer is segmented
>>>>>> + *
>>>>>> + * @param[in]  buf     Buffer handle
>>>>>> + *
>>>>>> + * @return             1 if buffer has more than one segment,
>>>>>> + *                     otherwise 0
>>>>>> + */
>>>>>> +
>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf);
>>>>>> +
>>>>>> +/**
>>>>>> + * Get address and size of user meta data associated with a buffer
>>>>>> + *
>>>>>> + * @param[in]  buf             Buffer handle
>>>>>> + * @param[out] udata_size      Number of bytes of user meta data
>>>>>> available
>>>>>> + *                             at the returned address
>>>>>> + * @return                     Address of the user meta data for this
>>>>>> buffer
>>>>>> + *                             or NULL if the buffer has no user meta
>>>>>> data.
>>>>>> + */
>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
>>>>>> +
>>>>>> +/**
>>>>>> + * Get address of user meta data associated with a buffer
>>>>>> + *
>>>>>> + * @param[in]  buf     Buffer handle
>>>>>> + *
>>>>>> + * @return             Address of the user meta data for this buffer
>>>>>> + *                     or NULL if the buffer has no user meta data.
>>>>>> + */
>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf);
>>>>>> +
>>>>>> +/**
>>>>>> + * Get count of number of segments in a buffer
>>>>>> + *
>>>>>> + * @param[in]  buf     Buffer handle
>>>>>> + *
>>>>>> + * @return             Count of the number of segments in buf
>>>>>> + */
>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf);
>>>>>> +
>>>>>> +/**
>>>>>> + * Get the segment identifier for a buffer segment by index
>>>>>> + *
>>>>>> + * @param[in]  buf     Buffer handle
>>>>>> + * @param[in]  ndx     Segment index of segment of interest
>>>>>> + *
>>>>>> + * @return             Segment identifier or ODP_SEGMENT_INVALID if
>>>>>> the
>>>>>> + *                     supplied ndx is out of range.
>>>>>> + */
>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>>>>>> size_t ndx);
>>>>>> +
>>>>>> +/**
>>>>>> + * Get the next segment identifier for a buffer segment
>>>>>> + *
>>>>>> + * @param[in]  buf     Buffer handle
>>>>>> + * @param[in]  seg     Segment identifier of the previous segment
>>>>>> + *
>>>>>> + * @return             Segment identifier of the next segment,
>>>>>> +                       or ODP_SEGMENT_INVALID.
>>>>>> + */
>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>>>>>> +                                            odp_buffer_segment_t
>>>>>> seg);
>>>>>> +/**
>>>>>> + * Get start address for a specified buffer segment
>>>>>> + *
>>>>>> + * @param[in]  buf     Buffer handle
>>>>>> + * @param[in]  seg     Segment identifier of the buffer to be
>>>>>> addressed
>>>>>> + * @param[out] seglen  Returned number of bytes in this buffer
>>>>>> + *                     segment available at returned address
>>>>>> + *
>>>>>> + * @return             Segment start address or NULL
>>>>>> + */
>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t
>>>>>> seg,
>>>>>> +size_t *seglen);
>>>>>> +
>>>>>> +/**
>>>>>> + *Unmap a buffer segment
>>>>>> + *
>>>>>> + * @param[in]  seg     Buffer segment handle
>>>>>> + */
>>>>>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
>>>>>> +
>>>>>> +/**
>>>>>> +* Get start address for a specified buffer offset
>>>>>> +*
>>>>>> +* @param[in]   buf     Buffer handle
>>>>>> +* @param[in]   offset  Byte offset within the buffer to be addressed
>>>>>> +* @param[out]  seglen  Returned number of bytes in this buffer
>>>>>> +*                      segment available at returned address
>>>>>> +*
>>>>>> +* @return              Offset start address or NULL
>>>>>> +*/
>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>>>>>> +size_t *seglen);
>>>>>> +
>>>>>> +/**
>>>>>> + * Unmap a buffer segment by offset
>>>>>> + *
>>>>>> + * @param[in]  buf     Buffer handle
>>>>>> + * @param[in]  offset  Buffer offset
>>>>>> + */
>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
>>>>>> +
>>>>>> +/**
>>>>>>   * Print buffer metadata to STDOUT
>>>>>>   *
>>>>>>   * @param buf      Buffer handle
>>>>>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
>>>>>>   */
>>>>>>  void odp_buffer_print(odp_buffer_t buf);
>>>>>>
>>>>>> +/**
>>>>>> + * Split a buffer into two buffers at a specified split point
>>>>>> + *
>>>>>> + * @param[in]  buf     Handle of buffer to split
>>>>>> + * @param[in]  offset  Byte offset within buf to split buffer
>>>>>> + *
>>>>>> + * @return             Buffer handle of the created split buffer
>>>>>> + */
>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
>>>>>> +
>>>>>> +/**
>>>>>> + * Join two buffers into a single buffer
>>>>>> + *
>>>>>> + * @param[in]  buf1    Buffer handle of first buffer to join
>>>>>> + * @param[in]  buf2    Buffer handle of second buffer to join
>>>>>> + *
>>>>>> + * @return             Buffer handle of the joined buffer
>>>>>> + */
>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);
>>>>>> +
>>>>>> +/**
>>>>>> + * Trim a buffer at a specified trim point
>>>>>> + *
>>>>>> + * @param[in]  buf     Buffer handle of buffer to trim
>>>>>> + * @param[in]  offset  byte offset within buf to trim
>>>>>> + *
>>>>>> + * @return             Handle of the trimmed buffer or
>>>>>> + *                     ODP_BUFFER_INVALID if the operation was not
>>>>>> performed
>>>>>> + */
>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
>>>>>> +/**
>>>>>> + * Extend a buffer for a specified number of bytes
>>>>>> + *
>>>>>> + * @param[in]  buf     Buffer handle of buffer to expand
>>>>>> + * @param[in]  ext     size, in bytes, of the extent to add to the
>>>>>> + *                     existing buffer.
>>>>>> + *
>>>>>> + * @return             Handle of the extended buffer or
>>>>>> ODP_BUFFER_INVALID
>>>>>> + *                     if the operation was not performed
>>>>>> + */
>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
>>>>>> +
>>>>>> +/**
>>>>>> + * Clone a buffer, returning an exact copy of it
>>>>>> + *
>>>>>> + * @param[in]  buf     Buffer handle of buffer to duplicate
>>>>>> + *
>>>>>> + * @return             Handle of the duplicated buffer or
>>>>>> ODP_BUFFER_INVALID
>>>>>> + *                     if the operation was not performed
>>>>>> + */
>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
>>>>>> +
>>>>>> +/**
>>>>>> + * Copy a buffer, returning an exact copy of it
>>>>>> + *
>>>>>> + * @param[in]  buf     Buffer handle of buffer to copy
>>>>>> + *
>>>>>> + * @return             Handle of the copied buffer or
>>>>>> ODP_BUFFER_INVALID
>>>>>> + *                     if the operation was not performed
>>>>>> + */
>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
>>>>>> +
>>>>>> +
>>>>>>
>>>>>>  #ifdef __cplusplus
>>>>>>  }
>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
>>>>>> b/platform/linux-generic/include/api/odp_buffer_pool.h
>>>>>> index fe88898..f85d96c 100644
>>>>>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
>>>>>> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const char
>>>>>> *name,
>>>>>>
>>>>>>
>>>>>>  /**
>>>>>> + * Get the next buffer pool from its predecessor
>>>>>> + *
>>>>>> + * @param[in]  pool            Buffer pool handle
>>>>>> + * @param[out] name            Name of the pool
>>>>>> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1
>>>>>> chars)
>>>>>> + * @param[out] udata_size      Size of user meta data used by this
>>>>>> pool.
>>>>>> + * @param[out] buf_num         Number of buffers contained in this
>>>>>> pool
>>>>>> + * @param[out] buf_size        Default size of application data in
>>>>>> each buffer
>>>>>> + * @param[out] buf_type        Buffer type of the pool
>>>>>> + * @param[out] buf_opts        Buffer options for this pool
>>>>>> + * @param[out] predef          Predefined (1) or Created (0).
>>>>>> + *
>>>>>> + * @return                     Buffer pool handle
>>>>>> + */
>>>>>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
>>>>>> +                                      char *name, size_t *udata_size,
>>>>>> +                                      size_t *buf_num, size_t
>>>>>> *buf_size,
>>>>>> +                                      enum odp_buffer_type *buf_type,
>>>>>> +                                      enum odp_buffer_opts *buf_opts,
>>>>>> +                                      uint32_t *predef);
>>>>>> +/**
>>>>>>   * Find a buffer pool by name
>>>>>>   *
>>>>>>   * @param name      Name of the pool
>>>>>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t
>>>>>> pool);
>>>>>>   */
>>>>>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
>>>>>>
>>>>>> +/**
>>>>>> +* Allocate a buffer from a buffer pool
>>>>>> +*
>>>>>> +* @param[in]   pool    Pool handle
>>>>>> +* @param[in]   size    Size of object to store in buffer
>>>>>> +*
>>>>>> +* @return              Buffer handle or ODP_BUFFER_INVALID
>>>>>> +*/
>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t
>>>>>> size);
>>>>>>
>>>>>>  /**
>>>>>>   * Buffer free
>>>>>> diff --git a/platform/linux-generic/odp_buffer.c
>>>>>> b/platform/linux-generic/odp_buffer.c
>>>>>> index e54e0e7..7f4b4f0 100644
>>>>>> --- a/platform/linux-generic/odp_buffer.c
>>>>>> +++ b/platform/linux-generic/odp_buffer.c
>>>>>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
>>>>>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
>>>>>>  }
>>>>>>
>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf)
>>>>>> +{
>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>>>>>> +
>>>>>> +       if (buf_hdr->scatter.num_bufs == 0)
>>>>>> +               return 0;
>>>>>> +       else
>>>>>> +               return 1;
>>>>>> +}
>>>>>> +
>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf)
>>>>>> +{
>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>>>>>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
>>>>>> +}
>>>>>>
>>>>>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
>>>>>>  {
>>>>>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
>>>>>>         printf("\n%s\n", str);
>>>>>>  }
>>>>>>
>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
>>>>>> +{
>>>>>> +       (void)buf;
>>>>>> +       (void)udata_size;
>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +
>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf)
>>>>>> +{
>>>>>> +       (void)buf;
>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +
>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>>>>>> +                                                size_t ndx)
>>>>>> +{
>>>>>> +       (void)buf;
>>>>>> +       (void)ndx;
>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +
>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>>>>>> +                                            odp_buffer_segment_t seg)
>>>>>> +{
>>>>>> +       (void)buf;
>>>>>> +       (void)seg;
>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +
>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t
>>>>>> seg,
>>>>>> +                            size_t *seglen)
>>>>>> +{
>>>>>> +       (void)buf;
>>>>>> +       (void)seg;
>>>>>> +       (void)seglen;
>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>>>>>> +size_t *seglen)
>>>>>> +{
>>>>>> +       (void)buf;
>>>>>> +       (void)offset;
>>>>>> +       (void)seglen;
>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
>>>>>> +{
>>>>>> +       (void)buf;
>>>>>> +       (void)offset;
>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>> +       return;
>>>>>> +}
>>>>>> +
>>>>>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t
>>>>>> buf_src)
>>>>>>  {
>>>>>>         (void)buf_dst;
>>>>>>         (void)buf_src;
>>>>>>  }
>>>>>> +
>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
>>>>>> +{
>>>>>> +       (void)buf;
>>>>>> +       (void)offset;
>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +
>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
>>>>>> +{
>>>>>> +       (void)buf1;
>>>>>> +       (void)buf2;
>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +
>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
>>>>>> +{
>>>>>> +       (void)buf;
>>>>>> +       (void)offset;
>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
>>>>>> +{
>>>>>> +       (void)buf;
>>>>>> +       (void)ext;
>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +
>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
>>>>>> +{
>>>>>> +       (void)buf;
>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +
>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
>>>>>> +{
>>>>>> +       (void)buf;
>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +
>>>>>> diff --git a/platform/linux-generic/odp_buffer_pool.c
>>>>>> b/platform/linux-generic/odp_buffer_pool.c
>>>>>> index a48d7d6..bff4db5 100644
>>>>>> --- a/platform/linux-generic/odp_buffer_pool.c
>>>>>> +++ b/platform/linux-generic/odp_buffer_pool.c
>>>>>> @@ -471,6 +471,13 @@ odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t
>>>>>> pool_hdl)
>>>>>>         return handle.u32;
>>>>>>  }
>>>>>>
>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t
>>>>>> size)
>>>>>> +{
>>>>>> +       (void)pool;
>>>>>> +       (void) size;
>>>>>> +       ODP_ERR("%s function is yet to be implemented", __func__);
>>>>>> +       return 0;
>>>>>> +}
>>>>>>
>>>>>>  void odp_buffer_free(odp_buffer_t buf)
>>>>>>  {
>>>>>> --
>>>>>> 2.0.1.472.g6f92e5f
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> lng-odp mailing list
>>>>>> lng-odp@lists.linaro.org
>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> lng-odp mailing list
>>>>>> lng-odp@lists.linaro.org
>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> lng-odp mailing list
>>>>> lng-odp@lists.linaro.org
>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> lng-odp mailing list
>>>> lng-odp@lists.linaro.org
>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>
>>>
>>
>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
Ciprian Barbu Oct. 22, 2014, 11:59 a.m. UTC | #12
On Wed, Oct 22, 2014 at 2:47 PM, Ciprian Barbu <ciprian.barbu@linaro.org> wrote:
> This thread has been cold for 5 days, so the assumption is that we can
> go forward with the design right now. This patch series proposed by
> Bala updates some part of the API to the final form of the Buffer
> Design Document, we should have it merged if there are no more
> objections. For that more people with the right expertise should have
> a look at it and get the thread back on track.
>
> I for example have observed the following issue. All the examples
> create buffer pools over shared memory, which doesn't make sense for
> some platforms, linux-dpdk for example, which ignores the base_addr
> argument altogether. I think we need more clarity on this subject, for
> sure the creation of buffer pools will differ from platform to
> platform, which migrates to the application responsibility.
>
> I think we should have a helper function to easily create buffer pools
> without worrying too much about the difference in buffer management
> between platforms, so that one can write a simple portable application
> with no sweat. For the hardcore programmers the API still gives fine
> control to buffer management that depending on the platform could
> involve additional prerequisites, like creating a shared memory
> segment to hold the buffer pool.

Ok, so I had another look at the Buffer Management final design. I now
see that the option of creating buffer pools from regions has been
removed, so in this case things will be simpler for the applications.
In other words we should really start working on the full
implementation of the API because from there the problem I just stated
above (having to create shared memory segments) will disappear.

>
> On Fri, Oct 17, 2014 at 4:33 PM, Bill Fischofer
> <bill.fischofer@linaro.org> wrote:
>> Let's consider the implications of removing segmentation support from
>> buffers and only having that concept be part of packets.
>>
>> The first question that arises is what is the relationship between the
>> abstract types odp_packet_t and odp_buffer_t? This is important because
>> currently we say that packets are allocated from ODP buffer pools, not from
>> packet pools.  Do we need a separate odp_packet_pool_t that is used for
>> packets?
>>
>> Today, when I allocate a packet I'm allocating a single object that happens
>> to be a single buffer object of type ODP_BUFFER_TYPE_PACKET.  But that only
>> works if the two objects have compatible semantics (including segmentation).
>> If the semantics are not compatible, then an odp_packet_t may in fact be
>> composed of multiple odp_buffer_t's because the packet may consist of
>> multiple segments and buffers no longer recognize the concept of segments so
>> a single buffer can only be a single segment.
>>
>> So now an odp_packet_segment_t may be an odp_buffer_t but an odp_packet_t in
>> fact is some meta-object that is constructed (by whom?) from multiple
>> odp_packet_segment_ts that are themselves odp_buffer_ts.  So
>> odp_packet_to_buffer() no longer makes sense since there is no longer a
>> one-to-one correspondence between packets and buffers.  We could have an
>> odp_packet_segment_to_buffer() routine instead.
>>
>> Next question: What about meta data?  If an odp_packet_t is a type of an
>> odp_buffer_t then this is very straightforward since all buffer meta data is
>> reusable as packet meta data and the packet type can just add its own
>> specific meta data to this set.  But if an odp_packet_t is now a separate
>> object then where does the storage for its meta data come from? If we try to
>> map it into an odp_buffer_t that doesn't work since an odp_packet_t may
>> consist of multiple underlying odp_buffer_ts, one for each
>> odp_packet_segment_t.  Is the packet meta data duplicated in each segment?
>> Is the first segment of a packet special (odp_packet_first_segment_t)?  And
>> what about user meta data, since this is of potentially variable size?
>>
>> I submit that there are a lot of implications to this that need to be fully
>> thought through, which is why I believe it's simpler to keep segmentation as
>> part of buffers that (for now) only happens to be used by a particular type
>> of buffer, namely packets.
>>
>> Bill
>>
>> On Fri, Oct 17, 2014 at 8:05 AM, Ola Liljedahl <ola.liljedahl@linaro.org>
>> wrote:
>>>
>>> Personally I don't see any need for segmentation support in buffers. I am
>>> just trying to shoot down what I think is flawed reasoning.
>>>
>>> -- Ola#1
>>>
>>> On 17 October 2014 15:03, Ola Liljedahl <ola.liljedahl@linaro.org> wrote:
>>>>
>>>> But segmentation is already needed in a current and known subclass (i.e.
>>>> packets). We are not talking about some other feature which we don't know if
>>>> it will be needed. So this is not a case of "just in case".
>>>>
>>>> -- Ola#1
>>>>
>>>>
>>>> On 17 October 2014 14:45, Ola Dahl <dahl.ola@gmail.com> wrote:
>>>>>
>>>>> Hi,
>>>>>
>>>>> I do not think it is wise to put features in the base class "just in
>>>>> case" they would be needed in some future (not yet known) subclass.
>>>>>
>>>>> So if the concept of segmentation is relevant for packets but not for
>>>>> timers then I think it should be implemented as a feature of packets.
>>>>>
>>>>> Best regards,
>>>>>
>>>>> Ola D
>>>>>
>>>>> On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer
>>>>> <bill.fischofer@linaro.org> wrote:
>>>>>>
>>>>>> I agree that packets are the buffer type that most likely uses
>>>>>> segments, however there are many advantages to putting this support in the
>>>>>> base class rather than the subclass independent of the number of buffer
>>>>>> subclasses that will use this support today.
>>>>>>
>>>>>> It's simpler
>>>>>> It's more extensible
>>>>>> It results in cleaner and more efficient application code
>>>>>>
>>>>>> Allow me to expand on these points.  First simplicity.  Call the work
>>>>>> required to support segmentation in the implementation X.  That X is going
>>>>>> to be pretty much constant no matter where it is done.  But if the
>>>>>> implementation has a choice between doing X at a low level vs. doing it at a
>>>>>> high level then it's simpler for the implementation to do it once and be
>>>>>> done with it.  If the implementation does it at a higher level then it is
>>>>>> either constrained to map that higher-level implementation to be built on a
>>>>>> set of lower-level functions that may or may not be appropriate or else it
>>>>>> needs to do a completely parallel implementation that is optimal but highly
>>>>>> duplicative.
>>>>>>
>>>>>> Extensibility should be clear.  If at some future point we decide
>>>>>> segmentation would be useful for some new buffer type (e.g., IPC) then
>>>>>> that's trivial to do if the base class supports it and awkward if it's only
>>>>>> part of packets.
>>>>>>
>>>>>> From an application standpoint, it's cleaner because the packet APIs
>>>>>> are just wrappers around their corresponding buffer APIs and can be mapped
>>>>>> directly.  Otherwise we have a set of APIs that don't map and are not easily
>>>>>> translatable.
>>>>>>
>>>>>> With regard to efficient segment access, that's what the
>>>>>> odp_packet_addr() routine provides--one-step fast-path addressability to the
>>>>>> first segment of a packet.  An odp_packet_t is an abstract opaque type.  It
>>>>>> is not, and cannot be treated as an address by the application.
>>>>>>
>>>>>> Does that make sense?
>>>>>>
>>>>>> Bill
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN - FI/Espoo)
>>>>>> <petri.savolainen@nsn.com> wrote:
>>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> 1. The only segmentation use case is for segmented packet, not for
>>>>>>> segmented buffers.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> 2. Common case for packets is that everything application needs is in
>>>>>>> the first segment. Odp_packet_t could refer always into that “first
>>>>>>> segment”, so that application (in the common case) would not need to use
>>>>>>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> When buffer level features are minimized, the need for
>>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All packet
>>>>>>> manipulation should happen through odp_packet_xxx(pkt, …) calls.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> -Petri
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> From: ext Bill Fischofer [mailto:bill.fischofer@linaro.org]
>>>>>>> Sent: Friday, October 17, 2014 1:17 PM
>>>>>>> To: Savolainen, Petri (NSN - FI/Espoo)
>>>>>>> Cc: ext Jacob, Jerin; lng-odp@lists.linaro.org
>>>>>>>
>>>>>>>
>>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> I'm not sure how to understand these two statements:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> 1. There's no use case for segmented buffers
>>>>>>>
>>>>>>> 2. We should optimize for the common case (with segments)
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> These seem contradictory.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> The use case for segmented buffers is that some platforms have a
>>>>>>> HW-defined and managed segmented buffer model. If we insist that the
>>>>>>> application be able to specify and control packet segment sizes we are
>>>>>>> making the decision to exclude such platforms from supporting ODP.  The
>>>>>>> optimization suggested is precisely what is being proposed here.  By default
>>>>>>> packets are assumed to be contained in implementation-managed segmented
>>>>>>> buffers and the first segment will be large enough to contain all packet
>>>>>>> headers for non-pathological cases.  The case where the application wishes
>>>>>>> to traverse the entire packet in SW is expected to be rare because in the
>>>>>>> data plane you simply do not have the cycles to do this at line rate for all
>>>>>>> packets.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs, this is
>>>>>>> simply syntax to avoid the constant need for explicit conversion functions
>>>>>>> since unlike C++, C does not support generic functions.  So you cannot pass
>>>>>>> an odp_packet_t to a function that expects an odp_buffer_t argument without
>>>>>>> a conversion call.  Do we really want to force applications to constantly be
>>>>>>> writing code like:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> rather than
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> odp_packet_xxx(pkt,...)
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Not only is this awkward, it is also inefficient.  By having the
>>>>>>> explicit odp_packet_xxx() calls, the implementation is free to optimize
>>>>>>> these references in whatever manner is appropriate to that implementation.
>>>>>>> For some this may be a simple preprocessor-type expansion while for others
>>>>>>> there may be more sophisticated handling.  But the application should
>>>>>>> neither know nor care about how the implementation chooses to do this.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN - FI/Espoo)
>>>>>>> <petri.savolainen@nsn.com> wrote:
>>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> This is also my opinion. There’s no use case for segmented buffers in
>>>>>>> v1.0 - so let’s keep it simple and define that buffers (and thus buffer
>>>>>>> pools) are always unsegmented. Segmentation comes into play only with
>>>>>>> packets (and only with those packets that cannot fit into a single buffer).
>>>>>>> For example, if implementation has max buffer size 256, any packets larger
>>>>>>> than that are segmented and segments are handled with packet_seg_xxx calls.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Also, I’d propose that we optimize for the common case (with segments)
>>>>>>> - so that the odp_packet_t handle would refer always to the head of packet
>>>>>>> segment. If the first segment (data/data_len pointed by the odp_packet_t)
>>>>>>> carries all data application is interested in (=protocol headers), the
>>>>>>> application would not have to use the segment API at all. Most applications
>>>>>>> would not see any difference between small/large or segmented/unsegmented
>>>>>>> packets as long as all headers fit into the first segment.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> -Petri
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> From: lng-odp-bounces@lists.linaro.org
>>>>>>> [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of ext Jacob, Jerin
>>>>>>> Sent: Friday, October 17, 2014 9:34 AM
>>>>>>> To: Bill Fischofer
>>>>>>> Cc: lng-odp@lists.linaro.org
>>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> The need for segment API infrastructure is very clear.The question is,
>>>>>>> Do we need separate APIs for
>>>>>>>
>>>>>>> segment management at odp_buffer_segment* AND odp_packet_segment*
>>>>>>> levels ?
>>>>>>>
>>>>>>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always
>>>>>>> unsegmented and if there is a
>>>>>>>
>>>>>>> API for odp_packet_segement* then there will be not be any consumer
>>>>>>> for odp_buffer_segment* API for 1.0
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> ________________________________
>>>>>>>
>>>>>>> From: Bill Fischofer <bill.fischofer@linaro.org>
>>>>>>> Sent: Thursday, October 16, 2014 9:08 PM
>>>>>>> To: Jacob, Jerin
>>>>>>> Cc: Ola Liljedahl; Balasubramanian Manoharan; lng-odp@lists.linaro.org
>>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> From the buffer design doc (p. 8-9):
>>>>>>>
>>>>>>> Buffer Pool Options
>>>>>>>
>>>>>>> The odp_buffer_opts_e enum is used to specify additional options
>>>>>>> relating to the buffer pool.  Buffer pool options defined are:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> ·     ODP_BUFFER_OPTS_NONE
>>>>>>>
>>>>>>> ·     ODP_BUFFER_OPTS_UNSEGMENTED
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> These options are additive so an application can simply specify a
>>>>>>> buf_opts by ORing together the options needed.  Note that buffer pool
>>>>>>> options are themselves OPTIONAL and a given implementation MAY fail the
>>>>>>> buffer pool creation request with an appropriate errno if the requested
>>>>>>> option is not supported by the underlying ODP implementation, with the
>>>>>>> exception that UNSEGMENTED pools MUST be supported for non-packet types and
>>>>>>> for packet types as long as the requested size is less than the
>>>>>>> implementation-defined native packet segment size.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options with
>>>>>>> no additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies that the
>>>>>>> buffer pool should be unsegmented.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> So unsegmented buffer pool support is available.  As far as RAW
>>>>>>> buffers go, again from the doc (p. 14):
>>>>>>>
>>>>>>> ODP_BUFFER_TYPE_RAW
>>>>>>>
>>>>>>> This is the “basic” buffer type which simply consists of a single
>>>>>>> fixed-sized block of contiguous memory.  Buffers of this type do not support
>>>>>>> user meta data and the only built-in meta data supported for this type of
>>>>>>> buffer are those that are statically computable, such as pool and size. This
>>>>>>> type of buffer is entirely under application control and most of the buffer
>>>>>>> APIs defined in this document are not available.  APIs for this type of
>>>>>>> buffer are described in this document.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> So RAW buffers are always unsegmented.  The intent is that Packets are
>>>>>>> by default segmented but can be unsegmented while the other buffer types are
>>>>>>> by default unsegmented but (with the exception of RAW buffers) can be made
>>>>>>> segmented.  This is because all buffers start out as a single segment and
>>>>>>> hence are unsegmented until they are expanded to overflow that single
>>>>>>> segment.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Hope that clarifies things.  Again, this is all very straightforward
>>>>>>> and only comes into play when actually needed.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin
>>>>>>> <Jerin.Jacob@caviumnetworks.com> wrote:
>>>>>>>
>>>>>>> If there is no valid use case for supporting segmentation for raw
>>>>>>> buffers then lets drop it. At least it will reduce the effort of
>>>>>>>
>>>>>>> implementing and testing/verification buffer APIs on  different
>>>>>>> platforms.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> ________________________________
>>>>>>>
>>>>>>> From: lng-odp-bounces@lists.linaro.org
>>>>>>> <lng-odp-bounces@lists.linaro.org> on behalf of Ola Liljedahl
>>>>>>> <ola.liljedahl@linaro.org>
>>>>>>> Sent: Wednesday, October 8, 2014 1:37 PM
>>>>>>> To: Balasubramanian Manoharan
>>>>>>> Cc: lng-odp@lists.linaro.org
>>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> As I wrote in my comment to the architecture discussion yesterday, I
>>>>>>> am against segmentation for buffers. Or at least there must be the
>>>>>>> possibility to create a buffer pool with guaranteed non-segmented buffers.
>>>>>>> Segmented packets are OK but not all usages for buffers relate to packets. A
>>>>>>> lot of internal usages (timeouts, SW messages, internal data structures)
>>>>>>> will not be able to handle segmented buffers so you must be able to force
>>>>>>> the creation of buffer pools with non-segmented buffers.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> -- Ola
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On 8 October 2014 09:50, Balasubramanian Manoharan
>>>>>>> <bala.manoharan@linaro.org> wrote:
>>>>>>>
>>>>>>> This patch contains ODP Buffer Management missing APIs
>>>>>>> The intent of this patch is to port the missing APIs from Buffer
>>>>>>> Management design document into Linux-generic repo.
>>>>>>> The dummy functions will be replaced during linux-generic
>>>>>>> implementation.
>>>>>>>
>>>>>>> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>
>>>>>>> ---
>>>>>>>  platform/linux-generic/include/api/odp_buffer.h    | 203
>>>>>>> ++++++++++++++++++++-
>>>>>>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
>>>>>>>  platform/linux-generic/odp_buffer.c                | 120 ++++++++++++
>>>>>>>  platform/linux-generic/odp_buffer_pool.c           |   7 +
>>>>>>>  4 files changed, 351 insertions(+), 9 deletions(-)
>>>>>>>
>>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer.h
>>>>>>> b/platform/linux-generic/include/api/odp_buffer.h
>>>>>>> index d8577fd..aeb75ed 100644
>>>>>>> --- a/platform/linux-generic/include/api/odp_buffer.h
>>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer.h
>>>>>>> @@ -28,8 +28,34 @@ extern "C" {
>>>>>>>   */
>>>>>>>  typedef uint32_t odp_buffer_t;
>>>>>>>
>>>>>>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>>>>>>> +/**
>>>>>>> +* ODP buffer segment
>>>>>>> +*/
>>>>>>> +typedef uint32_t odp_buffer_segment_t;
>>>>>>>
>>>>>>> +/**
>>>>>>> +* ODP buffer type
>>>>>>> +*/
>>>>>>> +typedef enum odp_buffer_type {
>>>>>>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */
>>>>>>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold any
>>>>>>> other
>>>>>>> +                                       buffer type */
>>>>>>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
>>>>>>> +                                       no additional metadata */
>>>>>>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
>>>>>>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
>>>>>>> +} odp_buffer_type_e;
>>>>>>> +
>>>>>>> +/**
>>>>>>> +* ODP buffer options
>>>>>>> +*/
>>>>>>> +typedef enum odp_buffer_opts {
>>>>>>> +       ODP_BUFFER_OPTS_NONE,
>>>>>>> +       ODP_BUFFER_OPTS_UNSEGMENTED
>>>>>>> +} odp_buffer_opts_e;
>>>>>>> +
>>>>>>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>>>>>>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
>>>>>>>
>>>>>>>  /**
>>>>>>>   * Buffer start address
>>>>>>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
>>>>>>>   */
>>>>>>>  int odp_buffer_type(odp_buffer_t buf);
>>>>>>>
>>>>>>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
>>>>>>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any
>>>>>>> other
>>>>>>> -                                         buffer type */
>>>>>>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional
>>>>>>> metadata */
>>>>>>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
>>>>>>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
>>>>>>> -
>>>>>>> -
>>>>>>>  /**
>>>>>>>   * Tests if buffer is valid
>>>>>>>   *
>>>>>>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
>>>>>>>  int odp_buffer_is_valid(odp_buffer_t buf);
>>>>>>>
>>>>>>>  /**
>>>>>>> + * Tests if buffer is segmented
>>>>>>> + *
>>>>>>> + * @param[in]  buf     Buffer handle
>>>>>>> + *
>>>>>>> + * @return             1 if buffer has more than one segment,
>>>>>>> + *                     otherwise 0
>>>>>>> + */
>>>>>>> +
>>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * Get address and size of user meta data associated with a buffer
>>>>>>> + *
>>>>>>> + * @param[in]  buf             Buffer handle
>>>>>>> + * @param[out] udata_size      Number of bytes of user meta data
>>>>>>> available
>>>>>>> + *                             at the returned address
>>>>>>> + * @return                     Address of the user meta data for this
>>>>>>> buffer
>>>>>>> + *                             or NULL if the buffer has no user meta
>>>>>>> data.
>>>>>>> + */
>>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * Get address of user meta data associated with a buffer
>>>>>>> + *
>>>>>>> + * @param[in]  buf     Buffer handle
>>>>>>> + *
>>>>>>> + * @return             Address of the user meta data for this buffer
>>>>>>> + *                     or NULL if the buffer has no user meta data.
>>>>>>> + */
>>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * Get count of number of segments in a buffer
>>>>>>> + *
>>>>>>> + * @param[in]  buf     Buffer handle
>>>>>>> + *
>>>>>>> + * @return             Count of the number of segments in buf
>>>>>>> + */
>>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * Get the segment identifier for a buffer segment by index
>>>>>>> + *
>>>>>>> + * @param[in]  buf     Buffer handle
>>>>>>> + * @param[in]  ndx     Segment index of segment of interest
>>>>>>> + *
>>>>>>> + * @return             Segment identifier or ODP_SEGMENT_INVALID if
>>>>>>> the
>>>>>>> + *                     supplied ndx is out of range.
>>>>>>> + */
>>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>>>>>>> size_t ndx);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * Get the next segment identifier for a buffer segment
>>>>>>> + *
>>>>>>> + * @param[in]  buf     Buffer handle
>>>>>>> + * @param[in]  seg     Segment identifier of the previous segment
>>>>>>> + *
>>>>>>> + * @return             Segment identifier of the next segment,
>>>>>>> +                       or ODP_SEGMENT_INVALID.
>>>>>>> + */
>>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>>>>>>> +                                            odp_buffer_segment_t
>>>>>>> seg);
>>>>>>> +/**
>>>>>>> + * Get start address for a specified buffer segment
>>>>>>> + *
>>>>>>> + * @param[in]  buf     Buffer handle
>>>>>>> + * @param[in]  seg     Segment identifier of the buffer to be
>>>>>>> addressed
>>>>>>> + * @param[out] seglen  Returned number of bytes in this buffer
>>>>>>> + *                     segment available at returned address
>>>>>>> + *
>>>>>>> + * @return             Segment start address or NULL
>>>>>>> + */
>>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t
>>>>>>> seg,
>>>>>>> +size_t *seglen);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + *Unmap a buffer segment
>>>>>>> + *
>>>>>>> + * @param[in]  seg     Buffer segment handle
>>>>>>> + */
>>>>>>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
>>>>>>> +
>>>>>>> +/**
>>>>>>> +* Get start address for a specified buffer offset
>>>>>>> +*
>>>>>>> +* @param[in]   buf     Buffer handle
>>>>>>> +* @param[in]   offset  Byte offset within the buffer to be addressed
>>>>>>> +* @param[out]  seglen  Returned number of bytes in this buffer
>>>>>>> +*                      segment available at returned address
>>>>>>> +*
>>>>>>> +* @return              Offset start address or NULL
>>>>>>> +*/
>>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>>>>>>> +size_t *seglen);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * Unmap a buffer segment by offset
>>>>>>> + *
>>>>>>> + * @param[in]  buf     Buffer handle
>>>>>>> + * @param[in]  offset  Buffer offset
>>>>>>> + */
>>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
>>>>>>> +
>>>>>>> +/**
>>>>>>>   * Print buffer metadata to STDOUT
>>>>>>>   *
>>>>>>>   * @param buf      Buffer handle
>>>>>>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
>>>>>>>   */
>>>>>>>  void odp_buffer_print(odp_buffer_t buf);
>>>>>>>
>>>>>>> +/**
>>>>>>> + * Split a buffer into two buffers at a specified split point
>>>>>>> + *
>>>>>>> + * @param[in]  buf     Handle of buffer to split
>>>>>>> + * @param[in]  offset  Byte offset within buf to split buffer
>>>>>>> + *
>>>>>>> + * @return             Buffer handle of the created split buffer
>>>>>>> + */
>>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * Join two buffers into a single buffer
>>>>>>> + *
>>>>>>> + * @param[in]  buf1    Buffer handle of first buffer to join
>>>>>>> + * @param[in]  buf2    Buffer handle of second buffer to join
>>>>>>> + *
>>>>>>> + * @return             Buffer handle of the joined buffer
>>>>>>> + */
>>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * Trim a buffer at a specified trim point
>>>>>>> + *
>>>>>>> + * @param[in]  buf     Buffer handle of buffer to trim
>>>>>>> + * @param[in]  offset  byte offset within buf to trim
>>>>>>> + *
>>>>>>> + * @return             Handle of the trimmed buffer or
>>>>>>> + *                     ODP_BUFFER_INVALID if the operation was not
>>>>>>> performed
>>>>>>> + */
>>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
>>>>>>> +/**
>>>>>>> + * Extend a buffer for a specified number of bytes
>>>>>>> + *
>>>>>>> + * @param[in]  buf     Buffer handle of buffer to expand
>>>>>>> + * @param[in]  ext     size, in bytes, of the extent to add to the
>>>>>>> + *                     existing buffer.
>>>>>>> + *
>>>>>>> + * @return             Handle of the extended buffer or
>>>>>>> ODP_BUFFER_INVALID
>>>>>>> + *                     if the operation was not performed
>>>>>>> + */
>>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * Clone a buffer, returning an exact copy of it
>>>>>>> + *
>>>>>>> + * @param[in]  buf     Buffer handle of buffer to duplicate
>>>>>>> + *
>>>>>>> + * @return             Handle of the duplicated buffer or
>>>>>>> ODP_BUFFER_INVALID
>>>>>>> + *                     if the operation was not performed
>>>>>>> + */
>>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * Copy a buffer, returning an exact copy of it
>>>>>>> + *
>>>>>>> + * @param[in]  buf     Buffer handle of buffer to copy
>>>>>>> + *
>>>>>>> + * @return             Handle of the copied buffer or
>>>>>>> ODP_BUFFER_INVALID
>>>>>>> + *                     if the operation was not performed
>>>>>>> + */
>>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
>>>>>>> +
>>>>>>> +
>>>>>>>
>>>>>>>  #ifdef __cplusplus
>>>>>>>  }
>>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
>>>>>>> b/platform/linux-generic/include/api/odp_buffer_pool.h
>>>>>>> index fe88898..f85d96c 100644
>>>>>>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
>>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
>>>>>>> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const char
>>>>>>> *name,
>>>>>>>
>>>>>>>
>>>>>>>  /**
>>>>>>> + * Get the next buffer pool from its predecessor
>>>>>>> + *
>>>>>>> + * @param[in]  pool            Buffer pool handle
>>>>>>> + * @param[out] name            Name of the pool
>>>>>>> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1
>>>>>>> chars)
>>>>>>> + * @param[out] udata_size      Size of user meta data used by this
>>>>>>> pool.
>>>>>>> + * @param[out] buf_num         Number of buffers contained in this
>>>>>>> pool
>>>>>>> + * @param[out] buf_size        Default size of application data in
>>>>>>> each buffer
>>>>>>> + * @param[out] buf_type        Buffer type of the pool
>>>>>>> + * @param[out] buf_opts        Buffer options for this pool
>>>>>>> + * @param[out] predef          Predefined (1) or Created (0).
>>>>>>> + *
>>>>>>> + * @return                     Buffer pool handle
>>>>>>> + */
>>>>>>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
>>>>>>> +                                      char *name, size_t *udata_size,
>>>>>>> +                                      size_t *buf_num, size_t
>>>>>>> *buf_size,
>>>>>>> +                                      enum odp_buffer_type *buf_type,
>>>>>>> +                                      enum odp_buffer_opts *buf_opts,
>>>>>>> +                                      uint32_t *predef);
>>>>>>> +/**
>>>>>>>   * Find a buffer pool by name
>>>>>>>   *
>>>>>>>   * @param name      Name of the pool
>>>>>>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t
>>>>>>> pool);
>>>>>>>   */
>>>>>>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
>>>>>>>
>>>>>>> +/**
>>>>>>> +* Allocate a buffer from a buffer pool
>>>>>>> +*
>>>>>>> +* @param[in]   pool    Pool handle
>>>>>>> +* @param[in]   size    Size of object to store in buffer
>>>>>>> +*
>>>>>>> +* @return              Buffer handle or ODP_BUFFER_INVALID
>>>>>>> +*/
>>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t
>>>>>>> size);
>>>>>>>
>>>>>>>  /**
>>>>>>>   * Buffer free
>>>>>>> diff --git a/platform/linux-generic/odp_buffer.c
>>>>>>> b/platform/linux-generic/odp_buffer.c
>>>>>>> index e54e0e7..7f4b4f0 100644
>>>>>>> --- a/platform/linux-generic/odp_buffer.c
>>>>>>> +++ b/platform/linux-generic/odp_buffer.c
>>>>>>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
>>>>>>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
>>>>>>>  }
>>>>>>>
>>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf)
>>>>>>> +{
>>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>>>>>>> +
>>>>>>> +       if (buf_hdr->scatter.num_bufs == 0)
>>>>>>> +               return 0;
>>>>>>> +       else
>>>>>>> +               return 1;
>>>>>>> +}
>>>>>>> +
>>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf)
>>>>>>> +{
>>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>>>>>>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
>>>>>>> +}
>>>>>>>
>>>>>>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
>>>>>>>  {
>>>>>>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
>>>>>>>         printf("\n%s\n", str);
>>>>>>>  }
>>>>>>>
>>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
>>>>>>> +{
>>>>>>> +       (void)buf;
>>>>>>> +       (void)udata_size;
>>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>>> +       return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf)
>>>>>>> +{
>>>>>>> +       (void)buf;
>>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>>> +       return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
>>>>>>> +                                                size_t ndx)
>>>>>>> +{
>>>>>>> +       (void)buf;
>>>>>>> +       (void)ndx;
>>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>>> +       return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>>>>>>> +                                            odp_buffer_segment_t seg)
>>>>>>> +{
>>>>>>> +       (void)buf;
>>>>>>> +       (void)seg;
>>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>>> +       return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t
>>>>>>> seg,
>>>>>>> +                            size_t *seglen)
>>>>>>> +{
>>>>>>> +       (void)buf;
>>>>>>> +       (void)seg;
>>>>>>> +       (void)seglen;
>>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>>> +       return 0;
>>>>>>> +}
>>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>>>>>>> +size_t *seglen)
>>>>>>> +{
>>>>>>> +       (void)buf;
>>>>>>> +       (void)offset;
>>>>>>> +       (void)seglen;
>>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>>> +       return 0;
>>>>>>> +}
>>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
>>>>>>> +{
>>>>>>> +       (void)buf;
>>>>>>> +       (void)offset;
>>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>>> +       return;
>>>>>>> +}
>>>>>>> +
>>>>>>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t
>>>>>>> buf_src)
>>>>>>>  {
>>>>>>>         (void)buf_dst;
>>>>>>>         (void)buf_src;
>>>>>>>  }
>>>>>>> +
>>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
>>>>>>> +{
>>>>>>> +       (void)buf;
>>>>>>> +       (void)offset;
>>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>>> +       return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
>>>>>>> +{
>>>>>>> +       (void)buf1;
>>>>>>> +       (void)buf2;
>>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>>> +       return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
>>>>>>> +{
>>>>>>> +       (void)buf;
>>>>>>> +       (void)offset;
>>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>>> +       return 0;
>>>>>>> +}
>>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
>>>>>>> +{
>>>>>>> +       (void)buf;
>>>>>>> +       (void)ext;
>>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>>> +       return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
>>>>>>> +{
>>>>>>> +       (void)buf;
>>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>>> +       return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
>>>>>>> +{
>>>>>>> +       (void)buf;
>>>>>>> +       ODP_UNIMPLEMENTED();
>>>>>>> +       return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> diff --git a/platform/linux-generic/odp_buffer_pool.c
>>>>>>> b/platform/linux-generic/odp_buffer_pool.c
>>>>>>> index a48d7d6..bff4db5 100644
>>>>>>> --- a/platform/linux-generic/odp_buffer_pool.c
>>>>>>> +++ b/platform/linux-generic/odp_buffer_pool.c
>>>>>>> @@ -471,6 +471,13 @@ odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t
>>>>>>> pool_hdl)
>>>>>>>         return handle.u32;
>>>>>>>  }
>>>>>>>
>>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t
>>>>>>> size)
>>>>>>> +{
>>>>>>> +       (void)pool;
>>>>>>> +       (void) size;
>>>>>>> +       ODP_ERR("%s function is yet to be implemented", __func__);
>>>>>>> +       return 0;
>>>>>>> +}
>>>>>>>
>>>>>>>  void odp_buffer_free(odp_buffer_t buf)
>>>>>>>  {
>>>>>>> --
>>>>>>> 2.0.1.472.g6f92e5f
>>>>>>>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> lng-odp mailing list
>>>>>>> lng-odp@lists.linaro.org
>>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> lng-odp mailing list
>>>>>>> lng-odp@lists.linaro.org
>>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> lng-odp mailing list
>>>>>> lng-odp@lists.linaro.org
>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>>>
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> lng-odp mailing list
>>>>> lng-odp@lists.linaro.org
>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>>>>
>>>>
>>>
>>
>>
>> _______________________________________________
>> lng-odp mailing list
>> lng-odp@lists.linaro.org
>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>
Savolainen, Petri (NSN - FI/Espoo) Oct. 22, 2014, 12:27 p.m. UTC | #13
Hi,

In short, I think we must not bring segmentation support to the buffer level "just in case" someone would need it there. Real use cases for segmentation are on packet level (large packets, packet fragmentation/reassembly, etc), so the feature should be implemented there. 

-Petri

> -----Original Message-----

> From: ext Ciprian Barbu [mailto:ciprian.barbu@linaro.org]

> Sent: Wednesday, October 22, 2014 3:00 PM

> To: Bill Fischofer

> Cc: Ola Liljedahl; Savolainen, Petri (NSN - FI/Espoo); lng-

> odp@lists.linaro.org

> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API

> 

> On Wed, Oct 22, 2014 at 2:47 PM, Ciprian Barbu <ciprian.barbu@linaro.org>

> wrote:

> > This thread has been cold for 5 days, so the assumption is that we can

> > go forward with the design right now. This patch series proposed by

> > Bala updates some part of the API to the final form of the Buffer

> > Design Document, we should have it merged if there are no more

> > objections. For that more people with the right expertise should have

> > a look at it and get the thread back on track.

> >

> > I for example have observed the following issue. All the examples

> > create buffer pools over shared memory, which doesn't make sense for

> > some platforms, linux-dpdk for example, which ignores the base_addr

> > argument altogether. I think we need more clarity on this subject, for

> > sure the creation of buffer pools will differ from platform to

> > platform, which migrates to the application responsibility.

> >

> > I think we should have a helper function to easily create buffer pools

> > without worrying too much about the difference in buffer management

> > between platforms, so that one can write a simple portable application

> > with no sweat. For the hardcore programmers the API still gives fine

> > control to buffer management that depending on the platform could

> > involve additional prerequisites, like creating a shared memory

> > segment to hold the buffer pool.

> 

> Ok, so I had another look at the Buffer Management final design. I now

> see that the option of creating buffer pools from regions has been

> removed, so in this case things will be simpler for the applications.

> In other words we should really start working on the full

> implementation of the API because from there the problem I just stated

> above (having to create shared memory segments) will disappear.

> 

> >

> > On Fri, Oct 17, 2014 at 4:33 PM, Bill Fischofer

> > <bill.fischofer@linaro.org> wrote:

> >> Let's consider the implications of removing segmentation support from

> >> buffers and only having that concept be part of packets.

> >>

> >> The first question that arises is what is the relationship between the

> >> abstract types odp_packet_t and odp_buffer_t? This is important because

> >> currently we say that packets are allocated from ODP buffer pools, not

> from

> >> packet pools.  Do we need a separate odp_packet_pool_t that is used for

> >> packets?

> >>

> >> Today, when I allocate a packet I'm allocating a single object that

> happens

> >> to be a single buffer object of type ODP_BUFFER_TYPE_PACKET.  But that

> only

> >> works if the two objects have compatible semantics (including

> segmentation).

> >> If the semantics are not compatible, then an odp_packet_t may in fact

> be

> >> composed of multiple odp_buffer_t's because the packet may consist of

> >> multiple segments and buffers no longer recognize the concept of

> segments so

> >> a single buffer can only be a single segment.

> >>

> >> So now an odp_packet_segment_t may be an odp_buffer_t but an

> odp_packet_t in

> >> fact is some meta-object that is constructed (by whom?) from multiple

> >> odp_packet_segment_ts that are themselves odp_buffer_ts.  So

> >> odp_packet_to_buffer() no longer makes sense since there is no longer a

> >> one-to-one correspondence between packets and buffers.  We could have

> an

> >> odp_packet_segment_to_buffer() routine instead.

> >>

> >> Next question: What about meta data?  If an odp_packet_t is a type of

> an

> >> odp_buffer_t then this is very straightforward since all buffer meta

> data is

> >> reusable as packet meta data and the packet type can just add its own

> >> specific meta data to this set.  But if an odp_packet_t is now a

> separate

> >> object then where does the storage for its meta data come from? If we

> try to

> >> map it into an odp_buffer_t that doesn't work since an odp_packet_t may

> >> consist of multiple underlying odp_buffer_ts, one for each

> >> odp_packet_segment_t.  Is the packet meta data duplicated in each

> segment?

> >> Is the first segment of a packet special (odp_packet_first_segment_t)?

> And

> >> what about user meta data, since this is of potentially variable size?

> >>

> >> I submit that there are a lot of implications to this that need to be

> fully

> >> thought through, which is why I believe it's simpler to keep

> segmentation as

> >> part of buffers that (for now) only happens to be used by a particular

> type

> >> of buffer, namely packets.

> >>

> >> Bill

> >>

> >> On Fri, Oct 17, 2014 at 8:05 AM, Ola Liljedahl

> <ola.liljedahl@linaro.org>

> >> wrote:

> >>>

> >>> Personally I don't see any need for segmentation support in buffers. I

> am

> >>> just trying to shoot down what I think is flawed reasoning.

> >>>

> >>> -- Ola#1

> >>>

> >>> On 17 October 2014 15:03, Ola Liljedahl <ola.liljedahl@linaro.org>

> wrote:

> >>>>

> >>>> But segmentation is already needed in a current and known subclass

> (i.e.

> >>>> packets). We are not talking about some other feature which we don't

> know if

> >>>> it will be needed. So this is not a case of "just in case".

> >>>>

> >>>> -- Ola#1

> >>>>

> >>>>

> >>>> On 17 October 2014 14:45, Ola Dahl <dahl.ola@gmail.com> wrote:

> >>>>>

> >>>>> Hi,

> >>>>>

> >>>>> I do not think it is wise to put features in the base class "just in

> >>>>> case" they would be needed in some future (not yet known) subclass.

> >>>>>

> >>>>> So if the concept of segmentation is relevant for packets but not

> for

> >>>>> timers then I think it should be implemented as a feature of

> packets.

> >>>>>

> >>>>> Best regards,

> >>>>>

> >>>>> Ola D

> >>>>>

> >>>>> On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer

> >>>>> <bill.fischofer@linaro.org> wrote:

> >>>>>>

> >>>>>> I agree that packets are the buffer type that most likely uses

> >>>>>> segments, however there are many advantages to putting this support

> in the

> >>>>>> base class rather than the subclass independent of the number of

> buffer

> >>>>>> subclasses that will use this support today.

> >>>>>>

> >>>>>> It's simpler

> >>>>>> It's more extensible

> >>>>>> It results in cleaner and more efficient application code

> >>>>>>

> >>>>>> Allow me to expand on these points.  First simplicity.  Call the

> work

> >>>>>> required to support segmentation in the implementation X.  That X

> is going

> >>>>>> to be pretty much constant no matter where it is done.  But if the

> >>>>>> implementation has a choice between doing X at a low level vs.

> doing it at a

> >>>>>> high level then it's simpler for the implementation to do it once

> and be

> >>>>>> done with it.  If the implementation does it at a higher level then

> it is

> >>>>>> either constrained to map that higher-level implementation to be

> built on a

> >>>>>> set of lower-level functions that may or may not be appropriate or

> else it

> >>>>>> needs to do a completely parallel implementation that is optimal

> but highly

> >>>>>> duplicative.

> >>>>>>

> >>>>>> Extensibility should be clear.  If at some future point we decide

> >>>>>> segmentation would be useful for some new buffer type (e.g., IPC)

> then

> >>>>>> that's trivial to do if the base class supports it and awkward if

> it's only

> >>>>>> part of packets.

> >>>>>>

> >>>>>> From an application standpoint, it's cleaner because the packet

> APIs

> >>>>>> are just wrappers around their corresponding buffer APIs and can be

> mapped

> >>>>>> directly.  Otherwise we have a set of APIs that don't map and are

> not easily

> >>>>>> translatable.

> >>>>>>

> >>>>>> With regard to efficient segment access, that's what the

> >>>>>> odp_packet_addr() routine provides--one-step fast-path

> addressability to the

> >>>>>> first segment of a packet.  An odp_packet_t is an abstract opaque

> type.  It

> >>>>>> is not, and cannot be treated as an address by the application.

> >>>>>>

> >>>>>> Does that make sense?

> >>>>>>

> >>>>>> Bill

> >>>>>>

> >>>>>>

> >>>>>>

> >>>>>>

> >>>>>> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN - FI/Espoo)

> >>>>>> <petri.savolainen@nsn.com> wrote:

> >>>>>>>

> >>>>>>> Hi,

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> 1. The only segmentation use case is for segmented packet, not for

> >>>>>>> segmented buffers.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> 2. Common case for packets is that everything application needs is

> in

> >>>>>>> the first segment. Odp_packet_t could refer always into that

> “first

> >>>>>>> segment”, so that application (in the common case) would not need

> to use

> >>>>>>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> When buffer level features are minimized, the need for

> >>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All

> packet

> >>>>>>> manipulation should happen through odp_packet_xxx(pkt, …) calls.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> -Petri

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> From: ext Bill Fischofer [mailto:bill.fischofer@linaro.org]

> >>>>>>> Sent: Friday, October 17, 2014 1:17 PM

> >>>>>>> To: Savolainen, Petri (NSN - FI/Espoo)

> >>>>>>> Cc: ext Jacob, Jerin; lng-odp@lists.linaro.org

> >>>>>>>

> >>>>>>>

> >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support

> API

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> I'm not sure how to understand these two statements:

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> 1. There's no use case for segmented buffers

> >>>>>>>

> >>>>>>> 2. We should optimize for the common case (with segments)

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> These seem contradictory.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> The use case for segmented buffers is that some platforms have a

> >>>>>>> HW-defined and managed segmented buffer model. If we insist that

> the

> >>>>>>> application be able to specify and control packet segment sizes we

> are

> >>>>>>> making the decision to exclude such platforms from supporting ODP.

> The

> >>>>>>> optimization suggested is precisely what is being proposed here.

> By default

> >>>>>>> packets are assumed to be contained in implementation-managed

> segmented

> >>>>>>> buffers and the first segment will be large enough to contain all

> packet

> >>>>>>> headers for non-pathological cases.  The case where the

> application wishes

> >>>>>>> to traverse the entire packet in SW is expected to be rare because

> in the

> >>>>>>> data plane you simply do not have the cycles to do this at line

> rate for all

> >>>>>>> packets.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs,

> this is

> >>>>>>> simply syntax to avoid the constant need for explicit conversion

> functions

> >>>>>>> since unlike C++, C does not support generic functions.  So you

> cannot pass

> >>>>>>> an odp_packet_t to a function that expects an odp_buffer_t

> argument without

> >>>>>>> a conversion call.  Do we really want to force applications to

> constantly be

> >>>>>>> writing code like:

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> rather than

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> odp_packet_xxx(pkt,...)

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> Not only is this awkward, it is also inefficient.  By having the

> >>>>>>> explicit odp_packet_xxx() calls, the implementation is free to

> optimize

> >>>>>>> these references in whatever manner is appropriate to that

> implementation.

> >>>>>>> For some this may be a simple preprocessor-type expansion while

> for others

> >>>>>>> there may be more sophisticated handling.  But the application

> should

> >>>>>>> neither know nor care about how the implementation chooses to do

> this.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN -

> FI/Espoo)

> >>>>>>> <petri.savolainen@nsn.com> wrote:

> >>>>>>>

> >>>>>>> Hi,

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> This is also my opinion. There’s no use case for segmented buffers

> in

> >>>>>>> v1.0 - so let’s keep it simple and define that buffers (and thus

> buffer

> >>>>>>> pools) are always unsegmented. Segmentation comes into play only

> with

> >>>>>>> packets (and only with those packets that cannot fit into a single

> buffer).

> >>>>>>> For example, if implementation has max buffer size 256, any

> packets larger

> >>>>>>> than that are segmented and segments are handled with

> packet_seg_xxx calls.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> Also, I’d propose that we optimize for the common case (with

> segments)

> >>>>>>> - so that the odp_packet_t handle would refer always to the head

> of packet

> >>>>>>> segment. If the first segment (data/data_len pointed by the

> odp_packet_t)

> >>>>>>> carries all data application is interested in (=protocol headers),

> the

> >>>>>>> application would not have to use the segment API at all. Most

> applications

> >>>>>>> would not see any difference between small/large or

> segmented/unsegmented

> >>>>>>> packets as long as all headers fit into the first segment.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> -Petri

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> From: lng-odp-bounces@lists.linaro.org

> >>>>>>> [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of ext Jacob,

> Jerin

> >>>>>>> Sent: Friday, October 17, 2014 9:34 AM

> >>>>>>> To: Bill Fischofer

> >>>>>>> Cc: lng-odp@lists.linaro.org

> >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support

> API

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> The need for segment API infrastructure is very clear.The question

> is,

> >>>>>>> Do we need separate APIs for

> >>>>>>>

> >>>>>>> segment management at odp_buffer_segment* AND odp_packet_segment*

> >>>>>>> levels ?

> >>>>>>>

> >>>>>>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always

> >>>>>>> unsegmented and if there is a

> >>>>>>>

> >>>>>>> API for odp_packet_segement* then there will be not be any

> consumer

> >>>>>>> for odp_buffer_segment* API for 1.0

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> ________________________________

> >>>>>>>

> >>>>>>> From: Bill Fischofer <bill.fischofer@linaro.org>

> >>>>>>> Sent: Thursday, October 16, 2014 9:08 PM

> >>>>>>> To: Jacob, Jerin

> >>>>>>> Cc: Ola Liljedahl; Balasubramanian Manoharan; lng-

> odp@lists.linaro.org

> >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support

> API

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> From the buffer design doc (p. 8-9):

> >>>>>>>

> >>>>>>> Buffer Pool Options

> >>>>>>>

> >>>>>>> The odp_buffer_opts_e enum is used to specify additional options

> >>>>>>> relating to the buffer pool.  Buffer pool options defined are:

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> ·     ODP_BUFFER_OPTS_NONE

> >>>>>>>

> >>>>>>> ·     ODP_BUFFER_OPTS_UNSEGMENTED

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> These options are additive so an application can simply specify a

> >>>>>>> buf_opts by ORing together the options needed.  Note that buffer

> pool

> >>>>>>> options are themselves OPTIONAL and a given implementation MAY

> fail the

> >>>>>>> buffer pool creation request with an appropriate errno if the

> requested

> >>>>>>> option is not supported by the underlying ODP implementation, with

> the

> >>>>>>> exception that UNSEGMENTED pools MUST be supported for non-packet

> types and

> >>>>>>> for packet types as long as the requested size is less than the

> >>>>>>> implementation-defined native packet segment size.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options

> with

> >>>>>>> no additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies

> that the

> >>>>>>> buffer pool should be unsegmented.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> So unsegmented buffer pool support is available.  As far as RAW

> >>>>>>> buffers go, again from the doc (p. 14):

> >>>>>>>

> >>>>>>> ODP_BUFFER_TYPE_RAW

> >>>>>>>

> >>>>>>> This is the “basic” buffer type which simply consists of a single

> >>>>>>> fixed-sized block of contiguous memory.  Buffers of this type do

> not support

> >>>>>>> user meta data and the only built-in meta data supported for this

> type of

> >>>>>>> buffer are those that are statically computable, such as pool and

> size. This

> >>>>>>> type of buffer is entirely under application control and most of

> the buffer

> >>>>>>> APIs defined in this document are not available.  APIs for this

> type of

> >>>>>>> buffer are described in this document.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> So RAW buffers are always unsegmented.  The intent is that Packets

> are

> >>>>>>> by default segmented but can be unsegmented while the other buffer

> types are

> >>>>>>> by default unsegmented but (with the exception of RAW buffers) can

> be made

> >>>>>>> segmented.  This is because all buffers start out as a single

> segment and

> >>>>>>> hence are unsegmented until they are expanded to overflow that

> single

> >>>>>>> segment.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> Hope that clarifies things.  Again, this is all very

> straightforward

> >>>>>>> and only comes into play when actually needed.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin

> >>>>>>> <Jerin.Jacob@caviumnetworks.com> wrote:

> >>>>>>>

> >>>>>>> If there is no valid use case for supporting segmentation for raw

> >>>>>>> buffers then lets drop it. At least it will reduce the effort of

> >>>>>>>

> >>>>>>> implementing and testing/verification buffer APIs on  different

> >>>>>>> platforms.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> ________________________________

> >>>>>>>

> >>>>>>> From: lng-odp-bounces@lists.linaro.org

> >>>>>>> <lng-odp-bounces@lists.linaro.org> on behalf of Ola Liljedahl

> >>>>>>> <ola.liljedahl@linaro.org>

> >>>>>>> Sent: Wednesday, October 8, 2014 1:37 PM

> >>>>>>> To: Balasubramanian Manoharan

> >>>>>>> Cc: lng-odp@lists.linaro.org

> >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support

> API

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> As I wrote in my comment to the architecture discussion yesterday,

> I

> >>>>>>> am against segmentation for buffers. Or at least there must be the

> >>>>>>> possibility to create a buffer pool with guaranteed non-segmented

> buffers.

> >>>>>>> Segmented packets are OK but not all usages for buffers relate to

> packets. A

> >>>>>>> lot of internal usages (timeouts, SW messages, internal data

> structures)

> >>>>>>> will not be able to handle segmented buffers so you must be able

> to force

> >>>>>>> the creation of buffer pools with non-segmented buffers.

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> -- Ola

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> On 8 October 2014 09:50, Balasubramanian Manoharan

> >>>>>>> <bala.manoharan@linaro.org> wrote:

> >>>>>>>

> >>>>>>> This patch contains ODP Buffer Management missing APIs

> >>>>>>> The intent of this patch is to port the missing APIs from Buffer

> >>>>>>> Management design document into Linux-generic repo.

> >>>>>>> The dummy functions will be replaced during linux-generic

> >>>>>>> implementation.

> >>>>>>>

> >>>>>>> Signed-off-by: Balasubramanian Manoharan

> <bala.manoharan@linaro.org>

> >>>>>>> ---

> >>>>>>>  platform/linux-generic/include/api/odp_buffer.h    | 203

> >>>>>>> ++++++++++++++++++++-

> >>>>>>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++

> >>>>>>>  platform/linux-generic/odp_buffer.c                | 120

> ++++++++++++

> >>>>>>>  platform/linux-generic/odp_buffer_pool.c           |   7 +

> >>>>>>>  4 files changed, 351 insertions(+), 9 deletions(-)

> >>>>>>>

> >>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer.h

> >>>>>>> b/platform/linux-generic/include/api/odp_buffer.h

> >>>>>>> index d8577fd..aeb75ed 100644

> >>>>>>> --- a/platform/linux-generic/include/api/odp_buffer.h

> >>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer.h

> >>>>>>> @@ -28,8 +28,34 @@ extern "C" {

> >>>>>>>   */

> >>>>>>>  typedef uint32_t odp_buffer_t;

> >>>>>>>

> >>>>>>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */

> >>>>>>> +/**

> >>>>>>> +* ODP buffer segment

> >>>>>>> +*/

> >>>>>>> +typedef uint32_t odp_buffer_segment_t;

> >>>>>>>

> >>>>>>> +/**

> >>>>>>> +* ODP buffer type

> >>>>>>> +*/

> >>>>>>> +typedef enum odp_buffer_type {

> >>>>>>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid

> */

> >>>>>>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold

> any

> >>>>>>> other

> >>>>>>> +                                       buffer type */

> >>>>>>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,

> >>>>>>> +                                       no additional metadata */

> >>>>>>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */

> >>>>>>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */

> >>>>>>> +} odp_buffer_type_e;

> >>>>>>> +

> >>>>>>> +/**

> >>>>>>> +* ODP buffer options

> >>>>>>> +*/

> >>>>>>> +typedef enum odp_buffer_opts {

> >>>>>>> +       ODP_BUFFER_OPTS_NONE,

> >>>>>>> +       ODP_BUFFER_OPTS_UNSEGMENTED

> >>>>>>> +} odp_buffer_opts_e;

> >>>>>>> +

> >>>>>>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */

> >>>>>>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */

> >>>>>>>

> >>>>>>>  /**

> >>>>>>>   * Buffer start address

> >>>>>>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);

> >>>>>>>   */

> >>>>>>>  int odp_buffer_type(odp_buffer_t buf);

> >>>>>>>

> >>>>>>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */

> >>>>>>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold

> any

> >>>>>>> other

> >>>>>>> -                                         buffer type */

> >>>>>>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no

> additional

> >>>>>>> metadata */

> >>>>>>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */

> >>>>>>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */

> >>>>>>> -

> >>>>>>> -

> >>>>>>>  /**

> >>>>>>>   * Tests if buffer is valid

> >>>>>>>   *

> >>>>>>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);

> >>>>>>>  int odp_buffer_is_valid(odp_buffer_t buf);

> >>>>>>>

> >>>>>>>  /**

> >>>>>>> + * Tests if buffer is segmented

> >>>>>>> + *

> >>>>>>> + * @param[in]  buf     Buffer handle

> >>>>>>> + *

> >>>>>>> + * @return             1 if buffer has more than one segment,

> >>>>>>> + *                     otherwise 0

> >>>>>>> + */

> >>>>>>> +

> >>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf);

> >>>>>>> +

> >>>>>>> +/**

> >>>>>>> + * Get address and size of user meta data associated with a

> buffer

> >>>>>>> + *

> >>>>>>> + * @param[in]  buf             Buffer handle

> >>>>>>> + * @param[out] udata_size      Number of bytes of user meta data

> >>>>>>> available

> >>>>>>> + *                             at the returned address

> >>>>>>> + * @return                     Address of the user meta data for

> this

> >>>>>>> buffer

> >>>>>>> + *                             or NULL if the buffer has no user

> meta

> >>>>>>> data.

> >>>>>>> + */

> >>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);

> >>>>>>> +

> >>>>>>> +/**

> >>>>>>> + * Get address of user meta data associated with a buffer

> >>>>>>> + *

> >>>>>>> + * @param[in]  buf     Buffer handle

> >>>>>>> + *

> >>>>>>> + * @return             Address of the user meta data for this

> buffer

> >>>>>>> + *                     or NULL if the buffer has no user meta

> data.

> >>>>>>> + */

> >>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf);

> >>>>>>> +

> >>>>>>> +/**

> >>>>>>> + * Get count of number of segments in a buffer

> >>>>>>> + *

> >>>>>>> + * @param[in]  buf     Buffer handle

> >>>>>>> + *

> >>>>>>> + * @return             Count of the number of segments in buf

> >>>>>>> + */

> >>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf);

> >>>>>>> +

> >>>>>>> +/**

> >>>>>>> + * Get the segment identifier for a buffer segment by index

> >>>>>>> + *

> >>>>>>> + * @param[in]  buf     Buffer handle

> >>>>>>> + * @param[in]  ndx     Segment index of segment of interest

> >>>>>>> + *

> >>>>>>> + * @return             Segment identifier or ODP_SEGMENT_INVALID

> if

> >>>>>>> the

> >>>>>>> + *                     supplied ndx is out of range.

> >>>>>>> + */

> >>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t

> buf,

> >>>>>>> size_t ndx);

> >>>>>>> +

> >>>>>>> +/**

> >>>>>>> + * Get the next segment identifier for a buffer segment

> >>>>>>> + *

> >>>>>>> + * @param[in]  buf     Buffer handle

> >>>>>>> + * @param[in]  seg     Segment identifier of the previous segment

> >>>>>>> + *

> >>>>>>> + * @return             Segment identifier of the next segment,

> >>>>>>> +                       or ODP_SEGMENT_INVALID.

> >>>>>>> + */

> >>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,

> >>>>>>> +                                            odp_buffer_segment_t

> >>>>>>> seg);

> >>>>>>> +/**

> >>>>>>> + * Get start address for a specified buffer segment

> >>>>>>> + *

> >>>>>>> + * @param[in]  buf     Buffer handle

> >>>>>>> + * @param[in]  seg     Segment identifier of the buffer to be

> >>>>>>> addressed

> >>>>>>> + * @param[out] seglen  Returned number of bytes in this buffer

> >>>>>>> + *                     segment available at returned address

> >>>>>>> + *

> >>>>>>> + * @return             Segment start address or NULL

> >>>>>>> + */

> >>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf,

> odp_buffer_segment_t

> >>>>>>> seg,

> >>>>>>> +size_t *seglen);

> >>>>>>> +

> >>>>>>> +/**

> >>>>>>> + *Unmap a buffer segment

> >>>>>>> + *

> >>>>>>> + * @param[in]  seg     Buffer segment handle

> >>>>>>> + */

> >>>>>>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);

> >>>>>>> +

> >>>>>>> +/**

> >>>>>>> +* Get start address for a specified buffer offset

> >>>>>>> +*

> >>>>>>> +* @param[in]   buf     Buffer handle

> >>>>>>> +* @param[in]   offset  Byte offset within the buffer to be

> addressed

> >>>>>>> +* @param[out]  seglen  Returned number of bytes in this buffer

> >>>>>>> +*                      segment available at returned address

> >>>>>>> +*

> >>>>>>> +* @return              Offset start address or NULL

> >>>>>>> +*/

> >>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,

> >>>>>>> +size_t *seglen);

> >>>>>>> +

> >>>>>>> +/**

> >>>>>>> + * Unmap a buffer segment by offset

> >>>>>>> + *

> >>>>>>> + * @param[in]  buf     Buffer handle

> >>>>>>> + * @param[in]  offset  Buffer offset

> >>>>>>> + */

> >>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);

> >>>>>>> +

> >>>>>>> +/**

> >>>>>>>   * Print buffer metadata to STDOUT

> >>>>>>>   *

> >>>>>>>   * @param buf      Buffer handle

> >>>>>>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);

> >>>>>>>   */

> >>>>>>>  void odp_buffer_print(odp_buffer_t buf);

> >>>>>>>

> >>>>>>> +/**

> >>>>>>> + * Split a buffer into two buffers at a specified split point

> >>>>>>> + *

> >>>>>>> + * @param[in]  buf     Handle of buffer to split

> >>>>>>> + * @param[in]  offset  Byte offset within buf to split buffer

> >>>>>>> + *

> >>>>>>> + * @return             Buffer handle of the created split buffer

> >>>>>>> + */

> >>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);

> >>>>>>> +

> >>>>>>> +/**

> >>>>>>> + * Join two buffers into a single buffer

> >>>>>>> + *

> >>>>>>> + * @param[in]  buf1    Buffer handle of first buffer to join

> >>>>>>> + * @param[in]  buf2    Buffer handle of second buffer to join

> >>>>>>> + *

> >>>>>>> + * @return             Buffer handle of the joined buffer

> >>>>>>> + */

> >>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t

> buf2);

> >>>>>>> +

> >>>>>>> +/**

> >>>>>>> + * Trim a buffer at a specified trim point

> >>>>>>> + *

> >>>>>>> + * @param[in]  buf     Buffer handle of buffer to trim

> >>>>>>> + * @param[in]  offset  byte offset within buf to trim

> >>>>>>> + *

> >>>>>>> + * @return             Handle of the trimmed buffer or

> >>>>>>> + *                     ODP_BUFFER_INVALID if the operation was

> not

> >>>>>>> performed

> >>>>>>> + */

> >>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);

> >>>>>>> +/**

> >>>>>>> + * Extend a buffer for a specified number of bytes

> >>>>>>> + *

> >>>>>>> + * @param[in]  buf     Buffer handle of buffer to expand

> >>>>>>> + * @param[in]  ext     size, in bytes, of the extent to add to

> the

> >>>>>>> + *                     existing buffer.

> >>>>>>> + *

> >>>>>>> + * @return             Handle of the extended buffer or

> >>>>>>> ODP_BUFFER_INVALID

> >>>>>>> + *                     if the operation was not performed

> >>>>>>> + */

> >>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);

> >>>>>>> +

> >>>>>>> +/**

> >>>>>>> + * Clone a buffer, returning an exact copy of it

> >>>>>>> + *

> >>>>>>> + * @param[in]  buf     Buffer handle of buffer to duplicate

> >>>>>>> + *

> >>>>>>> + * @return             Handle of the duplicated buffer or

> >>>>>>> ODP_BUFFER_INVALID

> >>>>>>> + *                     if the operation was not performed

> >>>>>>> + */

> >>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);

> >>>>>>> +

> >>>>>>> +/**

> >>>>>>> + * Copy a buffer, returning an exact copy of it

> >>>>>>> + *

> >>>>>>> + * @param[in]  buf     Buffer handle of buffer to copy

> >>>>>>> + *

> >>>>>>> + * @return             Handle of the copied buffer or

> >>>>>>> ODP_BUFFER_INVALID

> >>>>>>> + *                     if the operation was not performed

> >>>>>>> + */

> >>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);

> >>>>>>> +

> >>>>>>> +

> >>>>>>>

> >>>>>>>  #ifdef __cplusplus

> >>>>>>>  }

> >>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h

> >>>>>>> b/platform/linux-generic/include/api/odp_buffer_pool.h

> >>>>>>> index fe88898..f85d96c 100644

> >>>>>>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h

> >>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h

> >>>>>>> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const

> char

> >>>>>>> *name,

> >>>>>>>

> >>>>>>>

> >>>>>>>  /**

> >>>>>>> + * Get the next buffer pool from its predecessor

> >>>>>>> + *

> >>>>>>> + * @param[in]  pool            Buffer pool handle

> >>>>>>> + * @param[out] name            Name of the pool

> >>>>>>> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1

> >>>>>>> chars)

> >>>>>>> + * @param[out] udata_size      Size of user meta data used by

> this

> >>>>>>> pool.

> >>>>>>> + * @param[out] buf_num         Number of buffers contained in

> this

> >>>>>>> pool

> >>>>>>> + * @param[out] buf_size        Default size of application data

> in

> >>>>>>> each buffer

> >>>>>>> + * @param[out] buf_type        Buffer type of the pool

> >>>>>>> + * @param[out] buf_opts        Buffer options for this pool

> >>>>>>> + * @param[out] predef          Predefined (1) or Created (0).

> >>>>>>> + *

> >>>>>>> + * @return                     Buffer pool handle

> >>>>>>> + */

> >>>>>>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,

> >>>>>>> +                                      char *name, size_t

> *udata_size,

> >>>>>>> +                                      size_t *buf_num, size_t

> >>>>>>> *buf_size,

> >>>>>>> +                                      enum odp_buffer_type

> *buf_type,

> >>>>>>> +                                      enum odp_buffer_opts

> *buf_opts,

> >>>>>>> +                                      uint32_t *predef);

> >>>>>>> +/**

> >>>>>>>   * Find a buffer pool by name

> >>>>>>>   *

> >>>>>>>   * @param name      Name of the pool

> >>>>>>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t

> >>>>>>> pool);

> >>>>>>>   */

> >>>>>>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);

> >>>>>>>

> >>>>>>> +/**

> >>>>>>> +* Allocate a buffer from a buffer pool

> >>>>>>> +*

> >>>>>>> +* @param[in]   pool    Pool handle

> >>>>>>> +* @param[in]   size    Size of object to store in buffer

> >>>>>>> +*

> >>>>>>> +* @return              Buffer handle or ODP_BUFFER_INVALID

> >>>>>>> +*/

> >>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t

> >>>>>>> size);

> >>>>>>>

> >>>>>>>  /**

> >>>>>>>   * Buffer free

> >>>>>>> diff --git a/platform/linux-generic/odp_buffer.c

> >>>>>>> b/platform/linux-generic/odp_buffer.c

> >>>>>>> index e54e0e7..7f4b4f0 100644

> >>>>>>> --- a/platform/linux-generic/odp_buffer.c

> >>>>>>> +++ b/platform/linux-generic/odp_buffer.c

> >>>>>>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)

> >>>>>>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);

> >>>>>>>  }

> >>>>>>>

> >>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf)

> >>>>>>> +{

> >>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);

> >>>>>>> +

> >>>>>>> +       if (buf_hdr->scatter.num_bufs == 0)

> >>>>>>> +               return 0;

> >>>>>>> +       else

> >>>>>>> +               return 1;

> >>>>>>> +}

> >>>>>>> +

> >>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf)

> >>>>>>> +{

> >>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);

> >>>>>>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;

> >>>>>>> +}

> >>>>>>>

> >>>>>>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)

> >>>>>>>  {

> >>>>>>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)

> >>>>>>>         printf("\n%s\n", str);

> >>>>>>>  }

> >>>>>>>

> >>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)

> >>>>>>> +{

> >>>>>>> +       (void)buf;

> >>>>>>> +       (void)udata_size;

> >>>>>>> +       ODP_UNIMPLEMENTED();

> >>>>>>> +       return 0;

> >>>>>>> +}

> >>>>>>> +

> >>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf)

> >>>>>>> +{

> >>>>>>> +       (void)buf;

> >>>>>>> +       ODP_UNIMPLEMENTED();

> >>>>>>> +       return 0;

> >>>>>>> +}

> >>>>>>> +

> >>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t

> buf,

> >>>>>>> +                                                size_t ndx)

> >>>>>>> +{

> >>>>>>> +       (void)buf;

> >>>>>>> +       (void)ndx;

> >>>>>>> +       ODP_UNIMPLEMENTED();

> >>>>>>> +       return 0;

> >>>>>>> +}

> >>>>>>> +

> >>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,

> >>>>>>> +                                            odp_buffer_segment_t

> seg)

> >>>>>>> +{

> >>>>>>> +       (void)buf;

> >>>>>>> +       (void)seg;

> >>>>>>> +       ODP_UNIMPLEMENTED();

> >>>>>>> +       return 0;

> >>>>>>> +}

> >>>>>>> +

> >>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf,

> odp_buffer_segment_t

> >>>>>>> seg,

> >>>>>>> +                            size_t *seglen)

> >>>>>>> +{

> >>>>>>> +       (void)buf;

> >>>>>>> +       (void)seg;

> >>>>>>> +       (void)seglen;

> >>>>>>> +       ODP_UNIMPLEMENTED();

> >>>>>>> +       return 0;

> >>>>>>> +}

> >>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,

> >>>>>>> +size_t *seglen)

> >>>>>>> +{

> >>>>>>> +       (void)buf;

> >>>>>>> +       (void)offset;

> >>>>>>> +       (void)seglen;

> >>>>>>> +       ODP_UNIMPLEMENTED();

> >>>>>>> +       return 0;

> >>>>>>> +}

> >>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)

> >>>>>>> +{

> >>>>>>> +       (void)buf;

> >>>>>>> +       (void)offset;

> >>>>>>> +       ODP_UNIMPLEMENTED();

> >>>>>>> +       return;

> >>>>>>> +}

> >>>>>>> +

> >>>>>>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t

> >>>>>>> buf_src)

> >>>>>>>  {

> >>>>>>>         (void)buf_dst;

> >>>>>>>         (void)buf_src;

> >>>>>>>  }

> >>>>>>> +

> >>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)

> >>>>>>> +{

> >>>>>>> +       (void)buf;

> >>>>>>> +       (void)offset;

> >>>>>>> +       ODP_UNIMPLEMENTED();

> >>>>>>> +       return 0;

> >>>>>>> +}

> >>>>>>> +

> >>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t

> buf2)

> >>>>>>> +{

> >>>>>>> +       (void)buf1;

> >>>>>>> +       (void)buf2;

> >>>>>>> +       ODP_UNIMPLEMENTED();

> >>>>>>> +       return 0;

> >>>>>>> +}

> >>>>>>> +

> >>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)

> >>>>>>> +{

> >>>>>>> +       (void)buf;

> >>>>>>> +       (void)offset;

> >>>>>>> +       ODP_UNIMPLEMENTED();

> >>>>>>> +       return 0;

> >>>>>>> +}

> >>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)

> >>>>>>> +{

> >>>>>>> +       (void)buf;

> >>>>>>> +       (void)ext;

> >>>>>>> +       ODP_UNIMPLEMENTED();

> >>>>>>> +       return 0;

> >>>>>>> +}

> >>>>>>> +

> >>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)

> >>>>>>> +{

> >>>>>>> +       (void)buf;

> >>>>>>> +       ODP_UNIMPLEMENTED();

> >>>>>>> +       return 0;

> >>>>>>> +}

> >>>>>>> +

> >>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)

> >>>>>>> +{

> >>>>>>> +       (void)buf;

> >>>>>>> +       ODP_UNIMPLEMENTED();

> >>>>>>> +       return 0;

> >>>>>>> +}

> >>>>>>> +

> >>>>>>> diff --git a/platform/linux-generic/odp_buffer_pool.c

> >>>>>>> b/platform/linux-generic/odp_buffer_pool.c

> >>>>>>> index a48d7d6..bff4db5 100644

> >>>>>>> --- a/platform/linux-generic/odp_buffer_pool.c

> >>>>>>> +++ b/platform/linux-generic/odp_buffer_pool.c

> >>>>>>> @@ -471,6 +471,13 @@ odp_buffer_t

> odp_buffer_alloc(odp_buffer_pool_t

> >>>>>>> pool_hdl)

> >>>>>>>         return handle.u32;

> >>>>>>>  }

> >>>>>>>

> >>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t

> >>>>>>> size)

> >>>>>>> +{

> >>>>>>> +       (void)pool;

> >>>>>>> +       (void) size;

> >>>>>>> +       ODP_ERR("%s function is yet to be implemented", __func__);

> >>>>>>> +       return 0;

> >>>>>>> +}

> >>>>>>>

> >>>>>>>  void odp_buffer_free(odp_buffer_t buf)

> >>>>>>>  {

> >>>>>>> --

> >>>>>>> 2.0.1.472.g6f92e5f

> >>>>>>>

> >>>>>>>

> >>>>>>> _______________________________________________

> >>>>>>> lng-odp mailing list

> >>>>>>> lng-odp@lists.linaro.org

> >>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>> _______________________________________________

> >>>>>>> lng-odp mailing list

> >>>>>>> lng-odp@lists.linaro.org

> >>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>>

> >>>>>>

> >>>>>>

> >>>>>>

> >>>>>> _______________________________________________

> >>>>>> lng-odp mailing list

> >>>>>> lng-odp@lists.linaro.org

> >>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp

> >>>>>>

> >>>>>

> >>>>>

> >>>>> _______________________________________________

> >>>>> lng-odp mailing list

> >>>>> lng-odp@lists.linaro.org

> >>>>> http://lists.linaro.org/mailman/listinfo/lng-odp

> >>>>>

> >>>>

> >>>

> >>

> >>

> >> _______________________________________________

> >> lng-odp mailing list

> >> lng-odp@lists.linaro.org

> >> http://lists.linaro.org/mailman/listinfo/lng-odp

> >>
Alexandru Badicioiu Oct. 22, 2014, 1 p.m. UTC | #14
The option of creating buffer pools out of memory regions does not solve
existing applications portability problem. The odp_pktio application
expects packets to be allocated in shared memory regions. Is this a
semantic that should be satisfied by all platforms?
 odp_shm_create takes a flag argument which has two values for
linux-generic:
/*
 * Shared memory flags
 */

/* Share level */
#define ODP_SHM_SW_ONLY 0x1 /**< Application SW only, no HW access */
#define ODP_SHM_PROC    0x2 /**< Share with external processes */

but odp_pktio uses 0. Could we assume that this value has a kind of
ODP_SHM_PACKET meaning?
We could also explicitly extend this flag list to work across platforms.

Alex





On 22 October 2014 14:59, Ciprian Barbu <ciprian.barbu@linaro.org> wrote:

> On Wed, Oct 22, 2014 at 2:47 PM, Ciprian Barbu <ciprian.barbu@linaro.org>
> wrote:
> > This thread has been cold for 5 days, so the assumption is that we can
> > go forward with the design right now. This patch series proposed by
> > Bala updates some part of the API to the final form of the Buffer
> > Design Document, we should have it merged if there are no more
> > objections. For that more people with the right expertise should have
> > a look at it and get the thread back on track.
> >
> > I for example have observed the following issue. All the examples
> > create buffer pools over shared memory, which doesn't make sense for
> > some platforms, linux-dpdk for example, which ignores the base_addr
> > argument altogether. I think we need more clarity on this subject, for
> > sure the creation of buffer pools will differ from platform to
> > platform, which migrates to the application responsibility.
> >
> > I think we should have a helper function to easily create buffer pools
> > without worrying too much about the difference in buffer management
> > between platforms, so that one can write a simple portable application
> > with no sweat. For the hardcore programmers the API still gives fine
> > control to buffer management that depending on the platform could
> > involve additional prerequisites, like creating a shared memory
> > segment to hold the buffer pool.
>
> Ok, so I had another look at the Buffer Management final design. I now
> see that the option of creating buffer pools from regions has been
> removed, so in this case things will be simpler for the applications.
> In other words we should really start working on the full
> implementation of the API because from there the problem I just stated
> above (having to create shared memory segments) will disappear.
>
> >
> > On Fri, Oct 17, 2014 at 4:33 PM, Bill Fischofer
> > <bill.fischofer@linaro.org> wrote:
> >> Let's consider the implications of removing segmentation support from
> >> buffers and only having that concept be part of packets.
> >>
> >> The first question that arises is what is the relationship between the
> >> abstract types odp_packet_t and odp_buffer_t? This is important because
> >> currently we say that packets are allocated from ODP buffer pools, not
> from
> >> packet pools.  Do we need a separate odp_packet_pool_t that is used for
> >> packets?
> >>
> >> Today, when I allocate a packet I'm allocating a single object that
> happens
> >> to be a single buffer object of type ODP_BUFFER_TYPE_PACKET.  But that
> only
> >> works if the two objects have compatible semantics (including
> segmentation).
> >> If the semantics are not compatible, then an odp_packet_t may in fact be
> >> composed of multiple odp_buffer_t's because the packet may consist of
> >> multiple segments and buffers no longer recognize the concept of
> segments so
> >> a single buffer can only be a single segment.
> >>
> >> So now an odp_packet_segment_t may be an odp_buffer_t but an
> odp_packet_t in
> >> fact is some meta-object that is constructed (by whom?) from multiple
> >> odp_packet_segment_ts that are themselves odp_buffer_ts.  So
> >> odp_packet_to_buffer() no longer makes sense since there is no longer a
> >> one-to-one correspondence between packets and buffers.  We could have an
> >> odp_packet_segment_to_buffer() routine instead.
> >>
> >> Next question: What about meta data?  If an odp_packet_t is a type of an
> >> odp_buffer_t then this is very straightforward since all buffer meta
> data is
> >> reusable as packet meta data and the packet type can just add its own
> >> specific meta data to this set.  But if an odp_packet_t is now a
> separate
> >> object then where does the storage for its meta data come from? If we
> try to
> >> map it into an odp_buffer_t that doesn't work since an odp_packet_t may
> >> consist of multiple underlying odp_buffer_ts, one for each
> >> odp_packet_segment_t.  Is the packet meta data duplicated in each
> segment?
> >> Is the first segment of a packet special (odp_packet_first_segment_t)?
> And
> >> what about user meta data, since this is of potentially variable size?
> >>
> >> I submit that there are a lot of implications to this that need to be
> fully
> >> thought through, which is why I believe it's simpler to keep
> segmentation as
> >> part of buffers that (for now) only happens to be used by a particular
> type
> >> of buffer, namely packets.
> >>
> >> Bill
> >>
> >> On Fri, Oct 17, 2014 at 8:05 AM, Ola Liljedahl <
> ola.liljedahl@linaro.org>
> >> wrote:
> >>>
> >>> Personally I don't see any need for segmentation support in buffers. I
> am
> >>> just trying to shoot down what I think is flawed reasoning.
> >>>
> >>> -- Ola#1
> >>>
> >>> On 17 October 2014 15:03, Ola Liljedahl <ola.liljedahl@linaro.org>
> wrote:
> >>>>
> >>>> But segmentation is already needed in a current and known subclass
> (i.e.
> >>>> packets). We are not talking about some other feature which we don't
> know if
> >>>> it will be needed. So this is not a case of "just in case".
> >>>>
> >>>> -- Ola#1
> >>>>
> >>>>
> >>>> On 17 October 2014 14:45, Ola Dahl <dahl.ola@gmail.com> wrote:
> >>>>>
> >>>>> Hi,
> >>>>>
> >>>>> I do not think it is wise to put features in the base class "just in
> >>>>> case" they would be needed in some future (not yet known) subclass.
> >>>>>
> >>>>> So if the concept of segmentation is relevant for packets but not for
> >>>>> timers then I think it should be implemented as a feature of packets.
> >>>>>
> >>>>> Best regards,
> >>>>>
> >>>>> Ola D
> >>>>>
> >>>>> On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer
> >>>>> <bill.fischofer@linaro.org> wrote:
> >>>>>>
> >>>>>> I agree that packets are the buffer type that most likely uses
> >>>>>> segments, however there are many advantages to putting this support
> in the
> >>>>>> base class rather than the subclass independent of the number of
> buffer
> >>>>>> subclasses that will use this support today.
> >>>>>>
> >>>>>> It's simpler
> >>>>>> It's more extensible
> >>>>>> It results in cleaner and more efficient application code
> >>>>>>
> >>>>>> Allow me to expand on these points.  First simplicity.  Call the
> work
> >>>>>> required to support segmentation in the implementation X.  That X
> is going
> >>>>>> to be pretty much constant no matter where it is done.  But if the
> >>>>>> implementation has a choice between doing X at a low level vs.
> doing it at a
> >>>>>> high level then it's simpler for the implementation to do it once
> and be
> >>>>>> done with it.  If the implementation does it at a higher level then
> it is
> >>>>>> either constrained to map that higher-level implementation to be
> built on a
> >>>>>> set of lower-level functions that may or may not be appropriate or
> else it
> >>>>>> needs to do a completely parallel implementation that is optimal
> but highly
> >>>>>> duplicative.
> >>>>>>
> >>>>>> Extensibility should be clear.  If at some future point we decide
> >>>>>> segmentation would be useful for some new buffer type (e.g., IPC)
> then
> >>>>>> that's trivial to do if the base class supports it and awkward if
> it's only
> >>>>>> part of packets.
> >>>>>>
> >>>>>> From an application standpoint, it's cleaner because the packet APIs
> >>>>>> are just wrappers around their corresponding buffer APIs and can be
> mapped
> >>>>>> directly.  Otherwise we have a set of APIs that don't map and are
> not easily
> >>>>>> translatable.
> >>>>>>
> >>>>>> With regard to efficient segment access, that's what the
> >>>>>> odp_packet_addr() routine provides--one-step fast-path
> addressability to the
> >>>>>> first segment of a packet.  An odp_packet_t is an abstract opaque
> type.  It
> >>>>>> is not, and cannot be treated as an address by the application.
> >>>>>>
> >>>>>> Does that make sense?
> >>>>>>
> >>>>>> Bill
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN - FI/Espoo)
> >>>>>> <petri.savolainen@nsn.com> wrote:
> >>>>>>>
> >>>>>>> Hi,
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> 1. The only segmentation use case is for segmented packet, not for
> >>>>>>> segmented buffers.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> 2. Common case for packets is that everything application needs is
> in
> >>>>>>> the first segment. Odp_packet_t could refer always into that “first
> >>>>>>> segment”, so that application (in the common case) would not need
> to use
> >>>>>>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> When buffer level features are minimized, the need for
> >>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All
> packet
> >>>>>>> manipulation should happen through odp_packet_xxx(pkt, …) calls.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> -Petri
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> From: ext Bill Fischofer [mailto:bill.fischofer@linaro.org]
> >>>>>>> Sent: Friday, October 17, 2014 1:17 PM
> >>>>>>> To: Savolainen, Petri (NSN - FI/Espoo)
> >>>>>>> Cc: ext Jacob, Jerin; lng-odp@lists.linaro.org
> >>>>>>>
> >>>>>>>
> >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
> API
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> I'm not sure how to understand these two statements:
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> 1. There's no use case for segmented buffers
> >>>>>>>
> >>>>>>> 2. We should optimize for the common case (with segments)
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> These seem contradictory.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> The use case for segmented buffers is that some platforms have a
> >>>>>>> HW-defined and managed segmented buffer model. If we insist that
> the
> >>>>>>> application be able to specify and control packet segment sizes we
> are
> >>>>>>> making the decision to exclude such platforms from supporting
> ODP.  The
> >>>>>>> optimization suggested is precisely what is being proposed here.
> By default
> >>>>>>> packets are assumed to be contained in implementation-managed
> segmented
> >>>>>>> buffers and the first segment will be large enough to contain all
> packet
> >>>>>>> headers for non-pathological cases.  The case where the
> application wishes
> >>>>>>> to traverse the entire packet in SW is expected to be rare because
> in the
> >>>>>>> data plane you simply do not have the cycles to do this at line
> rate for all
> >>>>>>> packets.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs,
> this is
> >>>>>>> simply syntax to avoid the constant need for explicit conversion
> functions
> >>>>>>> since unlike C++, C does not support generic functions.  So you
> cannot pass
> >>>>>>> an odp_packet_t to a function that expects an odp_buffer_t
> argument without
> >>>>>>> a conversion call.  Do we really want to force applications to
> constantly be
> >>>>>>> writing code like:
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> rather than
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> odp_packet_xxx(pkt,...)
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> Not only is this awkward, it is also inefficient.  By having the
> >>>>>>> explicit odp_packet_xxx() calls, the implementation is free to
> optimize
> >>>>>>> these references in whatever manner is appropriate to that
> implementation.
> >>>>>>> For some this may be a simple preprocessor-type expansion while
> for others
> >>>>>>> there may be more sophisticated handling.  But the application
> should
> >>>>>>> neither know nor care about how the implementation chooses to do
> this.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN - FI/Espoo)
> >>>>>>> <petri.savolainen@nsn.com> wrote:
> >>>>>>>
> >>>>>>> Hi,
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> This is also my opinion. There’s no use case for segmented buffers
> in
> >>>>>>> v1.0 - so let’s keep it simple and define that buffers (and thus
> buffer
> >>>>>>> pools) are always unsegmented. Segmentation comes into play only
> with
> >>>>>>> packets (and only with those packets that cannot fit into a single
> buffer).
> >>>>>>> For example, if implementation has max buffer size 256, any
> packets larger
> >>>>>>> than that are segmented and segments are handled with
> packet_seg_xxx calls.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> Also, I’d propose that we optimize for the common case (with
> segments)
> >>>>>>> - so that the odp_packet_t handle would refer always to the head
> of packet
> >>>>>>> segment. If the first segment (data/data_len pointed by the
> odp_packet_t)
> >>>>>>> carries all data application is interested in (=protocol headers),
> the
> >>>>>>> application would not have to use the segment API at all. Most
> applications
> >>>>>>> would not see any difference between small/large or
> segmented/unsegmented
> >>>>>>> packets as long as all headers fit into the first segment.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> -Petri
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> From: lng-odp-bounces@lists.linaro.org
> >>>>>>> [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of ext Jacob,
> Jerin
> >>>>>>> Sent: Friday, October 17, 2014 9:34 AM
> >>>>>>> To: Bill Fischofer
> >>>>>>> Cc: lng-odp@lists.linaro.org
> >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
> API
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> The need for segment API infrastructure is very clear.The question
> is,
> >>>>>>> Do we need separate APIs for
> >>>>>>>
> >>>>>>> segment management at odp_buffer_segment* AND odp_packet_segment*
> >>>>>>> levels ?
> >>>>>>>
> >>>>>>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always
> >>>>>>> unsegmented and if there is a
> >>>>>>>
> >>>>>>> API for odp_packet_segement* then there will be not be any consumer
> >>>>>>> for odp_buffer_segment* API for 1.0
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> ________________________________
> >>>>>>>
> >>>>>>> From: Bill Fischofer <bill.fischofer@linaro.org>
> >>>>>>> Sent: Thursday, October 16, 2014 9:08 PM
> >>>>>>> To: Jacob, Jerin
> >>>>>>> Cc: Ola Liljedahl; Balasubramanian Manoharan;
> lng-odp@lists.linaro.org
> >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
> API
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> From the buffer design doc (p. 8-9):
> >>>>>>>
> >>>>>>> Buffer Pool Options
> >>>>>>>
> >>>>>>> The odp_buffer_opts_e enum is used to specify additional options
> >>>>>>> relating to the buffer pool.  Buffer pool options defined are:
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> ·     ODP_BUFFER_OPTS_NONE
> >>>>>>>
> >>>>>>> ·     ODP_BUFFER_OPTS_UNSEGMENTED
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> These options are additive so an application can simply specify a
> >>>>>>> buf_opts by ORing together the options needed.  Note that buffer
> pool
> >>>>>>> options are themselves OPTIONAL and a given implementation MAY
> fail the
> >>>>>>> buffer pool creation request with an appropriate errno if the
> requested
> >>>>>>> option is not supported by the underlying ODP implementation, with
> the
> >>>>>>> exception that UNSEGMENTED pools MUST be supported for non-packet
> types and
> >>>>>>> for packet types as long as the requested size is less than the
> >>>>>>> implementation-defined native packet segment size.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options
> with
> >>>>>>> no additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies
> that the
> >>>>>>> buffer pool should be unsegmented.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> So unsegmented buffer pool support is available.  As far as RAW
> >>>>>>> buffers go, again from the doc (p. 14):
> >>>>>>>
> >>>>>>> ODP_BUFFER_TYPE_RAW
> >>>>>>>
> >>>>>>> This is the “basic” buffer type which simply consists of a single
> >>>>>>> fixed-sized block of contiguous memory.  Buffers of this type do
> not support
> >>>>>>> user meta data and the only built-in meta data supported for this
> type of
> >>>>>>> buffer are those that are statically computable, such as pool and
> size. This
> >>>>>>> type of buffer is entirely under application control and most of
> the buffer
> >>>>>>> APIs defined in this document are not available.  APIs for this
> type of
> >>>>>>> buffer are described in this document.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> So RAW buffers are always unsegmented.  The intent is that Packets
> are
> >>>>>>> by default segmented but can be unsegmented while the other buffer
> types are
> >>>>>>> by default unsegmented but (with the exception of RAW buffers) can
> be made
> >>>>>>> segmented.  This is because all buffers start out as a single
> segment and
> >>>>>>> hence are unsegmented until they are expanded to overflow that
> single
> >>>>>>> segment.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> Hope that clarifies things.  Again, this is all very
> straightforward
> >>>>>>> and only comes into play when actually needed.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin
> >>>>>>> <Jerin.Jacob@caviumnetworks.com> wrote:
> >>>>>>>
> >>>>>>> If there is no valid use case for supporting segmentation for raw
> >>>>>>> buffers then lets drop it. At least it will reduce the effort of
> >>>>>>>
> >>>>>>> implementing and testing/verification buffer APIs on  different
> >>>>>>> platforms.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> ________________________________
> >>>>>>>
> >>>>>>> From: lng-odp-bounces@lists.linaro.org
> >>>>>>> <lng-odp-bounces@lists.linaro.org> on behalf of Ola Liljedahl
> >>>>>>> <ola.liljedahl@linaro.org>
> >>>>>>> Sent: Wednesday, October 8, 2014 1:37 PM
> >>>>>>> To: Balasubramanian Manoharan
> >>>>>>> Cc: lng-odp@lists.linaro.org
> >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
> API
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> As I wrote in my comment to the architecture discussion yesterday,
> I
> >>>>>>> am against segmentation for buffers. Or at least there must be the
> >>>>>>> possibility to create a buffer pool with guaranteed non-segmented
> buffers.
> >>>>>>> Segmented packets are OK but not all usages for buffers relate to
> packets. A
> >>>>>>> lot of internal usages (timeouts, SW messages, internal data
> structures)
> >>>>>>> will not be able to handle segmented buffers so you must be able
> to force
> >>>>>>> the creation of buffer pools with non-segmented buffers.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> -- Ola
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> On 8 October 2014 09:50, Balasubramanian Manoharan
> >>>>>>> <bala.manoharan@linaro.org> wrote:
> >>>>>>>
> >>>>>>> This patch contains ODP Buffer Management missing APIs
> >>>>>>> The intent of this patch is to port the missing APIs from Buffer
> >>>>>>> Management design document into Linux-generic repo.
> >>>>>>> The dummy functions will be replaced during linux-generic
> >>>>>>> implementation.
> >>>>>>>
> >>>>>>> Signed-off-by: Balasubramanian Manoharan <
> bala.manoharan@linaro.org>
> >>>>>>> ---
> >>>>>>>  platform/linux-generic/include/api/odp_buffer.h    | 203
> >>>>>>> ++++++++++++++++++++-
> >>>>>>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
> >>>>>>>  platform/linux-generic/odp_buffer.c                | 120
> ++++++++++++
> >>>>>>>  platform/linux-generic/odp_buffer_pool.c           |   7 +
> >>>>>>>  4 files changed, 351 insertions(+), 9 deletions(-)
> >>>>>>>
> >>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer.h
> >>>>>>> b/platform/linux-generic/include/api/odp_buffer.h
> >>>>>>> index d8577fd..aeb75ed 100644
> >>>>>>> --- a/platform/linux-generic/include/api/odp_buffer.h
> >>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer.h
> >>>>>>> @@ -28,8 +28,34 @@ extern "C" {
> >>>>>>>   */
> >>>>>>>  typedef uint32_t odp_buffer_t;
> >>>>>>>
> >>>>>>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
> >>>>>>> +/**
> >>>>>>> +* ODP buffer segment
> >>>>>>> +*/
> >>>>>>> +typedef uint32_t odp_buffer_segment_t;
> >>>>>>>
> >>>>>>> +/**
> >>>>>>> +* ODP buffer type
> >>>>>>> +*/
> >>>>>>> +typedef enum odp_buffer_type {
> >>>>>>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */
> >>>>>>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold
> any
> >>>>>>> other
> >>>>>>> +                                       buffer type */
> >>>>>>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
> >>>>>>> +                                       no additional metadata */
> >>>>>>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
> >>>>>>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
> >>>>>>> +} odp_buffer_type_e;
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> +* ODP buffer options
> >>>>>>> +*/
> >>>>>>> +typedef enum odp_buffer_opts {
> >>>>>>> +       ODP_BUFFER_OPTS_NONE,
> >>>>>>> +       ODP_BUFFER_OPTS_UNSEGMENTED
> >>>>>>> +} odp_buffer_opts_e;
> >>>>>>> +
> >>>>>>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
> >>>>>>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
> >>>>>>>
> >>>>>>>  /**
> >>>>>>>   * Buffer start address
> >>>>>>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
> >>>>>>>   */
> >>>>>>>  int odp_buffer_type(odp_buffer_t buf);
> >>>>>>>
> >>>>>>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
> >>>>>>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any
> >>>>>>> other
> >>>>>>> -                                         buffer type */
> >>>>>>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no
> additional
> >>>>>>> metadata */
> >>>>>>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
> >>>>>>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
> >>>>>>> -
> >>>>>>> -
> >>>>>>>  /**
> >>>>>>>   * Tests if buffer is valid
> >>>>>>>   *
> >>>>>>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
> >>>>>>>  int odp_buffer_is_valid(odp_buffer_t buf);
> >>>>>>>
> >>>>>>>  /**
> >>>>>>> + * Tests if buffer is segmented
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle
> >>>>>>> + *
> >>>>>>> + * @return             1 if buffer has more than one segment,
> >>>>>>> + *                     otherwise 0
> >>>>>>> + */
> >>>>>>> +
> >>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Get address and size of user meta data associated with a buffer
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf             Buffer handle
> >>>>>>> + * @param[out] udata_size      Number of bytes of user meta data
> >>>>>>> available
> >>>>>>> + *                             at the returned address
> >>>>>>> + * @return                     Address of the user meta data for
> this
> >>>>>>> buffer
> >>>>>>> + *                             or NULL if the buffer has no user
> meta
> >>>>>>> data.
> >>>>>>> + */
> >>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Get address of user meta data associated with a buffer
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle
> >>>>>>> + *
> >>>>>>> + * @return             Address of the user meta data for this
> buffer
> >>>>>>> + *                     or NULL if the buffer has no user meta
> data.
> >>>>>>> + */
> >>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Get count of number of segments in a buffer
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle
> >>>>>>> + *
> >>>>>>> + * @return             Count of the number of segments in buf
> >>>>>>> + */
> >>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Get the segment identifier for a buffer segment by index
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle
> >>>>>>> + * @param[in]  ndx     Segment index of segment of interest
> >>>>>>> + *
> >>>>>>> + * @return             Segment identifier or ODP_SEGMENT_INVALID
> if
> >>>>>>> the
> >>>>>>> + *                     supplied ndx is out of range.
> >>>>>>> + */
> >>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
> >>>>>>> size_t ndx);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Get the next segment identifier for a buffer segment
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle
> >>>>>>> + * @param[in]  seg     Segment identifier of the previous segment
> >>>>>>> + *
> >>>>>>> + * @return             Segment identifier of the next segment,
> >>>>>>> +                       or ODP_SEGMENT_INVALID.
> >>>>>>> + */
> >>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
> >>>>>>> +                                            odp_buffer_segment_t
> >>>>>>> seg);
> >>>>>>> +/**
> >>>>>>> + * Get start address for a specified buffer segment
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle
> >>>>>>> + * @param[in]  seg     Segment identifier of the buffer to be
> >>>>>>> addressed
> >>>>>>> + * @param[out] seglen  Returned number of bytes in this buffer
> >>>>>>> + *                     segment available at returned address
> >>>>>>> + *
> >>>>>>> + * @return             Segment start address or NULL
> >>>>>>> + */
> >>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf,
> odp_buffer_segment_t
> >>>>>>> seg,
> >>>>>>> +size_t *seglen);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + *Unmap a buffer segment
> >>>>>>> + *
> >>>>>>> + * @param[in]  seg     Buffer segment handle
> >>>>>>> + */
> >>>>>>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> +* Get start address for a specified buffer offset
> >>>>>>> +*
> >>>>>>> +* @param[in]   buf     Buffer handle
> >>>>>>> +* @param[in]   offset  Byte offset within the buffer to be
> addressed
> >>>>>>> +* @param[out]  seglen  Returned number of bytes in this buffer
> >>>>>>> +*                      segment available at returned address
> >>>>>>> +*
> >>>>>>> +* @return              Offset start address or NULL
> >>>>>>> +*/
> >>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
> >>>>>>> +size_t *seglen);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Unmap a buffer segment by offset
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle
> >>>>>>> + * @param[in]  offset  Buffer offset
> >>>>>>> + */
> >>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>>   * Print buffer metadata to STDOUT
> >>>>>>>   *
> >>>>>>>   * @param buf      Buffer handle
> >>>>>>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
> >>>>>>>   */
> >>>>>>>  void odp_buffer_print(odp_buffer_t buf);
> >>>>>>>
> >>>>>>> +/**
> >>>>>>> + * Split a buffer into two buffers at a specified split point
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Handle of buffer to split
> >>>>>>> + * @param[in]  offset  Byte offset within buf to split buffer
> >>>>>>> + *
> >>>>>>> + * @return             Buffer handle of the created split buffer
> >>>>>>> + */
> >>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Join two buffers into a single buffer
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf1    Buffer handle of first buffer to join
> >>>>>>> + * @param[in]  buf2    Buffer handle of second buffer to join
> >>>>>>> + *
> >>>>>>> + * @return             Buffer handle of the joined buffer
> >>>>>>> + */
> >>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t
> buf2);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Trim a buffer at a specified trim point
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle of buffer to trim
> >>>>>>> + * @param[in]  offset  byte offset within buf to trim
> >>>>>>> + *
> >>>>>>> + * @return             Handle of the trimmed buffer or
> >>>>>>> + *                     ODP_BUFFER_INVALID if the operation was not
> >>>>>>> performed
> >>>>>>> + */
> >>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
> >>>>>>> +/**
> >>>>>>> + * Extend a buffer for a specified number of bytes
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle of buffer to expand
> >>>>>>> + * @param[in]  ext     size, in bytes, of the extent to add to the
> >>>>>>> + *                     existing buffer.
> >>>>>>> + *
> >>>>>>> + * @return             Handle of the extended buffer or
> >>>>>>> ODP_BUFFER_INVALID
> >>>>>>> + *                     if the operation was not performed
> >>>>>>> + */
> >>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Clone a buffer, returning an exact copy of it
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle of buffer to duplicate
> >>>>>>> + *
> >>>>>>> + * @return             Handle of the duplicated buffer or
> >>>>>>> ODP_BUFFER_INVALID
> >>>>>>> + *                     if the operation was not performed
> >>>>>>> + */
> >>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Copy a buffer, returning an exact copy of it
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle of buffer to copy
> >>>>>>> + *
> >>>>>>> + * @return             Handle of the copied buffer or
> >>>>>>> ODP_BUFFER_INVALID
> >>>>>>> + *                     if the operation was not performed
> >>>>>>> + */
> >>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
> >>>>>>> +
> >>>>>>> +
> >>>>>>>
> >>>>>>>  #ifdef __cplusplus
> >>>>>>>  }
> >>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
> >>>>>>> b/platform/linux-generic/include/api/odp_buffer_pool.h
> >>>>>>> index fe88898..f85d96c 100644
> >>>>>>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
> >>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
> >>>>>>> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const
> char
> >>>>>>> *name,
> >>>>>>>
> >>>>>>>
> >>>>>>>  /**
> >>>>>>> + * Get the next buffer pool from its predecessor
> >>>>>>> + *
> >>>>>>> + * @param[in]  pool            Buffer pool handle
> >>>>>>> + * @param[out] name            Name of the pool
> >>>>>>> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1
> >>>>>>> chars)
> >>>>>>> + * @param[out] udata_size      Size of user meta data used by this
> >>>>>>> pool.
> >>>>>>> + * @param[out] buf_num         Number of buffers contained in this
> >>>>>>> pool
> >>>>>>> + * @param[out] buf_size        Default size of application data in
> >>>>>>> each buffer
> >>>>>>> + * @param[out] buf_type        Buffer type of the pool
> >>>>>>> + * @param[out] buf_opts        Buffer options for this pool
> >>>>>>> + * @param[out] predef          Predefined (1) or Created (0).
> >>>>>>> + *
> >>>>>>> + * @return                     Buffer pool handle
> >>>>>>> + */
> >>>>>>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
> >>>>>>> +                                      char *name, size_t
> *udata_size,
> >>>>>>> +                                      size_t *buf_num, size_t
> >>>>>>> *buf_size,
> >>>>>>> +                                      enum odp_buffer_type
> *buf_type,
> >>>>>>> +                                      enum odp_buffer_opts
> *buf_opts,
> >>>>>>> +                                      uint32_t *predef);
> >>>>>>> +/**
> >>>>>>>   * Find a buffer pool by name
> >>>>>>>   *
> >>>>>>>   * @param name      Name of the pool
> >>>>>>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t
> >>>>>>> pool);
> >>>>>>>   */
> >>>>>>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
> >>>>>>>
> >>>>>>> +/**
> >>>>>>> +* Allocate a buffer from a buffer pool
> >>>>>>> +*
> >>>>>>> +* @param[in]   pool    Pool handle
> >>>>>>> +* @param[in]   size    Size of object to store in buffer
> >>>>>>> +*
> >>>>>>> +* @return              Buffer handle or ODP_BUFFER_INVALID
> >>>>>>> +*/
> >>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t
> >>>>>>> size);
> >>>>>>>
> >>>>>>>  /**
> >>>>>>>   * Buffer free
> >>>>>>> diff --git a/platform/linux-generic/odp_buffer.c
> >>>>>>> b/platform/linux-generic/odp_buffer.c
> >>>>>>> index e54e0e7..7f4b4f0 100644
> >>>>>>> --- a/platform/linux-generic/odp_buffer.c
> >>>>>>> +++ b/platform/linux-generic/odp_buffer.c
> >>>>>>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
> >>>>>>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
> >>>>>>>  }
> >>>>>>>
> >>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf)
> >>>>>>> +{
> >>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
> >>>>>>> +
> >>>>>>> +       if (buf_hdr->scatter.num_bufs == 0)
> >>>>>>> +               return 0;
> >>>>>>> +       else
> >>>>>>> +               return 1;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf)
> >>>>>>> +{
> >>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
> >>>>>>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
> >>>>>>> +}
> >>>>>>>
> >>>>>>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
> >>>>>>>  {
> >>>>>>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
> >>>>>>>         printf("\n%s\n", str);
> >>>>>>>  }
> >>>>>>>
> >>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)udata_size;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
> >>>>>>> +                                                size_t ndx)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)ndx;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
> >>>>>>> +                                            odp_buffer_segment_t
> seg)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)seg;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf,
> odp_buffer_segment_t
> >>>>>>> seg,
> >>>>>>> +                            size_t *seglen)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)seg;
> >>>>>>> +       (void)seglen;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
> >>>>>>> +size_t *seglen)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)offset;
> >>>>>>> +       (void)seglen;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)offset;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t
> >>>>>>> buf_src)
> >>>>>>>  {
> >>>>>>>         (void)buf_dst;
> >>>>>>>         (void)buf_src;
> >>>>>>>  }
> >>>>>>> +
> >>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)offset;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
> >>>>>>> +{
> >>>>>>> +       (void)buf1;
> >>>>>>> +       (void)buf2;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)offset;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)ext;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> diff --git a/platform/linux-generic/odp_buffer_pool.c
> >>>>>>> b/platform/linux-generic/odp_buffer_pool.c
> >>>>>>> index a48d7d6..bff4db5 100644
> >>>>>>> --- a/platform/linux-generic/odp_buffer_pool.c
> >>>>>>> +++ b/platform/linux-generic/odp_buffer_pool.c
> >>>>>>> @@ -471,6 +471,13 @@ odp_buffer_t
> odp_buffer_alloc(odp_buffer_pool_t
> >>>>>>> pool_hdl)
> >>>>>>>         return handle.u32;
> >>>>>>>  }
> >>>>>>>
> >>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t
> >>>>>>> size)
> >>>>>>> +{
> >>>>>>> +       (void)pool;
> >>>>>>> +       (void) size;
> >>>>>>> +       ODP_ERR("%s function is yet to be implemented", __func__);
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>>
> >>>>>>>  void odp_buffer_free(odp_buffer_t buf)
> >>>>>>>  {
> >>>>>>> --
> >>>>>>> 2.0.1.472.g6f92e5f
> >>>>>>>
> >>>>>>>
> >>>>>>> _______________________________________________
> >>>>>>> lng-odp mailing list
> >>>>>>> lng-odp@lists.linaro.org
> >>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> _______________________________________________
> >>>>>>> lng-odp mailing list
> >>>>>>> lng-odp@lists.linaro.org
> >>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>> _______________________________________________
> >>>>>> lng-odp mailing list
> >>>>>> lng-odp@lists.linaro.org
> >>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
> >>>>>>
> >>>>>
> >>>>>
> >>>>> _______________________________________________
> >>>>> lng-odp mailing list
> >>>>> lng-odp@lists.linaro.org
> >>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
> >>>>>
> >>>>
> >>>
> >>
> >>
> >> _______________________________________________
> >> lng-odp mailing list
> >> lng-odp@lists.linaro.org
> >> http://lists.linaro.org/mailman/listinfo/lng-odp
> >>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
Savolainen, Petri (NSN - FI/Espoo) Oct. 22, 2014, 1:18 p.m. UTC | #15
0 is the default => with current flag definitions: both SW + HW can access,  not shared with external processes.

-Petri

From: ext Alexandru Badicioiu [mailto:alexandru.badicioiu@linaro.org]

Sent: Wednesday, October 22, 2014 4:01 PM
To: Ciprian Barbu
Cc: Bill Fischofer; Savolainen, Petri (NSN - FI/Espoo); lng-odp@lists.linaro.org
Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API

The option of creating buffer pools out of memory regions does not solve existing applications portability problem. The odp_pktio application expects packets to be allocated in shared memory regions. Is this a semantic that should be satisfied by all platforms?
 odp_shm_create takes a flag argument which has two values for linux-generic:
/*
 * Shared memory flags
 */

/* Share level */
#define ODP_SHM_SW_ONLY 0x1 /**< Application SW only, no HW access */
#define ODP_SHM_PROC    0x2 /**< Share with external processes */

but odp_pktio uses 0. Could we assume that this value has a kind of ODP_SHM_PACKET meaning?
We could also explicitly extend this flag list to work across platforms.

Alex





On 22 October 2014 14:59, Ciprian Barbu <ciprian.barbu@linaro.org<mailto:ciprian.barbu@linaro.org>> wrote:
On Wed, Oct 22, 2014 at 2:47 PM, Ciprian Barbu <ciprian.barbu@linaro.org<mailto:ciprian.barbu@linaro.org>> wrote:
> This thread has been cold for 5 days, so the assumption is that we can

> go forward with the design right now. This patch series proposed by

> Bala updates some part of the API to the final form of the Buffer

> Design Document, we should have it merged if there are no more

> objections. For that more people with the right expertise should have

> a look at it and get the thread back on track.

>

> I for example have observed the following issue. All the examples

> create buffer pools over shared memory, which doesn't make sense for

> some platforms, linux-dpdk for example, which ignores the base_addr

> argument altogether. I think we need more clarity on this subject, for

> sure the creation of buffer pools will differ from platform to

> platform, which migrates to the application responsibility.

>

> I think we should have a helper function to easily create buffer pools

> without worrying too much about the difference in buffer management

> between platforms, so that one can write a simple portable application

> with no sweat. For the hardcore programmers the API still gives fine

> control to buffer management that depending on the platform could

> involve additional prerequisites, like creating a shared memory

> segment to hold the buffer pool.


Ok, so I had another look at the Buffer Management final design. I now
see that the option of creating buffer pools from regions has been
removed, so in this case things will be simpler for the applications.
In other words we should really start working on the full
implementation of the API because from there the problem I just stated
above (having to create shared memory segments) will disappear.

>

> On Fri, Oct 17, 2014 at 4:33 PM, Bill Fischofer

> <bill.fischofer@linaro.org<mailto:bill.fischofer@linaro.org>> wrote:

>> Let's consider the implications of removing segmentation support from

>> buffers and only having that concept be part of packets.

>>

>> The first question that arises is what is the relationship between the

>> abstract types odp_packet_t and odp_buffer_t? This is important because

>> currently we say that packets are allocated from ODP buffer pools, not from

>> packet pools.  Do we need a separate odp_packet_pool_t that is used for

>> packets?

>>

>> Today, when I allocate a packet I'm allocating a single object that happens

>> to be a single buffer object of type ODP_BUFFER_TYPE_PACKET.  But that only

>> works if the two objects have compatible semantics (including segmentation).

>> If the semantics are not compatible, then an odp_packet_t may in fact be

>> composed of multiple odp_buffer_t's because the packet may consist of

>> multiple segments and buffers no longer recognize the concept of segments so

>> a single buffer can only be a single segment.

>>

>> So now an odp_packet_segment_t may be an odp_buffer_t but an odp_packet_t in

>> fact is some meta-object that is constructed (by whom?) from multiple

>> odp_packet_segment_ts that are themselves odp_buffer_ts.  So

>> odp_packet_to_buffer() no longer makes sense since there is no longer a

>> one-to-one correspondence between packets and buffers.  We could have an

>> odp_packet_segment_to_buffer() routine instead.

>>

>> Next question: What about meta data?  If an odp_packet_t is a type of an

>> odp_buffer_t then this is very straightforward since all buffer meta data is

>> reusable as packet meta data and the packet type can just add its own

>> specific meta data to this set.  But if an odp_packet_t is now a separate

>> object then where does the storage for its meta data come from? If we try to

>> map it into an odp_buffer_t that doesn't work since an odp_packet_t may

>> consist of multiple underlying odp_buffer_ts, one for each

>> odp_packet_segment_t.  Is the packet meta data duplicated in each segment?

>> Is the first segment of a packet special (odp_packet_first_segment_t)?  And

>> what about user meta data, since this is of potentially variable size?

>>

>> I submit that there are a lot of implications to this that need to be fully

>> thought through, which is why I believe it's simpler to keep segmentation as

>> part of buffers that (for now) only happens to be used by a particular type

>> of buffer, namely packets.

>>

>> Bill

>>

>> On Fri, Oct 17, 2014 at 8:05 AM, Ola Liljedahl <ola.liljedahl@linaro.org<mailto:ola.liljedahl@linaro.org>>

>> wrote:

>>>

>>> Personally I don't see any need for segmentation support in buffers. I am

>>> just trying to shoot down what I think is flawed reasoning.

>>>

>>> -- Ola#1

>>>

>>> On 17 October 2014 15:03, Ola Liljedahl <ola.liljedahl@linaro.org<mailto:ola.liljedahl@linaro.org>> wrote:

>>>>

>>>> But segmentation is already needed in a current and known subclass (i.e.

>>>> packets). We are not talking about some other feature which we don't know if

>>>> it will be needed. So this is not a case of "just in case".

>>>>

>>>> -- Ola#1

>>>>

>>>>

>>>> On 17 October 2014 14:45, Ola Dahl <dahl.ola@gmail.com<mailto:dahl.ola@gmail.com>> wrote:

>>>>>

>>>>> Hi,

>>>>>

>>>>> I do not think it is wise to put features in the base class "just in

>>>>> case" they would be needed in some future (not yet known) subclass.

>>>>>

>>>>> So if the concept of segmentation is relevant for packets but not for

>>>>> timers then I think it should be implemented as a feature of packets.

>>>>>

>>>>> Best regards,

>>>>>

>>>>> Ola D

>>>>>

>>>>> On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer

>>>>> <bill.fischofer@linaro.org<mailto:bill.fischofer@linaro.org>> wrote:

>>>>>>

>>>>>> I agree that packets are the buffer type that most likely uses

>>>>>> segments, however there are many advantages to putting this support in the

>>>>>> base class rather than the subclass independent of the number of buffer

>>>>>> subclasses that will use this support today.

>>>>>>

>>>>>> It's simpler

>>>>>> It's more extensible

>>>>>> It results in cleaner and more efficient application code

>>>>>>

>>>>>> Allow me to expand on these points.  First simplicity.  Call the work

>>>>>> required to support segmentation in the implementation X.  That X is going

>>>>>> to be pretty much constant no matter where it is done.  But if the

>>>>>> implementation has a choice between doing X at a low level vs. doing it at a

>>>>>> high level then it's simpler for the implementation to do it once and be

>>>>>> done with it.  If the implementation does it at a higher level then it is

>>>>>> either constrained to map that higher-level implementation to be built on a

>>>>>> set of lower-level functions that may or may not be appropriate or else it

>>>>>> needs to do a completely parallel implementation that is optimal but highly

>>>>>> duplicative.

>>>>>>

>>>>>> Extensibility should be clear.  If at some future point we decide

>>>>>> segmentation would be useful for some new buffer type (e.g., IPC) then

>>>>>> that's trivial to do if the base class supports it and awkward if it's only

>>>>>> part of packets.

>>>>>>

>>>>>> From an application standpoint, it's cleaner because the packet APIs

>>>>>> are just wrappers around their corresponding buffer APIs and can be mapped

>>>>>> directly.  Otherwise we have a set of APIs that don't map and are not easily

>>>>>> translatable.

>>>>>>

>>>>>> With regard to efficient segment access, that's what the

>>>>>> odp_packet_addr() routine provides--one-step fast-path addressability to the

>>>>>> first segment of a packet.  An odp_packet_t is an abstract opaque type.  It

>>>>>> is not, and cannot be treated as an address by the application.

>>>>>>

>>>>>> Does that make sense?

>>>>>>

>>>>>> Bill

>>>>>>

>>>>>>

>>>>>>

>>>>>>

>>>>>> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN - FI/Espoo)

>>>>>> <petri.savolainen@nsn.com<mailto:petri.savolainen@nsn.com>> wrote:

>>>>>>>

>>>>>>> Hi,

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> 1. The only segmentation use case is for segmented packet, not for

>>>>>>> segmented buffers.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> 2. Common case for packets is that everything application needs is in

>>>>>>> the first segment. Odp_packet_t could refer always into that “first

>>>>>>> segment”, so that application (in the common case) would not need to use

>>>>>>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> When buffer level features are minimized, the need for

>>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All packet

>>>>>>> manipulation should happen through odp_packet_xxx(pkt, …) calls.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> -Petri

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> From: ext Bill Fischofer [mailto:bill.fischofer@linaro.org<mailto:bill.fischofer@linaro.org>]

>>>>>>> Sent: Friday, October 17, 2014 1:17 PM

>>>>>>> To: Savolainen, Petri (NSN - FI/Espoo)

>>>>>>> Cc: ext Jacob, Jerin; lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>>>>

>>>>>>>

>>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> I'm not sure how to understand these two statements:

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> 1. There's no use case for segmented buffers

>>>>>>>

>>>>>>> 2. We should optimize for the common case (with segments)

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> These seem contradictory.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> The use case for segmented buffers is that some platforms have a

>>>>>>> HW-defined and managed segmented buffer model. If we insist that the

>>>>>>> application be able to specify and control packet segment sizes we are

>>>>>>> making the decision to exclude such platforms from supporting ODP.  The

>>>>>>> optimization suggested is precisely what is being proposed here.  By default

>>>>>>> packets are assumed to be contained in implementation-managed segmented

>>>>>>> buffers and the first segment will be large enough to contain all packet

>>>>>>> headers for non-pathological cases.  The case where the application wishes

>>>>>>> to traverse the entire packet in SW is expected to be rare because in the

>>>>>>> data plane you simply do not have the cycles to do this at line rate for all

>>>>>>> packets.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs, this is

>>>>>>> simply syntax to avoid the constant need for explicit conversion functions

>>>>>>> since unlike C++, C does not support generic functions.  So you cannot pass

>>>>>>> an odp_packet_t to a function that expects an odp_buffer_t argument without

>>>>>>> a conversion call.  Do we really want to force applications to constantly be

>>>>>>> writing code like:

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> rather than

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> odp_packet_xxx(pkt,...)

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> Not only is this awkward, it is also inefficient.  By having the

>>>>>>> explicit odp_packet_xxx() calls, the implementation is free to optimize

>>>>>>> these references in whatever manner is appropriate to that implementation.

>>>>>>> For some this may be a simple preprocessor-type expansion while for others

>>>>>>> there may be more sophisticated handling.  But the application should

>>>>>>> neither know nor care about how the implementation chooses to do this.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN - FI/Espoo)

>>>>>>> <petri.savolainen@nsn.com<mailto:petri.savolainen@nsn.com>> wrote:

>>>>>>>

>>>>>>> Hi,

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> This is also my opinion. There’s no use case for segmented buffers in

>>>>>>> v1.0 - so let’s keep it simple and define that buffers (and thus buffer

>>>>>>> pools) are always unsegmented. Segmentation comes into play only with

>>>>>>> packets (and only with those packets that cannot fit into a single buffer).

>>>>>>> For example, if implementation has max buffer size 256, any packets larger

>>>>>>> than that are segmented and segments are handled with packet_seg_xxx calls.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> Also, I’d propose that we optimize for the common case (with segments)

>>>>>>> - so that the odp_packet_t handle would refer always to the head of packet

>>>>>>> segment. If the first segment (data/data_len pointed by the odp_packet_t)

>>>>>>> carries all data application is interested in (=protocol headers), the

>>>>>>> application would not have to use the segment API at all. Most applications

>>>>>>> would not see any difference between small/large or segmented/unsegmented

>>>>>>> packets as long as all headers fit into the first segment.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> -Petri

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> From: lng-odp-bounces@lists.linaro.org<mailto:lng-odp-bounces@lists.linaro.org>

>>>>>>> [mailto:lng-odp-bounces@lists.linaro.org<mailto:lng-odp-bounces@lists.linaro.org>] On Behalf Of ext Jacob, Jerin

>>>>>>> Sent: Friday, October 17, 2014 9:34 AM

>>>>>>> To: Bill Fischofer

>>>>>>> Cc: lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> The need for segment API infrastructure is very clear.The question is,

>>>>>>> Do we need separate APIs for

>>>>>>>

>>>>>>> segment management at odp_buffer_segment* AND odp_packet_segment*

>>>>>>> levels ?

>>>>>>>

>>>>>>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always

>>>>>>> unsegmented and if there is a

>>>>>>>

>>>>>>> API for odp_packet_segement* then there will be not be any consumer

>>>>>>> for odp_buffer_segment* API for 1.0

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> ________________________________

>>>>>>>

>>>>>>> From: Bill Fischofer <bill.fischofer@linaro.org<mailto:bill.fischofer@linaro.org>>

>>>>>>> Sent: Thursday, October 16, 2014 9:08 PM

>>>>>>> To: Jacob, Jerin

>>>>>>> Cc: Ola Liljedahl; Balasubramanian Manoharan; lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> From the buffer design doc (p. 8-9):

>>>>>>>

>>>>>>> Buffer Pool Options

>>>>>>>

>>>>>>> The odp_buffer_opts_e enum is used to specify additional options

>>>>>>> relating to the buffer pool.  Buffer pool options defined are:

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> ·     ODP_BUFFER_OPTS_NONE

>>>>>>>

>>>>>>> ·     ODP_BUFFER_OPTS_UNSEGMENTED

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> These options are additive so an application can simply specify a

>>>>>>> buf_opts by ORing together the options needed.  Note that buffer pool

>>>>>>> options are themselves OPTIONAL and a given implementation MAY fail the

>>>>>>> buffer pool creation request with an appropriate errno if the requested

>>>>>>> option is not supported by the underlying ODP implementation, with the

>>>>>>> exception that UNSEGMENTED pools MUST be supported for non-packet types and

>>>>>>> for packet types as long as the requested size is less than the

>>>>>>> implementation-defined native packet segment size.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options with

>>>>>>> no additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies that the

>>>>>>> buffer pool should be unsegmented.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> So unsegmented buffer pool support is available.  As far as RAW

>>>>>>> buffers go, again from the doc (p. 14):

>>>>>>>

>>>>>>> ODP_BUFFER_TYPE_RAW

>>>>>>>

>>>>>>> This is the “basic” buffer type which simply consists of a single

>>>>>>> fixed-sized block of contiguous memory.  Buffers of this type do not support

>>>>>>> user meta data and the only built-in meta data supported for this type of

>>>>>>> buffer are those that are statically computable, such as pool and size. This

>>>>>>> type of buffer is entirely under application control and most of the buffer

>>>>>>> APIs defined in this document are not available.  APIs for this type of

>>>>>>> buffer are described in this document.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> So RAW buffers are always unsegmented.  The intent is that Packets are

>>>>>>> by default segmented but can be unsegmented while the other buffer types are

>>>>>>> by default unsegmented but (with the exception of RAW buffers) can be made

>>>>>>> segmented.  This is because all buffers start out as a single segment and

>>>>>>> hence are unsegmented until they are expanded to overflow that single

>>>>>>> segment.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> Hope that clarifies things.  Again, this is all very straightforward

>>>>>>> and only comes into play when actually needed.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin

>>>>>>> <Jerin.Jacob@caviumnetworks.com<mailto:Jerin.Jacob@caviumnetworks.com>> wrote:

>>>>>>>

>>>>>>> If there is no valid use case for supporting segmentation for raw

>>>>>>> buffers then lets drop it. At least it will reduce the effort of

>>>>>>>

>>>>>>> implementing and testing/verification buffer APIs on  different

>>>>>>> platforms.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> ________________________________

>>>>>>>

>>>>>>> From: lng-odp-bounces@lists.linaro.org<mailto:lng-odp-bounces@lists.linaro.org>

>>>>>>> <lng-odp-bounces@lists.linaro.org<mailto:lng-odp-bounces@lists.linaro.org>> on behalf of Ola Liljedahl

>>>>>>> <ola.liljedahl@linaro.org<mailto:ola.liljedahl@linaro.org>>

>>>>>>> Sent: Wednesday, October 8, 2014 1:37 PM

>>>>>>> To: Balasubramanian Manoharan

>>>>>>> Cc: lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> As I wrote in my comment to the architecture discussion yesterday, I

>>>>>>> am against segmentation for buffers. Or at least there must be the

>>>>>>> possibility to create a buffer pool with guaranteed non-segmented buffers.

>>>>>>> Segmented packets are OK but not all usages for buffers relate to packets. A

>>>>>>> lot of internal usages (timeouts, SW messages, internal data structures)

>>>>>>> will not be able to handle segmented buffers so you must be able to force

>>>>>>> the creation of buffer pools with non-segmented buffers.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> -- Ola

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> On 8 October 2014 09:50, Balasubramanian Manoharan

>>>>>>> <bala.manoharan@linaro.org<mailto:bala.manoharan@linaro.org>> wrote:

>>>>>>>

>>>>>>> This patch contains ODP Buffer Management missing APIs

>>>>>>> The intent of this patch is to port the missing APIs from Buffer

>>>>>>> Management design document into Linux-generic repo.

>>>>>>> The dummy functions will be replaced during linux-generic

>>>>>>> implementation.

>>>>>>>

>>>>>>> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org<mailto:bala.manoharan@linaro.org>>

>>>>>>> ---

>>>>>>>  platform/linux-generic/include/api/odp_buffer.h    | 203

>>>>>>> ++++++++++++++++++++-

>>>>>>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++

>>>>>>>  platform/linux-generic/odp_buffer.c                | 120 ++++++++++++

>>>>>>>  platform/linux-generic/odp_buffer_pool.c           |   7 +

>>>>>>>  4 files changed, 351 insertions(+), 9 deletions(-)

>>>>>>>

>>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer.h

>>>>>>> b/platform/linux-generic/include/api/odp_buffer.h

>>>>>>> index d8577fd..aeb75ed 100644

>>>>>>> --- a/platform/linux-generic/include/api/odp_buffer.h

>>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer.h

>>>>>>> @@ -28,8 +28,34 @@ extern "C" {

>>>>>>>   */

>>>>>>>  typedef uint32_t odp_buffer_t;

>>>>>>>

>>>>>>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */

>>>>>>> +/**

>>>>>>> +* ODP buffer segment

>>>>>>> +*/

>>>>>>> +typedef uint32_t odp_buffer_segment_t;

>>>>>>>

>>>>>>> +/**

>>>>>>> +* ODP buffer type

>>>>>>> +*/

>>>>>>> +typedef enum odp_buffer_type {

>>>>>>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */

>>>>>>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold any

>>>>>>> other

>>>>>>> +                                       buffer type */

>>>>>>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,

>>>>>>> +                                       no additional metadata */

>>>>>>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */

>>>>>>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */

>>>>>>> +} odp_buffer_type_e;

>>>>>>> +

>>>>>>> +/**

>>>>>>> +* ODP buffer options

>>>>>>> +*/

>>>>>>> +typedef enum odp_buffer_opts {

>>>>>>> +       ODP_BUFFER_OPTS_NONE,

>>>>>>> +       ODP_BUFFER_OPTS_UNSEGMENTED

>>>>>>> +} odp_buffer_opts_e;

>>>>>>> +

>>>>>>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */

>>>>>>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */

>>>>>>>

>>>>>>>  /**

>>>>>>>   * Buffer start address

>>>>>>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);

>>>>>>>   */

>>>>>>>  int odp_buffer_type(odp_buffer_t buf);

>>>>>>>

>>>>>>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */

>>>>>>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any

>>>>>>> other

>>>>>>> -                                         buffer type */

>>>>>>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional

>>>>>>> metadata */

>>>>>>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */

>>>>>>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */

>>>>>>> -

>>>>>>> -

>>>>>>>  /**

>>>>>>>   * Tests if buffer is valid

>>>>>>>   *

>>>>>>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);

>>>>>>>  int odp_buffer_is_valid(odp_buffer_t buf);

>>>>>>>

>>>>>>>  /**

>>>>>>> + * Tests if buffer is segmented

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle

>>>>>>> + *

>>>>>>> + * @return             1 if buffer has more than one segment,

>>>>>>> + *                     otherwise 0

>>>>>>> + */

>>>>>>> +

>>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Get address and size of user meta data associated with a buffer

>>>>>>> + *

>>>>>>> + * @param[in]  buf             Buffer handle

>>>>>>> + * @param[out] udata_size      Number of bytes of user meta data

>>>>>>> available

>>>>>>> + *                             at the returned address

>>>>>>> + * @return                     Address of the user meta data for this

>>>>>>> buffer

>>>>>>> + *                             or NULL if the buffer has no user meta

>>>>>>> data.

>>>>>>> + */

>>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Get address of user meta data associated with a buffer

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle

>>>>>>> + *

>>>>>>> + * @return             Address of the user meta data for this buffer

>>>>>>> + *                     or NULL if the buffer has no user meta data.

>>>>>>> + */

>>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Get count of number of segments in a buffer

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle

>>>>>>> + *

>>>>>>> + * @return             Count of the number of segments in buf

>>>>>>> + */

>>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Get the segment identifier for a buffer segment by index

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle

>>>>>>> + * @param[in]  ndx     Segment index of segment of interest

>>>>>>> + *

>>>>>>> + * @return             Segment identifier or ODP_SEGMENT_INVALID if

>>>>>>> the

>>>>>>> + *                     supplied ndx is out of range.

>>>>>>> + */

>>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,

>>>>>>> size_t ndx);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Get the next segment identifier for a buffer segment

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle

>>>>>>> + * @param[in]  seg     Segment identifier of the previous segment

>>>>>>> + *

>>>>>>> + * @return             Segment identifier of the next segment,

>>>>>>> +                       or ODP_SEGMENT_INVALID.

>>>>>>> + */

>>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,

>>>>>>> +                                            odp_buffer_segment_t

>>>>>>> seg);

>>>>>>> +/**

>>>>>>> + * Get start address for a specified buffer segment

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle

>>>>>>> + * @param[in]  seg     Segment identifier of the buffer to be

>>>>>>> addressed

>>>>>>> + * @param[out] seglen  Returned number of bytes in this buffer

>>>>>>> + *                     segment available at returned address

>>>>>>> + *

>>>>>>> + * @return             Segment start address or NULL

>>>>>>> + */

>>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t

>>>>>>> seg,

>>>>>>> +size_t *seglen);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + *Unmap a buffer segment

>>>>>>> + *

>>>>>>> + * @param[in]  seg     Buffer segment handle

>>>>>>> + */

>>>>>>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);

>>>>>>> +

>>>>>>> +/**

>>>>>>> +* Get start address for a specified buffer offset

>>>>>>> +*

>>>>>>> +* @param[in]   buf     Buffer handle

>>>>>>> +* @param[in]   offset  Byte offset within the buffer to be addressed

>>>>>>> +* @param[out]  seglen  Returned number of bytes in this buffer

>>>>>>> +*                      segment available at returned address

>>>>>>> +*

>>>>>>> +* @return              Offset start address or NULL

>>>>>>> +*/

>>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,

>>>>>>> +size_t *seglen);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Unmap a buffer segment by offset

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle

>>>>>>> + * @param[in]  offset  Buffer offset

>>>>>>> + */

>>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);

>>>>>>> +

>>>>>>> +/**

>>>>>>>   * Print buffer metadata to STDOUT

>>>>>>>   *

>>>>>>>   * @param buf      Buffer handle

>>>>>>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);

>>>>>>>   */

>>>>>>>  void odp_buffer_print(odp_buffer_t buf);

>>>>>>>

>>>>>>> +/**

>>>>>>> + * Split a buffer into two buffers at a specified split point

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Handle of buffer to split

>>>>>>> + * @param[in]  offset  Byte offset within buf to split buffer

>>>>>>> + *

>>>>>>> + * @return             Buffer handle of the created split buffer

>>>>>>> + */

>>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Join two buffers into a single buffer

>>>>>>> + *

>>>>>>> + * @param[in]  buf1    Buffer handle of first buffer to join

>>>>>>> + * @param[in]  buf2    Buffer handle of second buffer to join

>>>>>>> + *

>>>>>>> + * @return             Buffer handle of the joined buffer

>>>>>>> + */

>>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Trim a buffer at a specified trim point

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle of buffer to trim

>>>>>>> + * @param[in]  offset  byte offset within buf to trim

>>>>>>> + *

>>>>>>> + * @return             Handle of the trimmed buffer or

>>>>>>> + *                     ODP_BUFFER_INVALID if the operation was not

>>>>>>> performed

>>>>>>> + */

>>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);

>>>>>>> +/**

>>>>>>> + * Extend a buffer for a specified number of bytes

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle of buffer to expand

>>>>>>> + * @param[in]  ext     size, in bytes, of the extent to add to the

>>>>>>> + *                     existing buffer.

>>>>>>> + *

>>>>>>> + * @return             Handle of the extended buffer or

>>>>>>> ODP_BUFFER_INVALID

>>>>>>> + *                     if the operation was not performed

>>>>>>> + */

>>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Clone a buffer, returning an exact copy of it

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle of buffer to duplicate

>>>>>>> + *

>>>>>>> + * @return             Handle of the duplicated buffer or

>>>>>>> ODP_BUFFER_INVALID

>>>>>>> + *                     if the operation was not performed

>>>>>>> + */

>>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Copy a buffer, returning an exact copy of it

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle of buffer to copy

>>>>>>> + *

>>>>>>> + * @return             Handle of the copied buffer or

>>>>>>> ODP_BUFFER_INVALID

>>>>>>> + *                     if the operation was not performed

>>>>>>> + */

>>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);

>>>>>>> +

>>>>>>> +

>>>>>>>

>>>>>>>  #ifdef __cplusplus

>>>>>>>  }

>>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h

>>>>>>> b/platform/linux-generic/include/api/odp_buffer_pool.h

>>>>>>> index fe88898..f85d96c 100644

>>>>>>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h

>>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h

>>>>>>> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const char

>>>>>>> *name,

>>>>>>>

>>>>>>>

>>>>>>>  /**

>>>>>>> + * Get the next buffer pool from its predecessor

>>>>>>> + *

>>>>>>> + * @param[in]  pool            Buffer pool handle

>>>>>>> + * @param[out] name            Name of the pool

>>>>>>> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1

>>>>>>> chars)

>>>>>>> + * @param[out] udata_size      Size of user meta data used by this

>>>>>>> pool.

>>>>>>> + * @param[out] buf_num         Number of buffers contained in this

>>>>>>> pool

>>>>>>> + * @param[out] buf_size        Default size of application data in

>>>>>>> each buffer

>>>>>>> + * @param[out] buf_type        Buffer type of the pool

>>>>>>> + * @param[out] buf_opts        Buffer options for this pool

>>>>>>> + * @param[out] predef          Predefined (1) or Created (0).

>>>>>>> + *

>>>>>>> + * @return                     Buffer pool handle

>>>>>>> + */

>>>>>>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,

>>>>>>> +                                      char *name, size_t *udata_size,

>>>>>>> +                                      size_t *buf_num, size_t

>>>>>>> *buf_size,

>>>>>>> +                                      enum odp_buffer_type *buf_type,

>>>>>>> +                                      enum odp_buffer_opts *buf_opts,

>>>>>>> +                                      uint32_t *predef);

>>>>>>> +/**

>>>>>>>   * Find a buffer pool by name

>>>>>>>   *

>>>>>>>   * @param name      Name of the pool

>>>>>>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t

>>>>>>> pool);

>>>>>>>   */

>>>>>>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);

>>>>>>>

>>>>>>> +/**

>>>>>>> +* Allocate a buffer from a buffer pool

>>>>>>> +*

>>>>>>> +* @param[in]   pool    Pool handle

>>>>>>> +* @param[in]   size    Size of object to store in buffer

>>>>>>> +*

>>>>>>> +* @return              Buffer handle or ODP_BUFFER_INVALID

>>>>>>> +*/

>>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t

>>>>>>> size);

>>>>>>>

>>>>>>>  /**

>>>>>>>   * Buffer free

>>>>>>> diff --git a/platform/linux-generic/odp_buffer.c

>>>>>>> b/platform/linux-generic/odp_buffer.c

>>>>>>> index e54e0e7..7f4b4f0 100644

>>>>>>> --- a/platform/linux-generic/odp_buffer.c

>>>>>>> +++ b/platform/linux-generic/odp_buffer.c

>>>>>>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)

>>>>>>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);

>>>>>>>  }

>>>>>>>

>>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf)

>>>>>>> +{

>>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);

>>>>>>> +

>>>>>>> +       if (buf_hdr->scatter.num_bufs == 0)

>>>>>>> +               return 0;

>>>>>>> +       else

>>>>>>> +               return 1;

>>>>>>> +}

>>>>>>> +

>>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf)

>>>>>>> +{

>>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);

>>>>>>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;

>>>>>>> +}

>>>>>>>

>>>>>>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)

>>>>>>>  {

>>>>>>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)

>>>>>>>         printf("\n%s\n", str);

>>>>>>>  }

>>>>>>>

>>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)udata_size;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,

>>>>>>> +                                                size_t ndx)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)ndx;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,

>>>>>>> +                                            odp_buffer_segment_t seg)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)seg;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t

>>>>>>> seg,

>>>>>>> +                            size_t *seglen)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)seg;

>>>>>>> +       (void)seglen;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,

>>>>>>> +size_t *seglen)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)offset;

>>>>>>> +       (void)seglen;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)offset;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return;

>>>>>>> +}

>>>>>>> +

>>>>>>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t

>>>>>>> buf_src)

>>>>>>>  {

>>>>>>>         (void)buf_dst;

>>>>>>>         (void)buf_src;

>>>>>>>  }

>>>>>>> +

>>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)offset;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)

>>>>>>> +{

>>>>>>> +       (void)buf1;

>>>>>>> +       (void)buf2;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)offset;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)ext;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> diff --git a/platform/linux-generic/odp_buffer_pool.c

>>>>>>> b/platform/linux-generic/odp_buffer_pool.c

>>>>>>> index a48d7d6..bff4db5 100644

>>>>>>> --- a/platform/linux-generic/odp_buffer_pool.c

>>>>>>> +++ b/platform/linux-generic/odp_buffer_pool.c

>>>>>>> @@ -471,6 +471,13 @@ odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t

>>>>>>> pool_hdl)

>>>>>>>         return handle.u32;

>>>>>>>  }

>>>>>>>

>>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t

>>>>>>> size)

>>>>>>> +{

>>>>>>> +       (void)pool;

>>>>>>> +       (void) size;

>>>>>>> +       ODP_ERR("%s function is yet to be implemented", __func__);

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>>

>>>>>>>  void odp_buffer_free(odp_buffer_t buf)

>>>>>>>  {

>>>>>>> --

>>>>>>> 2.0.1.472.g6f92e5f

>>>>>>>

>>>>>>>

>>>>>>> _______________________________________________

>>>>>>> lng-odp mailing list

>>>>>>> lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> _______________________________________________

>>>>>>> lng-odp mailing list

>>>>>>> lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>

>>>>>>

>>>>>>

>>>>>> _______________________________________________

>>>>>> lng-odp mailing list

>>>>>> lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp

>>>>>>

>>>>>

>>>>>

>>>>> _______________________________________________

>>>>> lng-odp mailing list

>>>>> lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp

>>>>>

>>>>

>>>

>>

>>

>> _______________________________________________

>> lng-odp mailing list

>> lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>> http://lists.linaro.org/mailman/listinfo/lng-odp

>>


_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>
http://lists.linaro.org/mailman/listinfo/lng-odp
Alexandru Badicioiu Oct. 22, 2014, 1:26 p.m. UTC | #16
Thanks for clarification. Regarding the sharing, is 0 specifying that the
application does not require sharing or is a requirement for that segment
to be private?

Alex


On 22 October 2014 16:18, Savolainen, Petri (NSN - FI/Espoo) <
petri.savolainen@nsn.com> wrote:

>  0 is the default => with current flag definitions: both SW + HW can
> access,  not shared with external processes.
>
>
>
> -Petri
>
>
>
> *From:* ext Alexandru Badicioiu [mailto:alexandru.badicioiu@linaro.org]
> *Sent:* Wednesday, October 22, 2014 4:01 PM
> *To:* Ciprian Barbu
> *Cc:* Bill Fischofer; Savolainen, Petri (NSN - FI/Espoo);
> lng-odp@lists.linaro.org
>
> *Subject:* Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>
>
>
> The option of creating buffer pools out of memory regions does not solve
> existing applications portability problem. The odp_pktio application
> expects packets to be allocated in shared memory regions. Is this a
> semantic that should be satisfied by all platforms?
>
>  odp_shm_create takes a flag argument which has two values for
> linux-generic:
>
> /*
>
>  * Shared memory flags
>
>  */
>
>
>
> /* Share level */
>
> #define ODP_SHM_SW_ONLY 0x1 /**< Application SW only, no HW access */
>
> #define ODP_SHM_PROC    0x2 /**< Share with external processes */
>
>
>
> but odp_pktio uses 0. Could we assume that this value has a kind of
> ODP_SHM_PACKET meaning?
>
> We could also explicitly extend this flag list to work across platforms.
>
>
>
> Alex
>
>
>
>
>
>
>
>
>
>
>
> On 22 October 2014 14:59, Ciprian Barbu <ciprian.barbu@linaro.org> wrote:
>
> On Wed, Oct 22, 2014 at 2:47 PM, Ciprian Barbu <ciprian.barbu@linaro.org>
> wrote:
> > This thread has been cold for 5 days, so the assumption is that we can
> > go forward with the design right now. This patch series proposed by
> > Bala updates some part of the API to the final form of the Buffer
> > Design Document, we should have it merged if there are no more
> > objections. For that more people with the right expertise should have
> > a look at it and get the thread back on track.
> >
> > I for example have observed the following issue. All the examples
> > create buffer pools over shared memory, which doesn't make sense for
> > some platforms, linux-dpdk for example, which ignores the base_addr
> > argument altogether. I think we need more clarity on this subject, for
> > sure the creation of buffer pools will differ from platform to
> > platform, which migrates to the application responsibility.
> >
> > I think we should have a helper function to easily create buffer pools
> > without worrying too much about the difference in buffer management
> > between platforms, so that one can write a simple portable application
> > with no sweat. For the hardcore programmers the API still gives fine
> > control to buffer management that depending on the platform could
> > involve additional prerequisites, like creating a shared memory
> > segment to hold the buffer pool.
>
> Ok, so I had another look at the Buffer Management final design. I now
> see that the option of creating buffer pools from regions has been
> removed, so in this case things will be simpler for the applications.
> In other words we should really start working on the full
> implementation of the API because from there the problem I just stated
> above (having to create shared memory segments) will disappear.
>
>
> >
> > On Fri, Oct 17, 2014 at 4:33 PM, Bill Fischofer
> > <bill.fischofer@linaro.org> wrote:
> >> Let's consider the implications of removing segmentation support from
> >> buffers and only having that concept be part of packets.
> >>
> >> The first question that arises is what is the relationship between the
> >> abstract types odp_packet_t and odp_buffer_t? This is important because
> >> currently we say that packets are allocated from ODP buffer pools, not
> from
> >> packet pools.  Do we need a separate odp_packet_pool_t that is used for
> >> packets?
> >>
> >> Today, when I allocate a packet I'm allocating a single object that
> happens
> >> to be a single buffer object of type ODP_BUFFER_TYPE_PACKET.  But that
> only
> >> works if the two objects have compatible semantics (including
> segmentation).
> >> If the semantics are not compatible, then an odp_packet_t may in fact be
> >> composed of multiple odp_buffer_t's because the packet may consist of
> >> multiple segments and buffers no longer recognize the concept of
> segments so
> >> a single buffer can only be a single segment.
> >>
> >> So now an odp_packet_segment_t may be an odp_buffer_t but an
> odp_packet_t in
> >> fact is some meta-object that is constructed (by whom?) from multiple
> >> odp_packet_segment_ts that are themselves odp_buffer_ts.  So
> >> odp_packet_to_buffer() no longer makes sense since there is no longer a
> >> one-to-one correspondence between packets and buffers.  We could have an
> >> odp_packet_segment_to_buffer() routine instead.
> >>
> >> Next question: What about meta data?  If an odp_packet_t is a type of an
> >> odp_buffer_t then this is very straightforward since all buffer meta
> data is
> >> reusable as packet meta data and the packet type can just add its own
> >> specific meta data to this set.  But if an odp_packet_t is now a
> separate
> >> object then where does the storage for its meta data come from? If we
> try to
> >> map it into an odp_buffer_t that doesn't work since an odp_packet_t may
> >> consist of multiple underlying odp_buffer_ts, one for each
> >> odp_packet_segment_t.  Is the packet meta data duplicated in each
> segment?
> >> Is the first segment of a packet special (odp_packet_first_segment_t)?
> And
> >> what about user meta data, since this is of potentially variable size?
> >>
> >> I submit that there are a lot of implications to this that need to be
> fully
> >> thought through, which is why I believe it's simpler to keep
> segmentation as
> >> part of buffers that (for now) only happens to be used by a particular
> type
> >> of buffer, namely packets.
> >>
> >> Bill
> >>
> >> On Fri, Oct 17, 2014 at 8:05 AM, Ola Liljedahl <
> ola.liljedahl@linaro.org>
> >> wrote:
> >>>
> >>> Personally I don't see any need for segmentation support in buffers. I
> am
> >>> just trying to shoot down what I think is flawed reasoning.
> >>>
> >>> -- Ola#1
> >>>
> >>> On 17 October 2014 15:03, Ola Liljedahl <ola.liljedahl@linaro.org>
> wrote:
> >>>>
> >>>> But segmentation is already needed in a current and known subclass
> (i.e.
> >>>> packets). We are not talking about some other feature which we don't
> know if
> >>>> it will be needed. So this is not a case of "just in case".
> >>>>
> >>>> -- Ola#1
> >>>>
> >>>>
> >>>> On 17 October 2014 14:45, Ola Dahl <dahl.ola@gmail.com> wrote:
> >>>>>
> >>>>> Hi,
> >>>>>
> >>>>> I do not think it is wise to put features in the base class "just in
> >>>>> case" they would be needed in some future (not yet known) subclass.
> >>>>>
> >>>>> So if the concept of segmentation is relevant for packets but not for
> >>>>> timers then I think it should be implemented as a feature of packets.
> >>>>>
> >>>>> Best regards,
> >>>>>
> >>>>> Ola D
> >>>>>
> >>>>> On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer
> >>>>> <bill.fischofer@linaro.org> wrote:
> >>>>>>
> >>>>>> I agree that packets are the buffer type that most likely uses
> >>>>>> segments, however there are many advantages to putting this support
> in the
> >>>>>> base class rather than the subclass independent of the number of
> buffer
> >>>>>> subclasses that will use this support today.
> >>>>>>
> >>>>>> It's simpler
> >>>>>> It's more extensible
> >>>>>> It results in cleaner and more efficient application code
> >>>>>>
> >>>>>> Allow me to expand on these points.  First simplicity.  Call the
> work
> >>>>>> required to support segmentation in the implementation X.  That X
> is going
> >>>>>> to be pretty much constant no matter where it is done.  But if the
> >>>>>> implementation has a choice between doing X at a low level vs.
> doing it at a
> >>>>>> high level then it's simpler for the implementation to do it once
> and be
> >>>>>> done with it.  If the implementation does it at a higher level then
> it is
> >>>>>> either constrained to map that higher-level implementation to be
> built on a
> >>>>>> set of lower-level functions that may or may not be appropriate or
> else it
> >>>>>> needs to do a completely parallel implementation that is optimal
> but highly
> >>>>>> duplicative.
> >>>>>>
> >>>>>> Extensibility should be clear.  If at some future point we decide
> >>>>>> segmentation would be useful for some new buffer type (e.g., IPC)
> then
> >>>>>> that's trivial to do if the base class supports it and awkward if
> it's only
> >>>>>> part of packets.
> >>>>>>
> >>>>>> From an application standpoint, it's cleaner because the packet APIs
> >>>>>> are just wrappers around their corresponding buffer APIs and can be
> mapped
> >>>>>> directly.  Otherwise we have a set of APIs that don't map and are
> not easily
> >>>>>> translatable.
> >>>>>>
> >>>>>> With regard to efficient segment access, that's what the
> >>>>>> odp_packet_addr() routine provides--one-step fast-path
> addressability to the
> >>>>>> first segment of a packet.  An odp_packet_t is an abstract opaque
> type.  It
> >>>>>> is not, and cannot be treated as an address by the application.
> >>>>>>
> >>>>>> Does that make sense?
> >>>>>>
> >>>>>> Bill
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN - FI/Espoo)
> >>>>>> <petri.savolainen@nsn.com> wrote:
> >>>>>>>
> >>>>>>> Hi,
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> 1. The only segmentation use case is for segmented packet, not for
> >>>>>>> segmented buffers.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> 2. Common case for packets is that everything application needs is
> in
> >>>>>>> the first segment. Odp_packet_t could refer always into that “first
> >>>>>>> segment”, so that application (in the common case) would not need
> to use
> >>>>>>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> When buffer level features are minimized, the need for
> >>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All
> packet
> >>>>>>> manipulation should happen through odp_packet_xxx(pkt, …) calls.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> -Petri
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> From: ext Bill Fischofer [mailto:bill.fischofer@linaro.org]
> >>>>>>> Sent: Friday, October 17, 2014 1:17 PM
> >>>>>>> To: Savolainen, Petri (NSN - FI/Espoo)
> >>>>>>> Cc: ext Jacob, Jerin; lng-odp@lists.linaro.org
> >>>>>>>
> >>>>>>>
> >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
> API
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> I'm not sure how to understand these two statements:
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> 1. There's no use case for segmented buffers
> >>>>>>>
> >>>>>>> 2. We should optimize for the common case (with segments)
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> These seem contradictory.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> The use case for segmented buffers is that some platforms have a
> >>>>>>> HW-defined and managed segmented buffer model. If we insist that
> the
> >>>>>>> application be able to specify and control packet segment sizes we
> are
> >>>>>>> making the decision to exclude such platforms from supporting
> ODP.  The
> >>>>>>> optimization suggested is precisely what is being proposed here.
> By default
> >>>>>>> packets are assumed to be contained in implementation-managed
> segmented
> >>>>>>> buffers and the first segment will be large enough to contain all
> packet
> >>>>>>> headers for non-pathological cases.  The case where the
> application wishes
> >>>>>>> to traverse the entire packet in SW is expected to be rare because
> in the
> >>>>>>> data plane you simply do not have the cycles to do this at line
> rate for all
> >>>>>>> packets.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs,
> this is
> >>>>>>> simply syntax to avoid the constant need for explicit conversion
> functions
> >>>>>>> since unlike C++, C does not support generic functions.  So you
> cannot pass
> >>>>>>> an odp_packet_t to a function that expects an odp_buffer_t
> argument without
> >>>>>>> a conversion call.  Do we really want to force applications to
> constantly be
> >>>>>>> writing code like:
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> rather than
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> odp_packet_xxx(pkt,...)
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> Not only is this awkward, it is also inefficient.  By having the
> >>>>>>> explicit odp_packet_xxx() calls, the implementation is free to
> optimize
> >>>>>>> these references in whatever manner is appropriate to that
> implementation.
> >>>>>>> For some this may be a simple preprocessor-type expansion while
> for others
> >>>>>>> there may be more sophisticated handling.  But the application
> should
> >>>>>>> neither know nor care about how the implementation chooses to do
> this.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN - FI/Espoo)
> >>>>>>> <petri.savolainen@nsn.com> wrote:
> >>>>>>>
> >>>>>>> Hi,
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> This is also my opinion. There’s no use case for segmented buffers
> in
> >>>>>>> v1.0 - so let’s keep it simple and define that buffers (and thus
> buffer
> >>>>>>> pools) are always unsegmented. Segmentation comes into play only
> with
> >>>>>>> packets (and only with those packets that cannot fit into a single
> buffer).
> >>>>>>> For example, if implementation has max buffer size 256, any
> packets larger
> >>>>>>> than that are segmented and segments are handled with
> packet_seg_xxx calls.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> Also, I’d propose that we optimize for the common case (with
> segments)
> >>>>>>> - so that the odp_packet_t handle would refer always to the head
> of packet
> >>>>>>> segment. If the first segment (data/data_len pointed by the
> odp_packet_t)
> >>>>>>> carries all data application is interested in (=protocol headers),
> the
> >>>>>>> application would not have to use the segment API at all. Most
> applications
> >>>>>>> would not see any difference between small/large or
> segmented/unsegmented
> >>>>>>> packets as long as all headers fit into the first segment.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> -Petri
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> From: lng-odp-bounces@lists.linaro.org
> >>>>>>> [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of ext Jacob,
> Jerin
> >>>>>>> Sent: Friday, October 17, 2014 9:34 AM
> >>>>>>> To: Bill Fischofer
> >>>>>>> Cc: lng-odp@lists.linaro.org
> >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
> API
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> The need for segment API infrastructure is very clear.The question
> is,
> >>>>>>> Do we need separate APIs for
> >>>>>>>
> >>>>>>> segment management at odp_buffer_segment* AND odp_packet_segment*
> >>>>>>> levels ?
> >>>>>>>
> >>>>>>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always
> >>>>>>> unsegmented and if there is a
> >>>>>>>
> >>>>>>> API for odp_packet_segement* then there will be not be any consumer
> >>>>>>> for odp_buffer_segment* API for 1.0
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> ________________________________
> >>>>>>>
> >>>>>>> From: Bill Fischofer <bill.fischofer@linaro.org>
> >>>>>>> Sent: Thursday, October 16, 2014 9:08 PM
> >>>>>>> To: Jacob, Jerin
> >>>>>>> Cc: Ola Liljedahl; Balasubramanian Manoharan;
> lng-odp@lists.linaro.org
> >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
> API
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> From the buffer design doc (p. 8-9):
> >>>>>>>
> >>>>>>> Buffer Pool Options
> >>>>>>>
> >>>>>>> The odp_buffer_opts_e enum is used to specify additional options
> >>>>>>> relating to the buffer pool.  Buffer pool options defined are:
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> ·     ODP_BUFFER_OPTS_NONE
> >>>>>>>
> >>>>>>> ·     ODP_BUFFER_OPTS_UNSEGMENTED
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> These options are additive so an application can simply specify a
> >>>>>>> buf_opts by ORing together the options needed.  Note that buffer
> pool
> >>>>>>> options are themselves OPTIONAL and a given implementation MAY
> fail the
> >>>>>>> buffer pool creation request with an appropriate errno if the
> requested
> >>>>>>> option is not supported by the underlying ODP implementation, with
> the
> >>>>>>> exception that UNSEGMENTED pools MUST be supported for non-packet
> types and
> >>>>>>> for packet types as long as the requested size is less than the
> >>>>>>> implementation-defined native packet segment size.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options
> with
> >>>>>>> no additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies
> that the
> >>>>>>> buffer pool should be unsegmented.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> So unsegmented buffer pool support is available.  As far as RAW
> >>>>>>> buffers go, again from the doc (p. 14):
> >>>>>>>
> >>>>>>> ODP_BUFFER_TYPE_RAW
> >>>>>>>
> >>>>>>> This is the “basic” buffer type which simply consists of a single
> >>>>>>> fixed-sized block of contiguous memory.  Buffers of this type do
> not support
> >>>>>>> user meta data and the only built-in meta data supported for this
> type of
> >>>>>>> buffer are those that are statically computable, such as pool and
> size. This
> >>>>>>> type of buffer is entirely under application control and most of
> the buffer
> >>>>>>> APIs defined in this document are not available.  APIs for this
> type of
> >>>>>>> buffer are described in this document.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> So RAW buffers are always unsegmented.  The intent is that Packets
> are
> >>>>>>> by default segmented but can be unsegmented while the other buffer
> types are
> >>>>>>> by default unsegmented but (with the exception of RAW buffers) can
> be made
> >>>>>>> segmented.  This is because all buffers start out as a single
> segment and
> >>>>>>> hence are unsegmented until they are expanded to overflow that
> single
> >>>>>>> segment.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> Hope that clarifies things.  Again, this is all very
> straightforward
> >>>>>>> and only comes into play when actually needed.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin
> >>>>>>> <Jerin.Jacob@caviumnetworks.com> wrote:
> >>>>>>>
> >>>>>>> If there is no valid use case for supporting segmentation for raw
> >>>>>>> buffers then lets drop it. At least it will reduce the effort of
> >>>>>>>
> >>>>>>> implementing and testing/verification buffer APIs on  different
> >>>>>>> platforms.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> ________________________________
> >>>>>>>
> >>>>>>> From: lng-odp-bounces@lists.linaro.org
> >>>>>>> <lng-odp-bounces@lists.linaro.org> on behalf of Ola Liljedahl
> >>>>>>> <ola.liljedahl@linaro.org>
> >>>>>>> Sent: Wednesday, October 8, 2014 1:37 PM
> >>>>>>> To: Balasubramanian Manoharan
> >>>>>>> Cc: lng-odp@lists.linaro.org
> >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
> API
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> As I wrote in my comment to the architecture discussion yesterday,
> I
> >>>>>>> am against segmentation for buffers. Or at least there must be the
> >>>>>>> possibility to create a buffer pool with guaranteed non-segmented
> buffers.
> >>>>>>> Segmented packets are OK but not all usages for buffers relate to
> packets. A
> >>>>>>> lot of internal usages (timeouts, SW messages, internal data
> structures)
> >>>>>>> will not be able to handle segmented buffers so you must be able
> to force
> >>>>>>> the creation of buffer pools with non-segmented buffers.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> -- Ola
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> On 8 October 2014 09:50, Balasubramanian Manoharan
> >>>>>>> <bala.manoharan@linaro.org> wrote:
> >>>>>>>
> >>>>>>> This patch contains ODP Buffer Management missing APIs
> >>>>>>> The intent of this patch is to port the missing APIs from Buffer
> >>>>>>> Management design document into Linux-generic repo.
> >>>>>>> The dummy functions will be replaced during linux-generic
> >>>>>>> implementation.
> >>>>>>>
> >>>>>>> Signed-off-by: Balasubramanian Manoharan <
> bala.manoharan@linaro.org>
> >>>>>>> ---
> >>>>>>>  platform/linux-generic/include/api/odp_buffer.h    | 203
> >>>>>>> ++++++++++++++++++++-
> >>>>>>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
> >>>>>>>  platform/linux-generic/odp_buffer.c                | 120
> ++++++++++++
> >>>>>>>  platform/linux-generic/odp_buffer_pool.c           |   7 +
> >>>>>>>  4 files changed, 351 insertions(+), 9 deletions(-)
> >>>>>>>
> >>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer.h
> >>>>>>> b/platform/linux-generic/include/api/odp_buffer.h
> >>>>>>> index d8577fd..aeb75ed 100644
> >>>>>>> --- a/platform/linux-generic/include/api/odp_buffer.h
> >>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer.h
> >>>>>>> @@ -28,8 +28,34 @@ extern "C" {
> >>>>>>>   */
> >>>>>>>  typedef uint32_t odp_buffer_t;
> >>>>>>>
> >>>>>>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
> >>>>>>> +/**
> >>>>>>> +* ODP buffer segment
> >>>>>>> +*/
> >>>>>>> +typedef uint32_t odp_buffer_segment_t;
> >>>>>>>
> >>>>>>> +/**
> >>>>>>> +* ODP buffer type
> >>>>>>> +*/
> >>>>>>> +typedef enum odp_buffer_type {
> >>>>>>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */
> >>>>>>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold
> any
> >>>>>>> other
> >>>>>>> +                                       buffer type */
> >>>>>>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
> >>>>>>> +                                       no additional metadata */
> >>>>>>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
> >>>>>>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
> >>>>>>> +} odp_buffer_type_e;
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> +* ODP buffer options
> >>>>>>> +*/
> >>>>>>> +typedef enum odp_buffer_opts {
> >>>>>>> +       ODP_BUFFER_OPTS_NONE,
> >>>>>>> +       ODP_BUFFER_OPTS_UNSEGMENTED
> >>>>>>> +} odp_buffer_opts_e;
> >>>>>>> +
> >>>>>>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
> >>>>>>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
> >>>>>>>
> >>>>>>>  /**
> >>>>>>>   * Buffer start address
> >>>>>>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
> >>>>>>>   */
> >>>>>>>  int odp_buffer_type(odp_buffer_t buf);
> >>>>>>>
> >>>>>>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
> >>>>>>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any
> >>>>>>> other
> >>>>>>> -                                         buffer type */
> >>>>>>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no
> additional
> >>>>>>> metadata */
> >>>>>>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
> >>>>>>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
> >>>>>>> -
> >>>>>>> -
> >>>>>>>  /**
> >>>>>>>   * Tests if buffer is valid
> >>>>>>>   *
> >>>>>>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
> >>>>>>>  int odp_buffer_is_valid(odp_buffer_t buf);
> >>>>>>>
> >>>>>>>  /**
> >>>>>>> + * Tests if buffer is segmented
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle
> >>>>>>> + *
> >>>>>>> + * @return             1 if buffer has more than one segment,
> >>>>>>> + *                     otherwise 0
> >>>>>>> + */
> >>>>>>> +
> >>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Get address and size of user meta data associated with a buffer
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf             Buffer handle
> >>>>>>> + * @param[out] udata_size      Number of bytes of user meta data
> >>>>>>> available
> >>>>>>> + *                             at the returned address
> >>>>>>> + * @return                     Address of the user meta data for
> this
> >>>>>>> buffer
> >>>>>>> + *                             or NULL if the buffer has no user
> meta
> >>>>>>> data.
> >>>>>>> + */
> >>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Get address of user meta data associated with a buffer
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle
> >>>>>>> + *
> >>>>>>> + * @return             Address of the user meta data for this
> buffer
> >>>>>>> + *                     or NULL if the buffer has no user meta
> data.
> >>>>>>> + */
> >>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Get count of number of segments in a buffer
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle
> >>>>>>> + *
> >>>>>>> + * @return             Count of the number of segments in buf
> >>>>>>> + */
> >>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Get the segment identifier for a buffer segment by index
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle
> >>>>>>> + * @param[in]  ndx     Segment index of segment of interest
> >>>>>>> + *
> >>>>>>> + * @return             Segment identifier or ODP_SEGMENT_INVALID
> if
> >>>>>>> the
> >>>>>>> + *                     supplied ndx is out of range.
> >>>>>>> + */
> >>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
> >>>>>>> size_t ndx);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Get the next segment identifier for a buffer segment
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle
> >>>>>>> + * @param[in]  seg     Segment identifier of the previous segment
> >>>>>>> + *
> >>>>>>> + * @return             Segment identifier of the next segment,
> >>>>>>> +                       or ODP_SEGMENT_INVALID.
> >>>>>>> + */
> >>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
> >>>>>>> +                                            odp_buffer_segment_t
> >>>>>>> seg);
> >>>>>>> +/**
> >>>>>>> + * Get start address for a specified buffer segment
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle
> >>>>>>> + * @param[in]  seg     Segment identifier of the buffer to be
> >>>>>>> addressed
> >>>>>>> + * @param[out] seglen  Returned number of bytes in this buffer
> >>>>>>> + *                     segment available at returned address
> >>>>>>> + *
> >>>>>>> + * @return             Segment start address or NULL
> >>>>>>> + */
> >>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf,
> odp_buffer_segment_t
> >>>>>>> seg,
> >>>>>>> +size_t *seglen);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + *Unmap a buffer segment
> >>>>>>> + *
> >>>>>>> + * @param[in]  seg     Buffer segment handle
> >>>>>>> + */
> >>>>>>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> +* Get start address for a specified buffer offset
> >>>>>>> +*
> >>>>>>> +* @param[in]   buf     Buffer handle
> >>>>>>> +* @param[in]   offset  Byte offset within the buffer to be
> addressed
> >>>>>>> +* @param[out]  seglen  Returned number of bytes in this buffer
> >>>>>>> +*                      segment available at returned address
> >>>>>>> +*
> >>>>>>> +* @return              Offset start address or NULL
> >>>>>>> +*/
> >>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
> >>>>>>> +size_t *seglen);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Unmap a buffer segment by offset
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle
> >>>>>>> + * @param[in]  offset  Buffer offset
> >>>>>>> + */
> >>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>>   * Print buffer metadata to STDOUT
> >>>>>>>   *
> >>>>>>>   * @param buf      Buffer handle
> >>>>>>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
> >>>>>>>   */
> >>>>>>>  void odp_buffer_print(odp_buffer_t buf);
> >>>>>>>
> >>>>>>> +/**
> >>>>>>> + * Split a buffer into two buffers at a specified split point
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Handle of buffer to split
> >>>>>>> + * @param[in]  offset  Byte offset within buf to split buffer
> >>>>>>> + *
> >>>>>>> + * @return             Buffer handle of the created split buffer
> >>>>>>> + */
> >>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Join two buffers into a single buffer
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf1    Buffer handle of first buffer to join
> >>>>>>> + * @param[in]  buf2    Buffer handle of second buffer to join
> >>>>>>> + *
> >>>>>>> + * @return             Buffer handle of the joined buffer
> >>>>>>> + */
> >>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t
> buf2);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Trim a buffer at a specified trim point
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle of buffer to trim
> >>>>>>> + * @param[in]  offset  byte offset within buf to trim
> >>>>>>> + *
> >>>>>>> + * @return             Handle of the trimmed buffer or
> >>>>>>> + *                     ODP_BUFFER_INVALID if the operation was not
> >>>>>>> performed
> >>>>>>> + */
> >>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
> >>>>>>> +/**
> >>>>>>> + * Extend a buffer for a specified number of bytes
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle of buffer to expand
> >>>>>>> + * @param[in]  ext     size, in bytes, of the extent to add to the
> >>>>>>> + *                     existing buffer.
> >>>>>>> + *
> >>>>>>> + * @return             Handle of the extended buffer or
> >>>>>>> ODP_BUFFER_INVALID
> >>>>>>> + *                     if the operation was not performed
> >>>>>>> + */
> >>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Clone a buffer, returning an exact copy of it
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle of buffer to duplicate
> >>>>>>> + *
> >>>>>>> + * @return             Handle of the duplicated buffer or
> >>>>>>> ODP_BUFFER_INVALID
> >>>>>>> + *                     if the operation was not performed
> >>>>>>> + */
> >>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Copy a buffer, returning an exact copy of it
> >>>>>>> + *
> >>>>>>> + * @param[in]  buf     Buffer handle of buffer to copy
> >>>>>>> + *
> >>>>>>> + * @return             Handle of the copied buffer or
> >>>>>>> ODP_BUFFER_INVALID
> >>>>>>> + *                     if the operation was not performed
> >>>>>>> + */
> >>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
> >>>>>>> +
> >>>>>>> +
> >>>>>>>
> >>>>>>>  #ifdef __cplusplus
> >>>>>>>  }
> >>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
> >>>>>>> b/platform/linux-generic/include/api/odp_buffer_pool.h
> >>>>>>> index fe88898..f85d96c 100644
> >>>>>>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
> >>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
> >>>>>>> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const
> char
> >>>>>>> *name,
> >>>>>>>
> >>>>>>>
> >>>>>>>  /**
> >>>>>>> + * Get the next buffer pool from its predecessor
> >>>>>>> + *
> >>>>>>> + * @param[in]  pool            Buffer pool handle
> >>>>>>> + * @param[out] name            Name of the pool
> >>>>>>> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1
> >>>>>>> chars)
> >>>>>>> + * @param[out] udata_size      Size of user meta data used by this
> >>>>>>> pool.
> >>>>>>> + * @param[out] buf_num         Number of buffers contained in this
> >>>>>>> pool
> >>>>>>> + * @param[out] buf_size        Default size of application data in
> >>>>>>> each buffer
> >>>>>>> + * @param[out] buf_type        Buffer type of the pool
> >>>>>>> + * @param[out] buf_opts        Buffer options for this pool
> >>>>>>> + * @param[out] predef          Predefined (1) or Created (0).
> >>>>>>> + *
> >>>>>>> + * @return                     Buffer pool handle
> >>>>>>> + */
> >>>>>>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
> >>>>>>> +                                      char *name, size_t
> *udata_size,
> >>>>>>> +                                      size_t *buf_num, size_t
> >>>>>>> *buf_size,
> >>>>>>> +                                      enum odp_buffer_type
> *buf_type,
> >>>>>>> +                                      enum odp_buffer_opts
> *buf_opts,
> >>>>>>> +                                      uint32_t *predef);
> >>>>>>> +/**
> >>>>>>>   * Find a buffer pool by name
> >>>>>>>   *
> >>>>>>>   * @param name      Name of the pool
> >>>>>>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t
> >>>>>>> pool);
> >>>>>>>   */
> >>>>>>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
> >>>>>>>
> >>>>>>> +/**
> >>>>>>> +* Allocate a buffer from a buffer pool
> >>>>>>> +*
> >>>>>>> +* @param[in]   pool    Pool handle
> >>>>>>> +* @param[in]   size    Size of object to store in buffer
> >>>>>>> +*
> >>>>>>> +* @return              Buffer handle or ODP_BUFFER_INVALID
> >>>>>>> +*/
> >>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t
> >>>>>>> size);
> >>>>>>>
> >>>>>>>  /**
> >>>>>>>   * Buffer free
> >>>>>>> diff --git a/platform/linux-generic/odp_buffer.c
> >>>>>>> b/platform/linux-generic/odp_buffer.c
> >>>>>>> index e54e0e7..7f4b4f0 100644
> >>>>>>> --- a/platform/linux-generic/odp_buffer.c
> >>>>>>> +++ b/platform/linux-generic/odp_buffer.c
> >>>>>>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
> >>>>>>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
> >>>>>>>  }
> >>>>>>>
> >>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf)
> >>>>>>> +{
> >>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
> >>>>>>> +
> >>>>>>> +       if (buf_hdr->scatter.num_bufs == 0)
> >>>>>>> +               return 0;
> >>>>>>> +       else
> >>>>>>> +               return 1;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf)
> >>>>>>> +{
> >>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
> >>>>>>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
> >>>>>>> +}
> >>>>>>>
> >>>>>>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
> >>>>>>>  {
> >>>>>>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
> >>>>>>>         printf("\n%s\n", str);
> >>>>>>>  }
> >>>>>>>
> >>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)udata_size;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
> >>>>>>> +                                                size_t ndx)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)ndx;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
> >>>>>>> +                                            odp_buffer_segment_t
> seg)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)seg;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf,
> odp_buffer_segment_t
> >>>>>>> seg,
> >>>>>>> +                            size_t *seglen)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)seg;
> >>>>>>> +       (void)seglen;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
> >>>>>>> +size_t *seglen)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)offset;
> >>>>>>> +       (void)seglen;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)offset;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t
> >>>>>>> buf_src)
> >>>>>>>  {
> >>>>>>>         (void)buf_dst;
> >>>>>>>         (void)buf_src;
> >>>>>>>  }
> >>>>>>> +
> >>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)offset;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
> >>>>>>> +{
> >>>>>>> +       (void)buf1;
> >>>>>>> +       (void)buf2;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)offset;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       (void)ext;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
> >>>>>>> +{
> >>>>>>> +       (void)buf;
> >>>>>>> +       ODP_UNIMPLEMENTED();
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> diff --git a/platform/linux-generic/odp_buffer_pool.c
> >>>>>>> b/platform/linux-generic/odp_buffer_pool.c
> >>>>>>> index a48d7d6..bff4db5 100644
> >>>>>>> --- a/platform/linux-generic/odp_buffer_pool.c
> >>>>>>> +++ b/platform/linux-generic/odp_buffer_pool.c
> >>>>>>> @@ -471,6 +471,13 @@ odp_buffer_t
> odp_buffer_alloc(odp_buffer_pool_t
> >>>>>>> pool_hdl)
> >>>>>>>         return handle.u32;
> >>>>>>>  }
> >>>>>>>
> >>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t
> >>>>>>> size)
> >>>>>>> +{
> >>>>>>> +       (void)pool;
> >>>>>>> +       (void) size;
> >>>>>>> +       ODP_ERR("%s function is yet to be implemented", __func__);
> >>>>>>> +       return 0;
> >>>>>>> +}
> >>>>>>>
> >>>>>>>  void odp_buffer_free(odp_buffer_t buf)
> >>>>>>>  {
> >>>>>>> --
> >>>>>>> 2.0.1.472.g6f92e5f
> >>>>>>>
> >>>>>>>
> >>>>>>> _______________________________________________
> >>>>>>> lng-odp mailing list
> >>>>>>> lng-odp@lists.linaro.org
> >>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> _______________________________________________
> >>>>>>> lng-odp mailing list
> >>>>>>> lng-odp@lists.linaro.org
> >>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>> _______________________________________________
> >>>>>> lng-odp mailing list
> >>>>>> lng-odp@lists.linaro.org
> >>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
> >>>>>>
> >>>>>
> >>>>>
> >>>>> _______________________________________________
> >>>>> lng-odp mailing list
> >>>>> lng-odp@lists.linaro.org
> >>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
> >>>>>
> >>>>
> >>>
> >>
> >>
> >> _______________________________________________
> >> lng-odp mailing list
> >> lng-odp@lists.linaro.org
> >> http://lists.linaro.org/mailman/listinfo/lng-odp
> >>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
>
>
Savolainen, Petri (NSN - FI/Espoo) Oct. 22, 2014, 1:34 p.m. UTC | #17
It indicates that application is not going to share it. Requirement to be private would be tighter requirement (== another flag, but not needed right now I think).

-Petri


From: ext Alexandru Badicioiu [mailto:alexandru.badicioiu@linaro.org]

Sent: Wednesday, October 22, 2014 4:27 PM
To: Savolainen, Petri (NSN - FI/Espoo)
Cc: Ciprian Barbu; Bill Fischofer; lng-odp@lists.linaro.org
Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API

Thanks for clarification. Regarding the sharing, is 0 specifying that the application does not require sharing or is a requirement for that segment to be private?

Alex


On 22 October 2014 16:18, Savolainen, Petri (NSN - FI/Espoo) <petri.savolainen@nsn.com<mailto:petri.savolainen@nsn.com>> wrote:
0 is the default => with current flag definitions: both SW + HW can access,  not shared with external processes.

-Petri

From: ext Alexandru Badicioiu [mailto:alexandru.badicioiu@linaro.org<mailto:alexandru.badicioiu@linaro.org>]

Sent: Wednesday, October 22, 2014 4:01 PM
To: Ciprian Barbu
Cc: Bill Fischofer; Savolainen, Petri (NSN - FI/Espoo); lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API

The option of creating buffer pools out of memory regions does not solve existing applications portability problem. The odp_pktio application expects packets to be allocated in shared memory regions. Is this a semantic that should be satisfied by all platforms?
 odp_shm_create takes a flag argument which has two values for linux-generic:
/*
 * Shared memory flags
 */

/* Share level */
#define ODP_SHM_SW_ONLY 0x1 /**< Application SW only, no HW access */
#define ODP_SHM_PROC    0x2 /**< Share with external processes */

but odp_pktio uses 0. Could we assume that this value has a kind of ODP_SHM_PACKET meaning?
We could also explicitly extend this flag list to work across platforms.

Alex





On 22 October 2014 14:59, Ciprian Barbu <ciprian.barbu@linaro.org<mailto:ciprian.barbu@linaro.org>> wrote:
On Wed, Oct 22, 2014 at 2:47 PM, Ciprian Barbu <ciprian.barbu@linaro.org<mailto:ciprian.barbu@linaro.org>> wrote:
> This thread has been cold for 5 days, so the assumption is that we can

> go forward with the design right now. This patch series proposed by

> Bala updates some part of the API to the final form of the Buffer

> Design Document, we should have it merged if there are no more

> objections. For that more people with the right expertise should have

> a look at it and get the thread back on track.

>

> I for example have observed the following issue. All the examples

> create buffer pools over shared memory, which doesn't make sense for

> some platforms, linux-dpdk for example, which ignores the base_addr

> argument altogether. I think we need more clarity on this subject, for

> sure the creation of buffer pools will differ from platform to

> platform, which migrates to the application responsibility.

>

> I think we should have a helper function to easily create buffer pools

> without worrying too much about the difference in buffer management

> between platforms, so that one can write a simple portable application

> with no sweat. For the hardcore programmers the API still gives fine

> control to buffer management that depending on the platform could

> involve additional prerequisites, like creating a shared memory

> segment to hold the buffer pool.


Ok, so I had another look at the Buffer Management final design. I now
see that the option of creating buffer pools from regions has been
removed, so in this case things will be simpler for the applications.
In other words we should really start working on the full
implementation of the API because from there the problem I just stated
above (having to create shared memory segments) will disappear.

>

> On Fri, Oct 17, 2014 at 4:33 PM, Bill Fischofer

> <bill.fischofer@linaro.org<mailto:bill.fischofer@linaro.org>> wrote:

>> Let's consider the implications of removing segmentation support from

>> buffers and only having that concept be part of packets.

>>

>> The first question that arises is what is the relationship between the

>> abstract types odp_packet_t and odp_buffer_t? This is important because

>> currently we say that packets are allocated from ODP buffer pools, not from

>> packet pools.  Do we need a separate odp_packet_pool_t that is used for

>> packets?

>>

>> Today, when I allocate a packet I'm allocating a single object that happens

>> to be a single buffer object of type ODP_BUFFER_TYPE_PACKET.  But that only

>> works if the two objects have compatible semantics (including segmentation).

>> If the semantics are not compatible, then an odp_packet_t may in fact be

>> composed of multiple odp_buffer_t's because the packet may consist of

>> multiple segments and buffers no longer recognize the concept of segments so

>> a single buffer can only be a single segment.

>>

>> So now an odp_packet_segment_t may be an odp_buffer_t but an odp_packet_t in

>> fact is some meta-object that is constructed (by whom?) from multiple

>> odp_packet_segment_ts that are themselves odp_buffer_ts.  So

>> odp_packet_to_buffer() no longer makes sense since there is no longer a

>> one-to-one correspondence between packets and buffers.  We could have an

>> odp_packet_segment_to_buffer() routine instead.

>>

>> Next question: What about meta data?  If an odp_packet_t is a type of an

>> odp_buffer_t then this is very straightforward since all buffer meta data is

>> reusable as packet meta data and the packet type can just add its own

>> specific meta data to this set.  But if an odp_packet_t is now a separate

>> object then where does the storage for its meta data come from? If we try to

>> map it into an odp_buffer_t that doesn't work since an odp_packet_t may

>> consist of multiple underlying odp_buffer_ts, one for each

>> odp_packet_segment_t.  Is the packet meta data duplicated in each segment?

>> Is the first segment of a packet special (odp_packet_first_segment_t)?  And

>> what about user meta data, since this is of potentially variable size?

>>

>> I submit that there are a lot of implications to this that need to be fully

>> thought through, which is why I believe it's simpler to keep segmentation as

>> part of buffers that (for now) only happens to be used by a particular type

>> of buffer, namely packets.

>>

>> Bill

>>

>> On Fri, Oct 17, 2014 at 8:05 AM, Ola Liljedahl <ola.liljedahl@linaro.org<mailto:ola.liljedahl@linaro.org>>

>> wrote:

>>>

>>> Personally I don't see any need for segmentation support in buffers. I am

>>> just trying to shoot down what I think is flawed reasoning.

>>>

>>> -- Ola#1

>>>

>>> On 17 October 2014 15:03, Ola Liljedahl <ola.liljedahl@linaro.org<mailto:ola.liljedahl@linaro.org>> wrote:

>>>>

>>>> But segmentation is already needed in a current and known subclass (i.e.

>>>> packets). We are not talking about some other feature which we don't know if

>>>> it will be needed. So this is not a case of "just in case".

>>>>

>>>> -- Ola#1

>>>>

>>>>

>>>> On 17 October 2014 14:45, Ola Dahl <dahl.ola@gmail.com<mailto:dahl.ola@gmail.com>> wrote:

>>>>>

>>>>> Hi,

>>>>>

>>>>> I do not think it is wise to put features in the base class "just in

>>>>> case" they would be needed in some future (not yet known) subclass.

>>>>>

>>>>> So if the concept of segmentation is relevant for packets but not for

>>>>> timers then I think it should be implemented as a feature of packets.

>>>>>

>>>>> Best regards,

>>>>>

>>>>> Ola D

>>>>>

>>>>> On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer

>>>>> <bill.fischofer@linaro.org<mailto:bill.fischofer@linaro.org>> wrote:

>>>>>>

>>>>>> I agree that packets are the buffer type that most likely uses

>>>>>> segments, however there are many advantages to putting this support in the

>>>>>> base class rather than the subclass independent of the number of buffer

>>>>>> subclasses that will use this support today.

>>>>>>

>>>>>> It's simpler

>>>>>> It's more extensible

>>>>>> It results in cleaner and more efficient application code

>>>>>>

>>>>>> Allow me to expand on these points.  First simplicity.  Call the work

>>>>>> required to support segmentation in the implementation X.  That X is going

>>>>>> to be pretty much constant no matter where it is done.  But if the

>>>>>> implementation has a choice between doing X at a low level vs. doing it at a

>>>>>> high level then it's simpler for the implementation to do it once and be

>>>>>> done with it.  If the implementation does it at a higher level then it is

>>>>>> either constrained to map that higher-level implementation to be built on a

>>>>>> set of lower-level functions that may or may not be appropriate or else it

>>>>>> needs to do a completely parallel implementation that is optimal but highly

>>>>>> duplicative.

>>>>>>

>>>>>> Extensibility should be clear.  If at some future point we decide

>>>>>> segmentation would be useful for some new buffer type (e.g., IPC) then

>>>>>> that's trivial to do if the base class supports it and awkward if it's only

>>>>>> part of packets.

>>>>>>

>>>>>> From an application standpoint, it's cleaner because the packet APIs

>>>>>> are just wrappers around their corresponding buffer APIs and can be mapped

>>>>>> directly.  Otherwise we have a set of APIs that don't map and are not easily

>>>>>> translatable.

>>>>>>

>>>>>> With regard to efficient segment access, that's what the

>>>>>> odp_packet_addr() routine provides--one-step fast-path addressability to the

>>>>>> first segment of a packet.  An odp_packet_t is an abstract opaque type.  It

>>>>>> is not, and cannot be treated as an address by the application.

>>>>>>

>>>>>> Does that make sense?

>>>>>>

>>>>>> Bill

>>>>>>

>>>>>>

>>>>>>

>>>>>>

>>>>>> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN - FI/Espoo)

>>>>>> <petri.savolainen@nsn.com<mailto:petri.savolainen@nsn.com>> wrote:

>>>>>>>

>>>>>>> Hi,

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> 1. The only segmentation use case is for segmented packet, not for

>>>>>>> segmented buffers.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> 2. Common case for packets is that everything application needs is in

>>>>>>> the first segment. Odp_packet_t could refer always into that “first

>>>>>>> segment”, so that application (in the common case) would not need to use

>>>>>>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> When buffer level features are minimized, the need for

>>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All packet

>>>>>>> manipulation should happen through odp_packet_xxx(pkt, …) calls.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> -Petri

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> From: ext Bill Fischofer [mailto:bill.fischofer@linaro.org<mailto:bill.fischofer@linaro.org>]

>>>>>>> Sent: Friday, October 17, 2014 1:17 PM

>>>>>>> To: Savolainen, Petri (NSN - FI/Espoo)

>>>>>>> Cc: ext Jacob, Jerin; lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>>>>

>>>>>>>

>>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> I'm not sure how to understand these two statements:

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> 1. There's no use case for segmented buffers

>>>>>>>

>>>>>>> 2. We should optimize for the common case (with segments)

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> These seem contradictory.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> The use case for segmented buffers is that some platforms have a

>>>>>>> HW-defined and managed segmented buffer model. If we insist that the

>>>>>>> application be able to specify and control packet segment sizes we are

>>>>>>> making the decision to exclude such platforms from supporting ODP.  The

>>>>>>> optimization suggested is precisely what is being proposed here.  By default

>>>>>>> packets are assumed to be contained in implementation-managed segmented

>>>>>>> buffers and the first segment will be large enough to contain all packet

>>>>>>> headers for non-pathological cases.  The case where the application wishes

>>>>>>> to traverse the entire packet in SW is expected to be rare because in the

>>>>>>> data plane you simply do not have the cycles to do this at line rate for all

>>>>>>> packets.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs, this is

>>>>>>> simply syntax to avoid the constant need for explicit conversion functions

>>>>>>> since unlike C++, C does not support generic functions.  So you cannot pass

>>>>>>> an odp_packet_t to a function that expects an odp_buffer_t argument without

>>>>>>> a conversion call.  Do we really want to force applications to constantly be

>>>>>>> writing code like:

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> rather than

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> odp_packet_xxx(pkt,...)

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> Not only is this awkward, it is also inefficient.  By having the

>>>>>>> explicit odp_packet_xxx() calls, the implementation is free to optimize

>>>>>>> these references in whatever manner is appropriate to that implementation.

>>>>>>> For some this may be a simple preprocessor-type expansion while for others

>>>>>>> there may be more sophisticated handling.  But the application should

>>>>>>> neither know nor care about how the implementation chooses to do this.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN - FI/Espoo)

>>>>>>> <petri.savolainen@nsn.com<mailto:petri.savolainen@nsn.com>> wrote:

>>>>>>>

>>>>>>> Hi,

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> This is also my opinion. There’s no use case for segmented buffers in

>>>>>>> v1.0 - so let’s keep it simple and define that buffers (and thus buffer

>>>>>>> pools) are always unsegmented. Segmentation comes into play only with

>>>>>>> packets (and only with those packets that cannot fit into a single buffer).

>>>>>>> For example, if implementation has max buffer size 256, any packets larger

>>>>>>> than that are segmented and segments are handled with packet_seg_xxx calls.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> Also, I’d propose that we optimize for the common case (with segments)

>>>>>>> - so that the odp_packet_t handle would refer always to the head of packet

>>>>>>> segment. If the first segment (data/data_len pointed by the odp_packet_t)

>>>>>>> carries all data application is interested in (=protocol headers), the

>>>>>>> application would not have to use the segment API at all. Most applications

>>>>>>> would not see any difference between small/large or segmented/unsegmented

>>>>>>> packets as long as all headers fit into the first segment.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> -Petri

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> From: lng-odp-bounces@lists.linaro.org<mailto:lng-odp-bounces@lists.linaro.org>

>>>>>>> [mailto:lng-odp-bounces@lists.linaro.org<mailto:lng-odp-bounces@lists.linaro.org>] On Behalf Of ext Jacob, Jerin

>>>>>>> Sent: Friday, October 17, 2014 9:34 AM

>>>>>>> To: Bill Fischofer

>>>>>>> Cc: lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> The need for segment API infrastructure is very clear.The question is,

>>>>>>> Do we need separate APIs for

>>>>>>>

>>>>>>> segment management at odp_buffer_segment* AND odp_packet_segment*

>>>>>>> levels ?

>>>>>>>

>>>>>>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always

>>>>>>> unsegmented and if there is a

>>>>>>>

>>>>>>> API for odp_packet_segement* then there will be not be any consumer

>>>>>>> for odp_buffer_segment* API for 1.0

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> ________________________________

>>>>>>>

>>>>>>> From: Bill Fischofer <bill.fischofer@linaro.org<mailto:bill.fischofer@linaro.org>>

>>>>>>> Sent: Thursday, October 16, 2014 9:08 PM

>>>>>>> To: Jacob, Jerin

>>>>>>> Cc: Ola Liljedahl; Balasubramanian Manoharan; lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> From the buffer design doc (p. 8-9):

>>>>>>>

>>>>>>> Buffer Pool Options

>>>>>>>

>>>>>>> The odp_buffer_opts_e enum is used to specify additional options

>>>>>>> relating to the buffer pool.  Buffer pool options defined are:

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> ·     ODP_BUFFER_OPTS_NONE

>>>>>>>

>>>>>>> ·     ODP_BUFFER_OPTS_UNSEGMENTED

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> These options are additive so an application can simply specify a

>>>>>>> buf_opts by ORing together the options needed.  Note that buffer pool

>>>>>>> options are themselves OPTIONAL and a given implementation MAY fail the

>>>>>>> buffer pool creation request with an appropriate errno if the requested

>>>>>>> option is not supported by the underlying ODP implementation, with the

>>>>>>> exception that UNSEGMENTED pools MUST be supported for non-packet types and

>>>>>>> for packet types as long as the requested size is less than the

>>>>>>> implementation-defined native packet segment size.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options with

>>>>>>> no additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies that the

>>>>>>> buffer pool should be unsegmented.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> So unsegmented buffer pool support is available.  As far as RAW

>>>>>>> buffers go, again from the doc (p. 14):

>>>>>>>

>>>>>>> ODP_BUFFER_TYPE_RAW

>>>>>>>

>>>>>>> This is the “basic” buffer type which simply consists of a single

>>>>>>> fixed-sized block of contiguous memory.  Buffers of this type do not support

>>>>>>> user meta data and the only built-in meta data supported for this type of

>>>>>>> buffer are those that are statically computable, such as pool and size. This

>>>>>>> type of buffer is entirely under application control and most of the buffer

>>>>>>> APIs defined in this document are not available.  APIs for this type of

>>>>>>> buffer are described in this document.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> So RAW buffers are always unsegmented.  The intent is that Packets are

>>>>>>> by default segmented but can be unsegmented while the other buffer types are

>>>>>>> by default unsegmented but (with the exception of RAW buffers) can be made

>>>>>>> segmented.  This is because all buffers start out as a single segment and

>>>>>>> hence are unsegmented until they are expanded to overflow that single

>>>>>>> segment.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> Hope that clarifies things.  Again, this is all very straightforward

>>>>>>> and only comes into play when actually needed.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin

>>>>>>> <Jerin.Jacob@caviumnetworks.com<mailto:Jerin.Jacob@caviumnetworks.com>> wrote:

>>>>>>>

>>>>>>> If there is no valid use case for supporting segmentation for raw

>>>>>>> buffers then lets drop it. At least it will reduce the effort of

>>>>>>>

>>>>>>> implementing and testing/verification buffer APIs on  different

>>>>>>> platforms.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> ________________________________

>>>>>>>

>>>>>>> From: lng-odp-bounces@lists.linaro.org<mailto:lng-odp-bounces@lists.linaro.org>

>>>>>>> <lng-odp-bounces@lists.linaro.org<mailto:lng-odp-bounces@lists.linaro.org>> on behalf of Ola Liljedahl

>>>>>>> <ola.liljedahl@linaro.org<mailto:ola.liljedahl@linaro.org>>

>>>>>>> Sent: Wednesday, October 8, 2014 1:37 PM

>>>>>>> To: Balasubramanian Manoharan

>>>>>>> Cc: lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> As I wrote in my comment to the architecture discussion yesterday, I

>>>>>>> am against segmentation for buffers. Or at least there must be the

>>>>>>> possibility to create a buffer pool with guaranteed non-segmented buffers.

>>>>>>> Segmented packets are OK but not all usages for buffers relate to packets. A

>>>>>>> lot of internal usages (timeouts, SW messages, internal data structures)

>>>>>>> will not be able to handle segmented buffers so you must be able to force

>>>>>>> the creation of buffer pools with non-segmented buffers.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> -- Ola

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> On 8 October 2014 09:50, Balasubramanian Manoharan

>>>>>>> <bala.manoharan@linaro.org<mailto:bala.manoharan@linaro.org>> wrote:

>>>>>>>

>>>>>>> This patch contains ODP Buffer Management missing APIs

>>>>>>> The intent of this patch is to port the missing APIs from Buffer

>>>>>>> Management design document into Linux-generic repo.

>>>>>>> The dummy functions will be replaced during linux-generic

>>>>>>> implementation.

>>>>>>>

>>>>>>> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org<mailto:bala.manoharan@linaro.org>>

>>>>>>> ---

>>>>>>>  platform/linux-generic/include/api/odp_buffer.h    | 203

>>>>>>> ++++++++++++++++++++-

>>>>>>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++

>>>>>>>  platform/linux-generic/odp_buffer.c                | 120 ++++++++++++

>>>>>>>  platform/linux-generic/odp_buffer_pool.c           |   7 +

>>>>>>>  4 files changed, 351 insertions(+), 9 deletions(-)

>>>>>>>

>>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer.h

>>>>>>> b/platform/linux-generic/include/api/odp_buffer.h

>>>>>>> index d8577fd..aeb75ed 100644

>>>>>>> --- a/platform/linux-generic/include/api/odp_buffer.h

>>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer.h

>>>>>>> @@ -28,8 +28,34 @@ extern "C" {

>>>>>>>   */

>>>>>>>  typedef uint32_t odp_buffer_t;

>>>>>>>

>>>>>>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */

>>>>>>> +/**

>>>>>>> +* ODP buffer segment

>>>>>>> +*/

>>>>>>> +typedef uint32_t odp_buffer_segment_t;

>>>>>>>

>>>>>>> +/**

>>>>>>> +* ODP buffer type

>>>>>>> +*/

>>>>>>> +typedef enum odp_buffer_type {

>>>>>>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid */

>>>>>>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold any

>>>>>>> other

>>>>>>> +                                       buffer type */

>>>>>>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,

>>>>>>> +                                       no additional metadata */

>>>>>>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */

>>>>>>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */

>>>>>>> +} odp_buffer_type_e;

>>>>>>> +

>>>>>>> +/**

>>>>>>> +* ODP buffer options

>>>>>>> +*/

>>>>>>> +typedef enum odp_buffer_opts {

>>>>>>> +       ODP_BUFFER_OPTS_NONE,

>>>>>>> +       ODP_BUFFER_OPTS_UNSEGMENTED

>>>>>>> +} odp_buffer_opts_e;

>>>>>>> +

>>>>>>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */

>>>>>>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */

>>>>>>>

>>>>>>>  /**

>>>>>>>   * Buffer start address

>>>>>>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);

>>>>>>>   */

>>>>>>>  int odp_buffer_type(odp_buffer_t buf);

>>>>>>>

>>>>>>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */

>>>>>>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any

>>>>>>> other

>>>>>>> -                                         buffer type */

>>>>>>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional

>>>>>>> metadata */

>>>>>>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */

>>>>>>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */

>>>>>>> -

>>>>>>> -

>>>>>>>  /**

>>>>>>>   * Tests if buffer is valid

>>>>>>>   *

>>>>>>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);

>>>>>>>  int odp_buffer_is_valid(odp_buffer_t buf);

>>>>>>>

>>>>>>>  /**

>>>>>>> + * Tests if buffer is segmented

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle

>>>>>>> + *

>>>>>>> + * @return             1 if buffer has more than one segment,

>>>>>>> + *                     otherwise 0

>>>>>>> + */

>>>>>>> +

>>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Get address and size of user meta data associated with a buffer

>>>>>>> + *

>>>>>>> + * @param[in]  buf             Buffer handle

>>>>>>> + * @param[out] udata_size      Number of bytes of user meta data

>>>>>>> available

>>>>>>> + *                             at the returned address

>>>>>>> + * @return                     Address of the user meta data for this

>>>>>>> buffer

>>>>>>> + *                             or NULL if the buffer has no user meta

>>>>>>> data.

>>>>>>> + */

>>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Get address of user meta data associated with a buffer

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle

>>>>>>> + *

>>>>>>> + * @return             Address of the user meta data for this buffer

>>>>>>> + *                     or NULL if the buffer has no user meta data.

>>>>>>> + */

>>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Get count of number of segments in a buffer

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle

>>>>>>> + *

>>>>>>> + * @return             Count of the number of segments in buf

>>>>>>> + */

>>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Get the segment identifier for a buffer segment by index

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle

>>>>>>> + * @param[in]  ndx     Segment index of segment of interest

>>>>>>> + *

>>>>>>> + * @return             Segment identifier or ODP_SEGMENT_INVALID if

>>>>>>> the

>>>>>>> + *                     supplied ndx is out of range.

>>>>>>> + */

>>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,

>>>>>>> size_t ndx);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Get the next segment identifier for a buffer segment

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle

>>>>>>> + * @param[in]  seg     Segment identifier of the previous segment

>>>>>>> + *

>>>>>>> + * @return             Segment identifier of the next segment,

>>>>>>> +                       or ODP_SEGMENT_INVALID.

>>>>>>> + */

>>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,

>>>>>>> +                                            odp_buffer_segment_t

>>>>>>> seg);

>>>>>>> +/**

>>>>>>> + * Get start address for a specified buffer segment

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle

>>>>>>> + * @param[in]  seg     Segment identifier of the buffer to be

>>>>>>> addressed

>>>>>>> + * @param[out] seglen  Returned number of bytes in this buffer

>>>>>>> + *                     segment available at returned address

>>>>>>> + *

>>>>>>> + * @return             Segment start address or NULL

>>>>>>> + */

>>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t

>>>>>>> seg,

>>>>>>> +size_t *seglen);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + *Unmap a buffer segment

>>>>>>> + *

>>>>>>> + * @param[in]  seg     Buffer segment handle

>>>>>>> + */

>>>>>>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);

>>>>>>> +

>>>>>>> +/**

>>>>>>> +* Get start address for a specified buffer offset

>>>>>>> +*

>>>>>>> +* @param[in]   buf     Buffer handle

>>>>>>> +* @param[in]   offset  Byte offset within the buffer to be addressed

>>>>>>> +* @param[out]  seglen  Returned number of bytes in this buffer

>>>>>>> +*                      segment available at returned address

>>>>>>> +*

>>>>>>> +* @return              Offset start address or NULL

>>>>>>> +*/

>>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,

>>>>>>> +size_t *seglen);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Unmap a buffer segment by offset

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle

>>>>>>> + * @param[in]  offset  Buffer offset

>>>>>>> + */

>>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);

>>>>>>> +

>>>>>>> +/**

>>>>>>>   * Print buffer metadata to STDOUT

>>>>>>>   *

>>>>>>>   * @param buf      Buffer handle

>>>>>>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);

>>>>>>>   */

>>>>>>>  void odp_buffer_print(odp_buffer_t buf);

>>>>>>>

>>>>>>> +/**

>>>>>>> + * Split a buffer into two buffers at a specified split point

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Handle of buffer to split

>>>>>>> + * @param[in]  offset  Byte offset within buf to split buffer

>>>>>>> + *

>>>>>>> + * @return             Buffer handle of the created split buffer

>>>>>>> + */

>>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Join two buffers into a single buffer

>>>>>>> + *

>>>>>>> + * @param[in]  buf1    Buffer handle of first buffer to join

>>>>>>> + * @param[in]  buf2    Buffer handle of second buffer to join

>>>>>>> + *

>>>>>>> + * @return             Buffer handle of the joined buffer

>>>>>>> + */

>>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Trim a buffer at a specified trim point

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle of buffer to trim

>>>>>>> + * @param[in]  offset  byte offset within buf to trim

>>>>>>> + *

>>>>>>> + * @return             Handle of the trimmed buffer or

>>>>>>> + *                     ODP_BUFFER_INVALID if the operation was not

>>>>>>> performed

>>>>>>> + */

>>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);

>>>>>>> +/**

>>>>>>> + * Extend a buffer for a specified number of bytes

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle of buffer to expand

>>>>>>> + * @param[in]  ext     size, in bytes, of the extent to add to the

>>>>>>> + *                     existing buffer.

>>>>>>> + *

>>>>>>> + * @return             Handle of the extended buffer or

>>>>>>> ODP_BUFFER_INVALID

>>>>>>> + *                     if the operation was not performed

>>>>>>> + */

>>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Clone a buffer, returning an exact copy of it

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle of buffer to duplicate

>>>>>>> + *

>>>>>>> + * @return             Handle of the duplicated buffer or

>>>>>>> ODP_BUFFER_INVALID

>>>>>>> + *                     if the operation was not performed

>>>>>>> + */

>>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);

>>>>>>> +

>>>>>>> +/**

>>>>>>> + * Copy a buffer, returning an exact copy of it

>>>>>>> + *

>>>>>>> + * @param[in]  buf     Buffer handle of buffer to copy

>>>>>>> + *

>>>>>>> + * @return             Handle of the copied buffer or

>>>>>>> ODP_BUFFER_INVALID

>>>>>>> + *                     if the operation was not performed

>>>>>>> + */

>>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);

>>>>>>> +

>>>>>>> +

>>>>>>>

>>>>>>>  #ifdef __cplusplus

>>>>>>>  }

>>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h

>>>>>>> b/platform/linux-generic/include/api/odp_buffer_pool.h

>>>>>>> index fe88898..f85d96c 100644

>>>>>>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h

>>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h

>>>>>>> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const char

>>>>>>> *name,

>>>>>>>

>>>>>>>

>>>>>>>  /**

>>>>>>> + * Get the next buffer pool from its predecessor

>>>>>>> + *

>>>>>>> + * @param[in]  pool            Buffer pool handle

>>>>>>> + * @param[out] name            Name of the pool

>>>>>>> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1

>>>>>>> chars)

>>>>>>> + * @param[out] udata_size      Size of user meta data used by this

>>>>>>> pool.

>>>>>>> + * @param[out] buf_num         Number of buffers contained in this

>>>>>>> pool

>>>>>>> + * @param[out] buf_size        Default size of application data in

>>>>>>> each buffer

>>>>>>> + * @param[out] buf_type        Buffer type of the pool

>>>>>>> + * @param[out] buf_opts        Buffer options for this pool

>>>>>>> + * @param[out] predef          Predefined (1) or Created (0).

>>>>>>> + *

>>>>>>> + * @return                     Buffer pool handle

>>>>>>> + */

>>>>>>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,

>>>>>>> +                                      char *name, size_t *udata_size,

>>>>>>> +                                      size_t *buf_num, size_t

>>>>>>> *buf_size,

>>>>>>> +                                      enum odp_buffer_type *buf_type,

>>>>>>> +                                      enum odp_buffer_opts *buf_opts,

>>>>>>> +                                      uint32_t *predef);

>>>>>>> +/**

>>>>>>>   * Find a buffer pool by name

>>>>>>>   *

>>>>>>>   * @param name      Name of the pool

>>>>>>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t

>>>>>>> pool);

>>>>>>>   */

>>>>>>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);

>>>>>>>

>>>>>>> +/**

>>>>>>> +* Allocate a buffer from a buffer pool

>>>>>>> +*

>>>>>>> +* @param[in]   pool    Pool handle

>>>>>>> +* @param[in]   size    Size of object to store in buffer

>>>>>>> +*

>>>>>>> +* @return              Buffer handle or ODP_BUFFER_INVALID

>>>>>>> +*/

>>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t

>>>>>>> size);

>>>>>>>

>>>>>>>  /**

>>>>>>>   * Buffer free

>>>>>>> diff --git a/platform/linux-generic/odp_buffer.c

>>>>>>> b/platform/linux-generic/odp_buffer.c

>>>>>>> index e54e0e7..7f4b4f0 100644

>>>>>>> --- a/platform/linux-generic/odp_buffer.c

>>>>>>> +++ b/platform/linux-generic/odp_buffer.c

>>>>>>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)

>>>>>>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);

>>>>>>>  }

>>>>>>>

>>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf)

>>>>>>> +{

>>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);

>>>>>>> +

>>>>>>> +       if (buf_hdr->scatter.num_bufs == 0)

>>>>>>> +               return 0;

>>>>>>> +       else

>>>>>>> +               return 1;

>>>>>>> +}

>>>>>>> +

>>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf)

>>>>>>> +{

>>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);

>>>>>>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;

>>>>>>> +}

>>>>>>>

>>>>>>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)

>>>>>>>  {

>>>>>>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)

>>>>>>>         printf("\n%s\n", str);

>>>>>>>  }

>>>>>>>

>>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)udata_size;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,

>>>>>>> +                                                size_t ndx)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)ndx;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,

>>>>>>> +                                            odp_buffer_segment_t seg)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)seg;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t

>>>>>>> seg,

>>>>>>> +                            size_t *seglen)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)seg;

>>>>>>> +       (void)seglen;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,

>>>>>>> +size_t *seglen)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)offset;

>>>>>>> +       (void)seglen;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)offset;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return;

>>>>>>> +}

>>>>>>> +

>>>>>>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t

>>>>>>> buf_src)

>>>>>>>  {

>>>>>>>         (void)buf_dst;

>>>>>>>         (void)buf_src;

>>>>>>>  }

>>>>>>> +

>>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)offset;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)

>>>>>>> +{

>>>>>>> +       (void)buf1;

>>>>>>> +       (void)buf2;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)offset;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       (void)ext;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)

>>>>>>> +{

>>>>>>> +       (void)buf;

>>>>>>> +       ODP_UNIMPLEMENTED();

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>> +

>>>>>>> diff --git a/platform/linux-generic/odp_buffer_pool.c

>>>>>>> b/platform/linux-generic/odp_buffer_pool.c

>>>>>>> index a48d7d6..bff4db5 100644

>>>>>>> --- a/platform/linux-generic/odp_buffer_pool.c

>>>>>>> +++ b/platform/linux-generic/odp_buffer_pool.c

>>>>>>> @@ -471,6 +471,13 @@ odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t

>>>>>>> pool_hdl)

>>>>>>>         return handle.u32;

>>>>>>>  }

>>>>>>>

>>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t

>>>>>>> size)

>>>>>>> +{

>>>>>>> +       (void)pool;

>>>>>>> +       (void) size;

>>>>>>> +       ODP_ERR("%s function is yet to be implemented", __func__);

>>>>>>> +       return 0;

>>>>>>> +}

>>>>>>>

>>>>>>>  void odp_buffer_free(odp_buffer_t buf)

>>>>>>>  {

>>>>>>> --

>>>>>>> 2.0.1.472.g6f92e5f

>>>>>>>

>>>>>>>

>>>>>>> _______________________________________________

>>>>>>> lng-odp mailing list

>>>>>>> lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> _______________________________________________

>>>>>>> lng-odp mailing list

>>>>>>> lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>

>>>>>>

>>>>>>

>>>>>> _______________________________________________

>>>>>> lng-odp mailing list

>>>>>> lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp

>>>>>>

>>>>>

>>>>>

>>>>> _______________________________________________

>>>>> lng-odp mailing list

>>>>> lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp

>>>>>

>>>>

>>>

>>

>>

>> _______________________________________________

>> lng-odp mailing list

>> lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>

>> http://lists.linaro.org/mailman/listinfo/lng-odp

>>


_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>
http://lists.linaro.org/mailman/listinfo/lng-odp
Bill Fischofer Oct. 22, 2014, 1:47 p.m. UTC | #18
I had previously detailed some of the problems that arise if we remove
segmentation support from buffers while trying to keep it as part of
packets.  I'd still like to see a response to these questions.  Given that
we support unsegmented buffers I don't see what the objection is here.
Those that don't want to deal with segments need not deal with them at
all.  That may limit the platforms they can run on, but applications will
always choose which implementations are best suited to their needs.

Bill

On Wed, Oct 22, 2014 at 7:27 AM, Savolainen, Petri (NSN - FI/Espoo) <
petri.savolainen@nsn.com> wrote:

> Hi,
>
> In short, I think we must not bring segmentation support to the buffer
> level "just in case" someone would need it there. Real use cases for
> segmentation are on packet level (large packets, packet
> fragmentation/reassembly, etc), so the feature should be implemented there.
>
> -Petri
>
> > -----Original Message-----
> > From: ext Ciprian Barbu [mailto:ciprian.barbu@linaro.org]
> > Sent: Wednesday, October 22, 2014 3:00 PM
> > To: Bill Fischofer
> > Cc: Ola Liljedahl; Savolainen, Petri (NSN - FI/Espoo); lng-
> > odp@lists.linaro.org
> > Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
> >
> > On Wed, Oct 22, 2014 at 2:47 PM, Ciprian Barbu <ciprian.barbu@linaro.org
> >
> > wrote:
> > > This thread has been cold for 5 days, so the assumption is that we can
> > > go forward with the design right now. This patch series proposed by
> > > Bala updates some part of the API to the final form of the Buffer
> > > Design Document, we should have it merged if there are no more
> > > objections. For that more people with the right expertise should have
> > > a look at it and get the thread back on track.
> > >
> > > I for example have observed the following issue. All the examples
> > > create buffer pools over shared memory, which doesn't make sense for
> > > some platforms, linux-dpdk for example, which ignores the base_addr
> > > argument altogether. I think we need more clarity on this subject, for
> > > sure the creation of buffer pools will differ from platform to
> > > platform, which migrates to the application responsibility.
> > >
> > > I think we should have a helper function to easily create buffer pools
> > > without worrying too much about the difference in buffer management
> > > between platforms, so that one can write a simple portable application
> > > with no sweat. For the hardcore programmers the API still gives fine
> > > control to buffer management that depending on the platform could
> > > involve additional prerequisites, like creating a shared memory
> > > segment to hold the buffer pool.
> >
> > Ok, so I had another look at the Buffer Management final design. I now
> > see that the option of creating buffer pools from regions has been
> > removed, so in this case things will be simpler for the applications.
> > In other words we should really start working on the full
> > implementation of the API because from there the problem I just stated
> > above (having to create shared memory segments) will disappear.
> >
> > >
> > > On Fri, Oct 17, 2014 at 4:33 PM, Bill Fischofer
> > > <bill.fischofer@linaro.org> wrote:
> > >> Let's consider the implications of removing segmentation support from
> > >> buffers and only having that concept be part of packets.
> > >>
> > >> The first question that arises is what is the relationship between the
> > >> abstract types odp_packet_t and odp_buffer_t? This is important
> because
> > >> currently we say that packets are allocated from ODP buffer pools, not
> > from
> > >> packet pools.  Do we need a separate odp_packet_pool_t that is used
> for
> > >> packets?
> > >>
> > >> Today, when I allocate a packet I'm allocating a single object that
> > happens
> > >> to be a single buffer object of type ODP_BUFFER_TYPE_PACKET.  But that
> > only
> > >> works if the two objects have compatible semantics (including
> > segmentation).
> > >> If the semantics are not compatible, then an odp_packet_t may in fact
> > be
> > >> composed of multiple odp_buffer_t's because the packet may consist of
> > >> multiple segments and buffers no longer recognize the concept of
> > segments so
> > >> a single buffer can only be a single segment.
> > >>
> > >> So now an odp_packet_segment_t may be an odp_buffer_t but an
> > odp_packet_t in
> > >> fact is some meta-object that is constructed (by whom?) from multiple
> > >> odp_packet_segment_ts that are themselves odp_buffer_ts.  So
> > >> odp_packet_to_buffer() no longer makes sense since there is no longer
> a
> > >> one-to-one correspondence between packets and buffers.  We could have
> > an
> > >> odp_packet_segment_to_buffer() routine instead.
> > >>
> > >> Next question: What about meta data?  If an odp_packet_t is a type of
> > an
> > >> odp_buffer_t then this is very straightforward since all buffer meta
> > data is
> > >> reusable as packet meta data and the packet type can just add its own
> > >> specific meta data to this set.  But if an odp_packet_t is now a
> > separate
> > >> object then where does the storage for its meta data come from? If we
> > try to
> > >> map it into an odp_buffer_t that doesn't work since an odp_packet_t
> may
> > >> consist of multiple underlying odp_buffer_ts, one for each
> > >> odp_packet_segment_t.  Is the packet meta data duplicated in each
> > segment?
> > >> Is the first segment of a packet special (odp_packet_first_segment_t)?
> > And
> > >> what about user meta data, since this is of potentially variable size?
> > >>
> > >> I submit that there are a lot of implications to this that need to be
> > fully
> > >> thought through, which is why I believe it's simpler to keep
> > segmentation as
> > >> part of buffers that (for now) only happens to be used by a particular
> > type
> > >> of buffer, namely packets.
> > >>
> > >> Bill
> > >>
> > >> On Fri, Oct 17, 2014 at 8:05 AM, Ola Liljedahl
> > <ola.liljedahl@linaro.org>
> > >> wrote:
> > >>>
> > >>> Personally I don't see any need for segmentation support in buffers.
> I
> > am
> > >>> just trying to shoot down what I think is flawed reasoning.
> > >>>
> > >>> -- Ola#1
> > >>>
> > >>> On 17 October 2014 15:03, Ola Liljedahl <ola.liljedahl@linaro.org>
> > wrote:
> > >>>>
> > >>>> But segmentation is already needed in a current and known subclass
> > (i.e.
> > >>>> packets). We are not talking about some other feature which we don't
> > know if
> > >>>> it will be needed. So this is not a case of "just in case".
> > >>>>
> > >>>> -- Ola#1
> > >>>>
> > >>>>
> > >>>> On 17 October 2014 14:45, Ola Dahl <dahl.ola@gmail.com> wrote:
> > >>>>>
> > >>>>> Hi,
> > >>>>>
> > >>>>> I do not think it is wise to put features in the base class "just
> in
> > >>>>> case" they would be needed in some future (not yet known) subclass.
> > >>>>>
> > >>>>> So if the concept of segmentation is relevant for packets but not
> > for
> > >>>>> timers then I think it should be implemented as a feature of
> > packets.
> > >>>>>
> > >>>>> Best regards,
> > >>>>>
> > >>>>> Ola D
> > >>>>>
> > >>>>> On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer
> > >>>>> <bill.fischofer@linaro.org> wrote:
> > >>>>>>
> > >>>>>> I agree that packets are the buffer type that most likely uses
> > >>>>>> segments, however there are many advantages to putting this
> support
> > in the
> > >>>>>> base class rather than the subclass independent of the number of
> > buffer
> > >>>>>> subclasses that will use this support today.
> > >>>>>>
> > >>>>>> It's simpler
> > >>>>>> It's more extensible
> > >>>>>> It results in cleaner and more efficient application code
> > >>>>>>
> > >>>>>> Allow me to expand on these points.  First simplicity.  Call the
> > work
> > >>>>>> required to support segmentation in the implementation X.  That X
> > is going
> > >>>>>> to be pretty much constant no matter where it is done.  But if the
> > >>>>>> implementation has a choice between doing X at a low level vs.
> > doing it at a
> > >>>>>> high level then it's simpler for the implementation to do it once
> > and be
> > >>>>>> done with it.  If the implementation does it at a higher level
> then
> > it is
> > >>>>>> either constrained to map that higher-level implementation to be
> > built on a
> > >>>>>> set of lower-level functions that may or may not be appropriate or
> > else it
> > >>>>>> needs to do a completely parallel implementation that is optimal
> > but highly
> > >>>>>> duplicative.
> > >>>>>>
> > >>>>>> Extensibility should be clear.  If at some future point we decide
> > >>>>>> segmentation would be useful for some new buffer type (e.g., IPC)
> > then
> > >>>>>> that's trivial to do if the base class supports it and awkward if
> > it's only
> > >>>>>> part of packets.
> > >>>>>>
> > >>>>>> From an application standpoint, it's cleaner because the packet
> > APIs
> > >>>>>> are just wrappers around their corresponding buffer APIs and can
> be
> > mapped
> > >>>>>> directly.  Otherwise we have a set of APIs that don't map and are
> > not easily
> > >>>>>> translatable.
> > >>>>>>
> > >>>>>> With regard to efficient segment access, that's what the
> > >>>>>> odp_packet_addr() routine provides--one-step fast-path
> > addressability to the
> > >>>>>> first segment of a packet.  An odp_packet_t is an abstract opaque
> > type.  It
> > >>>>>> is not, and cannot be treated as an address by the application.
> > >>>>>>
> > >>>>>> Does that make sense?
> > >>>>>>
> > >>>>>> Bill
> > >>>>>>
> > >>>>>>
> > >>>>>>
> > >>>>>>
> > >>>>>> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN -
> FI/Espoo)
> > >>>>>> <petri.savolainen@nsn.com> wrote:
> > >>>>>>>
> > >>>>>>> Hi,
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> 1. The only segmentation use case is for segmented packet, not
> for
> > >>>>>>> segmented buffers.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> 2. Common case for packets is that everything application needs
> is
> > in
> > >>>>>>> the first segment. Odp_packet_t could refer always into that
> > “first
> > >>>>>>> segment”, so that application (in the common case) would not need
> > to use
> > >>>>>>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> When buffer level features are minimized, the need for
> > >>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All
> > packet
> > >>>>>>> manipulation should happen through odp_packet_xxx(pkt, …) calls.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> -Petri
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> From: ext Bill Fischofer [mailto:bill.fischofer@linaro.org]
> > >>>>>>> Sent: Friday, October 17, 2014 1:17 PM
> > >>>>>>> To: Savolainen, Petri (NSN - FI/Espoo)
> > >>>>>>> Cc: ext Jacob, Jerin; lng-odp@lists.linaro.org
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
> > API
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> I'm not sure how to understand these two statements:
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> 1. There's no use case for segmented buffers
> > >>>>>>>
> > >>>>>>> 2. We should optimize for the common case (with segments)
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> These seem contradictory.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> The use case for segmented buffers is that some platforms have a
> > >>>>>>> HW-defined and managed segmented buffer model. If we insist that
> > the
> > >>>>>>> application be able to specify and control packet segment sizes
> we
> > are
> > >>>>>>> making the decision to exclude such platforms from supporting
> ODP.
> > The
> > >>>>>>> optimization suggested is precisely what is being proposed here.
> > By default
> > >>>>>>> packets are assumed to be contained in implementation-managed
> > segmented
> > >>>>>>> buffers and the first segment will be large enough to contain all
> > packet
> > >>>>>>> headers for non-pathological cases.  The case where the
> > application wishes
> > >>>>>>> to traverse the entire packet in SW is expected to be rare
> because
> > in the
> > >>>>>>> data plane you simply do not have the cycles to do this at line
> > rate for all
> > >>>>>>> packets.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs,
> > this is
> > >>>>>>> simply syntax to avoid the constant need for explicit conversion
> > functions
> > >>>>>>> since unlike C++, C does not support generic functions.  So you
> > cannot pass
> > >>>>>>> an odp_packet_t to a function that expects an odp_buffer_t
> > argument without
> > >>>>>>> a conversion call.  Do we really want to force applications to
> > constantly be
> > >>>>>>> writing code like:
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> rather than
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> odp_packet_xxx(pkt,...)
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> Not only is this awkward, it is also inefficient.  By having the
> > >>>>>>> explicit odp_packet_xxx() calls, the implementation is free to
> > optimize
> > >>>>>>> these references in whatever manner is appropriate to that
> > implementation.
> > >>>>>>> For some this may be a simple preprocessor-type expansion while
> > for others
> > >>>>>>> there may be more sophisticated handling.  But the application
> > should
> > >>>>>>> neither know nor care about how the implementation chooses to do
> > this.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN -
> > FI/Espoo)
> > >>>>>>> <petri.savolainen@nsn.com> wrote:
> > >>>>>>>
> > >>>>>>> Hi,
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> This is also my opinion. There’s no use case for segmented
> buffers
> > in
> > >>>>>>> v1.0 - so let’s keep it simple and define that buffers (and thus
> > buffer
> > >>>>>>> pools) are always unsegmented. Segmentation comes into play only
> > with
> > >>>>>>> packets (and only with those packets that cannot fit into a
> single
> > buffer).
> > >>>>>>> For example, if implementation has max buffer size 256, any
> > packets larger
> > >>>>>>> than that are segmented and segments are handled with
> > packet_seg_xxx calls.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> Also, I’d propose that we optimize for the common case (with
> > segments)
> > >>>>>>> - so that the odp_packet_t handle would refer always to the head
> > of packet
> > >>>>>>> segment. If the first segment (data/data_len pointed by the
> > odp_packet_t)
> > >>>>>>> carries all data application is interested in (=protocol
> headers),
> > the
> > >>>>>>> application would not have to use the segment API at all. Most
> > applications
> > >>>>>>> would not see any difference between small/large or
> > segmented/unsegmented
> > >>>>>>> packets as long as all headers fit into the first segment.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> -Petri
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> From: lng-odp-bounces@lists.linaro.org
> > >>>>>>> [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of ext
> Jacob,
> > Jerin
> > >>>>>>> Sent: Friday, October 17, 2014 9:34 AM
> > >>>>>>> To: Bill Fischofer
> > >>>>>>> Cc: lng-odp@lists.linaro.org
> > >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
> > API
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> The need for segment API infrastructure is very clear.The
> question
> > is,
> > >>>>>>> Do we need separate APIs for
> > >>>>>>>
> > >>>>>>> segment management at odp_buffer_segment* AND odp_packet_segment*
> > >>>>>>> levels ?
> > >>>>>>>
> > >>>>>>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be always
> > >>>>>>> unsegmented and if there is a
> > >>>>>>>
> > >>>>>>> API for odp_packet_segement* then there will be not be any
> > consumer
> > >>>>>>> for odp_buffer_segment* API for 1.0
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> ________________________________
> > >>>>>>>
> > >>>>>>> From: Bill Fischofer <bill.fischofer@linaro.org>
> > >>>>>>> Sent: Thursday, October 16, 2014 9:08 PM
> > >>>>>>> To: Jacob, Jerin
> > >>>>>>> Cc: Ola Liljedahl; Balasubramanian Manoharan; lng-
> > odp@lists.linaro.org
> > >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
> > API
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> From the buffer design doc (p. 8-9):
> > >>>>>>>
> > >>>>>>> Buffer Pool Options
> > >>>>>>>
> > >>>>>>> The odp_buffer_opts_e enum is used to specify additional options
> > >>>>>>> relating to the buffer pool.  Buffer pool options defined are:
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> ·     ODP_BUFFER_OPTS_NONE
> > >>>>>>>
> > >>>>>>> ·     ODP_BUFFER_OPTS_UNSEGMENTED
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> These options are additive so an application can simply specify a
> > >>>>>>> buf_opts by ORing together the options needed.  Note that buffer
> > pool
> > >>>>>>> options are themselves OPTIONAL and a given implementation MAY
> > fail the
> > >>>>>>> buffer pool creation request with an appropriate errno if the
> > requested
> > >>>>>>> option is not supported by the underlying ODP implementation,
> with
> > the
> > >>>>>>> exception that UNSEGMENTED pools MUST be supported for non-packet
> > types and
> > >>>>>>> for packet types as long as the requested size is less than the
> > >>>>>>> implementation-defined native packet segment size.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options
> > with
> > >>>>>>> no additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies
> > that the
> > >>>>>>> buffer pool should be unsegmented.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> So unsegmented buffer pool support is available.  As far as RAW
> > >>>>>>> buffers go, again from the doc (p. 14):
> > >>>>>>>
> > >>>>>>> ODP_BUFFER_TYPE_RAW
> > >>>>>>>
> > >>>>>>> This is the “basic” buffer type which simply consists of a single
> > >>>>>>> fixed-sized block of contiguous memory.  Buffers of this type do
> > not support
> > >>>>>>> user meta data and the only built-in meta data supported for this
> > type of
> > >>>>>>> buffer are those that are statically computable, such as pool and
> > size. This
> > >>>>>>> type of buffer is entirely under application control and most of
> > the buffer
> > >>>>>>> APIs defined in this document are not available.  APIs for this
> > type of
> > >>>>>>> buffer are described in this document.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> So RAW buffers are always unsegmented.  The intent is that
> Packets
> > are
> > >>>>>>> by default segmented but can be unsegmented while the other
> buffer
> > types are
> > >>>>>>> by default unsegmented but (with the exception of RAW buffers)
> can
> > be made
> > >>>>>>> segmented.  This is because all buffers start out as a single
> > segment and
> > >>>>>>> hence are unsegmented until they are expanded to overflow that
> > single
> > >>>>>>> segment.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> Hope that clarifies things.  Again, this is all very
> > straightforward
> > >>>>>>> and only comes into play when actually needed.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin
> > >>>>>>> <Jerin.Jacob@caviumnetworks.com> wrote:
> > >>>>>>>
> > >>>>>>> If there is no valid use case for supporting segmentation for raw
> > >>>>>>> buffers then lets drop it. At least it will reduce the effort of
> > >>>>>>>
> > >>>>>>> implementing and testing/verification buffer APIs on  different
> > >>>>>>> platforms.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> ________________________________
> > >>>>>>>
> > >>>>>>> From: lng-odp-bounces@lists.linaro.org
> > >>>>>>> <lng-odp-bounces@lists.linaro.org> on behalf of Ola Liljedahl
> > >>>>>>> <ola.liljedahl@linaro.org>
> > >>>>>>> Sent: Wednesday, October 8, 2014 1:37 PM
> > >>>>>>> To: Balasubramanian Manoharan
> > >>>>>>> Cc: lng-odp@lists.linaro.org
> > >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
> > API
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> As I wrote in my comment to the architecture discussion
> yesterday,
> > I
> > >>>>>>> am against segmentation for buffers. Or at least there must be
> the
> > >>>>>>> possibility to create a buffer pool with guaranteed non-segmented
> > buffers.
> > >>>>>>> Segmented packets are OK but not all usages for buffers relate to
> > packets. A
> > >>>>>>> lot of internal usages (timeouts, SW messages, internal data
> > structures)
> > >>>>>>> will not be able to handle segmented buffers so you must be able
> > to force
> > >>>>>>> the creation of buffer pools with non-segmented buffers.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> -- Ola
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> On 8 October 2014 09:50, Balasubramanian Manoharan
> > >>>>>>> <bala.manoharan@linaro.org> wrote:
> > >>>>>>>
> > >>>>>>> This patch contains ODP Buffer Management missing APIs
> > >>>>>>> The intent of this patch is to port the missing APIs from Buffer
> > >>>>>>> Management design document into Linux-generic repo.
> > >>>>>>> The dummy functions will be replaced during linux-generic
> > >>>>>>> implementation.
> > >>>>>>>
> > >>>>>>> Signed-off-by: Balasubramanian Manoharan
> > <bala.manoharan@linaro.org>
> > >>>>>>> ---
> > >>>>>>>  platform/linux-generic/include/api/odp_buffer.h    | 203
> > >>>>>>> ++++++++++++++++++++-
> > >>>>>>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
> > >>>>>>>  platform/linux-generic/odp_buffer.c                | 120
> > ++++++++++++
> > >>>>>>>  platform/linux-generic/odp_buffer_pool.c           |   7 +
> > >>>>>>>  4 files changed, 351 insertions(+), 9 deletions(-)
> > >>>>>>>
> > >>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer.h
> > >>>>>>> b/platform/linux-generic/include/api/odp_buffer.h
> > >>>>>>> index d8577fd..aeb75ed 100644
> > >>>>>>> --- a/platform/linux-generic/include/api/odp_buffer.h
> > >>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer.h
> > >>>>>>> @@ -28,8 +28,34 @@ extern "C" {
> > >>>>>>>   */
> > >>>>>>>  typedef uint32_t odp_buffer_t;
> > >>>>>>>
> > >>>>>>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
> > >>>>>>> +/**
> > >>>>>>> +* ODP buffer segment
> > >>>>>>> +*/
> > >>>>>>> +typedef uint32_t odp_buffer_segment_t;
> > >>>>>>>
> > >>>>>>> +/**
> > >>>>>>> +* ODP buffer type
> > >>>>>>> +*/
> > >>>>>>> +typedef enum odp_buffer_type {
> > >>>>>>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid
> > */
> > >>>>>>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can hold
> > any
> > >>>>>>> other
> > >>>>>>> +                                       buffer type */
> > >>>>>>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
> > >>>>>>> +                                       no additional metadata */
> > >>>>>>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
> > >>>>>>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
> > >>>>>>> +} odp_buffer_type_e;
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> +* ODP buffer options
> > >>>>>>> +*/
> > >>>>>>> +typedef enum odp_buffer_opts {
> > >>>>>>> +       ODP_BUFFER_OPTS_NONE,
> > >>>>>>> +       ODP_BUFFER_OPTS_UNSEGMENTED
> > >>>>>>> +} odp_buffer_opts_e;
> > >>>>>>> +
> > >>>>>>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
> > >>>>>>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
> > >>>>>>>
> > >>>>>>>  /**
> > >>>>>>>   * Buffer start address
> > >>>>>>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
> > >>>>>>>   */
> > >>>>>>>  int odp_buffer_type(odp_buffer_t buf);
> > >>>>>>>
> > >>>>>>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
> > >>>>>>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold
> > any
> > >>>>>>> other
> > >>>>>>> -                                         buffer type */
> > >>>>>>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no
> > additional
> > >>>>>>> metadata */
> > >>>>>>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
> > >>>>>>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
> > >>>>>>> -
> > >>>>>>> -
> > >>>>>>>  /**
> > >>>>>>>   * Tests if buffer is valid
> > >>>>>>>   *
> > >>>>>>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
> > >>>>>>>  int odp_buffer_is_valid(odp_buffer_t buf);
> > >>>>>>>
> > >>>>>>>  /**
> > >>>>>>> + * Tests if buffer is segmented
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  buf     Buffer handle
> > >>>>>>> + *
> > >>>>>>> + * @return             1 if buffer has more than one segment,
> > >>>>>>> + *                     otherwise 0
> > >>>>>>> + */
> > >>>>>>> +
> > >>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf);
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> + * Get address and size of user meta data associated with a
> > buffer
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  buf             Buffer handle
> > >>>>>>> + * @param[out] udata_size      Number of bytes of user meta data
> > >>>>>>> available
> > >>>>>>> + *                             at the returned address
> > >>>>>>> + * @return                     Address of the user meta data for
> > this
> > >>>>>>> buffer
> > >>>>>>> + *                             or NULL if the buffer has no user
> > meta
> > >>>>>>> data.
> > >>>>>>> + */
> > >>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> + * Get address of user meta data associated with a buffer
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  buf     Buffer handle
> > >>>>>>> + *
> > >>>>>>> + * @return             Address of the user meta data for this
> > buffer
> > >>>>>>> + *                     or NULL if the buffer has no user meta
> > data.
> > >>>>>>> + */
> > >>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf);
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> + * Get count of number of segments in a buffer
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  buf     Buffer handle
> > >>>>>>> + *
> > >>>>>>> + * @return             Count of the number of segments in buf
> > >>>>>>> + */
> > >>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf);
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> + * Get the segment identifier for a buffer segment by index
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  buf     Buffer handle
> > >>>>>>> + * @param[in]  ndx     Segment index of segment of interest
> > >>>>>>> + *
> > >>>>>>> + * @return             Segment identifier or ODP_SEGMENT_INVALID
> > if
> > >>>>>>> the
> > >>>>>>> + *                     supplied ndx is out of range.
> > >>>>>>> + */
> > >>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t
> > buf,
> > >>>>>>> size_t ndx);
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> + * Get the next segment identifier for a buffer segment
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  buf     Buffer handle
> > >>>>>>> + * @param[in]  seg     Segment identifier of the previous
> segment
> > >>>>>>> + *
> > >>>>>>> + * @return             Segment identifier of the next segment,
> > >>>>>>> +                       or ODP_SEGMENT_INVALID.
> > >>>>>>> + */
> > >>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
> > >>>>>>> +                                            odp_buffer_segment_t
> > >>>>>>> seg);
> > >>>>>>> +/**
> > >>>>>>> + * Get start address for a specified buffer segment
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  buf     Buffer handle
> > >>>>>>> + * @param[in]  seg     Segment identifier of the buffer to be
> > >>>>>>> addressed
> > >>>>>>> + * @param[out] seglen  Returned number of bytes in this buffer
> > >>>>>>> + *                     segment available at returned address
> > >>>>>>> + *
> > >>>>>>> + * @return             Segment start address or NULL
> > >>>>>>> + */
> > >>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf,
> > odp_buffer_segment_t
> > >>>>>>> seg,
> > >>>>>>> +size_t *seglen);
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> + *Unmap a buffer segment
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  seg     Buffer segment handle
> > >>>>>>> + */
> > >>>>>>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> +* Get start address for a specified buffer offset
> > >>>>>>> +*
> > >>>>>>> +* @param[in]   buf     Buffer handle
> > >>>>>>> +* @param[in]   offset  Byte offset within the buffer to be
> > addressed
> > >>>>>>> +* @param[out]  seglen  Returned number of bytes in this buffer
> > >>>>>>> +*                      segment available at returned address
> > >>>>>>> +*
> > >>>>>>> +* @return              Offset start address or NULL
> > >>>>>>> +*/
> > >>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
> > >>>>>>> +size_t *seglen);
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> + * Unmap a buffer segment by offset
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  buf     Buffer handle
> > >>>>>>> + * @param[in]  offset  Buffer offset
> > >>>>>>> + */
> > >>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>>   * Print buffer metadata to STDOUT
> > >>>>>>>   *
> > >>>>>>>   * @param buf      Buffer handle
> > >>>>>>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
> > >>>>>>>   */
> > >>>>>>>  void odp_buffer_print(odp_buffer_t buf);
> > >>>>>>>
> > >>>>>>> +/**
> > >>>>>>> + * Split a buffer into two buffers at a specified split point
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  buf     Handle of buffer to split
> > >>>>>>> + * @param[in]  offset  Byte offset within buf to split buffer
> > >>>>>>> + *
> > >>>>>>> + * @return             Buffer handle of the created split buffer
> > >>>>>>> + */
> > >>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> + * Join two buffers into a single buffer
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  buf1    Buffer handle of first buffer to join
> > >>>>>>> + * @param[in]  buf2    Buffer handle of second buffer to join
> > >>>>>>> + *
> > >>>>>>> + * @return             Buffer handle of the joined buffer
> > >>>>>>> + */
> > >>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t
> > buf2);
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> + * Trim a buffer at a specified trim point
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  buf     Buffer handle of buffer to trim
> > >>>>>>> + * @param[in]  offset  byte offset within buf to trim
> > >>>>>>> + *
> > >>>>>>> + * @return             Handle of the trimmed buffer or
> > >>>>>>> + *                     ODP_BUFFER_INVALID if the operation was
> > not
> > >>>>>>> performed
> > >>>>>>> + */
> > >>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
> > >>>>>>> +/**
> > >>>>>>> + * Extend a buffer for a specified number of bytes
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  buf     Buffer handle of buffer to expand
> > >>>>>>> + * @param[in]  ext     size, in bytes, of the extent to add to
> > the
> > >>>>>>> + *                     existing buffer.
> > >>>>>>> + *
> > >>>>>>> + * @return             Handle of the extended buffer or
> > >>>>>>> ODP_BUFFER_INVALID
> > >>>>>>> + *                     if the operation was not performed
> > >>>>>>> + */
> > >>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> + * Clone a buffer, returning an exact copy of it
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  buf     Buffer handle of buffer to duplicate
> > >>>>>>> + *
> > >>>>>>> + * @return             Handle of the duplicated buffer or
> > >>>>>>> ODP_BUFFER_INVALID
> > >>>>>>> + *                     if the operation was not performed
> > >>>>>>> + */
> > >>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> + * Copy a buffer, returning an exact copy of it
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  buf     Buffer handle of buffer to copy
> > >>>>>>> + *
> > >>>>>>> + * @return             Handle of the copied buffer or
> > >>>>>>> ODP_BUFFER_INVALID
> > >>>>>>> + *                     if the operation was not performed
> > >>>>>>> + */
> > >>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
> > >>>>>>> +
> > >>>>>>> +
> > >>>>>>>
> > >>>>>>>  #ifdef __cplusplus
> > >>>>>>>  }
> > >>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h
> > >>>>>>> b/platform/linux-generic/include/api/odp_buffer_pool.h
> > >>>>>>> index fe88898..f85d96c 100644
> > >>>>>>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
> > >>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
> > >>>>>>> @@ -52,6 +52,27 @@ odp_buffer_pool_t odp_buffer_pool_create(const
> > char
> > >>>>>>> *name,
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>  /**
> > >>>>>>> + * Get the next buffer pool from its predecessor
> > >>>>>>> + *
> > >>>>>>> + * @param[in]  pool            Buffer pool handle
> > >>>>>>> + * @param[out] name            Name of the pool
> > >>>>>>> + *                             (max ODP_BUFFER_POOL_NAME_LEN - 1
> > >>>>>>> chars)
> > >>>>>>> + * @param[out] udata_size      Size of user meta data used by
> > this
> > >>>>>>> pool.
> > >>>>>>> + * @param[out] buf_num         Number of buffers contained in
> > this
> > >>>>>>> pool
> > >>>>>>> + * @param[out] buf_size        Default size of application data
> > in
> > >>>>>>> each buffer
> > >>>>>>> + * @param[out] buf_type        Buffer type of the pool
> > >>>>>>> + * @param[out] buf_opts        Buffer options for this pool
> > >>>>>>> + * @param[out] predef          Predefined (1) or Created (0).
> > >>>>>>> + *
> > >>>>>>> + * @return                     Buffer pool handle
> > >>>>>>> + */
> > >>>>>>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
> > >>>>>>> +                                      char *name, size_t
> > *udata_size,
> > >>>>>>> +                                      size_t *buf_num, size_t
> > >>>>>>> *buf_size,
> > >>>>>>> +                                      enum odp_buffer_type
> > *buf_type,
> > >>>>>>> +                                      enum odp_buffer_opts
> > *buf_opts,
> > >>>>>>> +                                      uint32_t *predef);
> > >>>>>>> +/**
> > >>>>>>>   * Find a buffer pool by name
> > >>>>>>>   *
> > >>>>>>>   * @param name      Name of the pool
> > >>>>>>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t
> > >>>>>>> pool);
> > >>>>>>>   */
> > >>>>>>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
> > >>>>>>>
> > >>>>>>> +/**
> > >>>>>>> +* Allocate a buffer from a buffer pool
> > >>>>>>> +*
> > >>>>>>> +* @param[in]   pool    Pool handle
> > >>>>>>> +* @param[in]   size    Size of object to store in buffer
> > >>>>>>> +*
> > >>>>>>> +* @return              Buffer handle or ODP_BUFFER_INVALID
> > >>>>>>> +*/
> > >>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool,
> size_t
> > >>>>>>> size);
> > >>>>>>>
> > >>>>>>>  /**
> > >>>>>>>   * Buffer free
> > >>>>>>> diff --git a/platform/linux-generic/odp_buffer.c
> > >>>>>>> b/platform/linux-generic/odp_buffer.c
> > >>>>>>> index e54e0e7..7f4b4f0 100644
> > >>>>>>> --- a/platform/linux-generic/odp_buffer.c
> > >>>>>>> +++ b/platform/linux-generic/odp_buffer.c
> > >>>>>>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
> > >>>>>>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
> > >>>>>>>  }
> > >>>>>>>
> > >>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf)
> > >>>>>>> +{
> > >>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
> > >>>>>>> +
> > >>>>>>> +       if (buf_hdr->scatter.num_bufs == 0)
> > >>>>>>> +               return 0;
> > >>>>>>> +       else
> > >>>>>>> +               return 1;
> > >>>>>>> +}
> > >>>>>>> +
> > >>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf)
> > >>>>>>> +{
> > >>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
> > >>>>>>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
> > >>>>>>> +}
> > >>>>>>>
> > >>>>>>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
> > >>>>>>>  {
> > >>>>>>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
> > >>>>>>>         printf("\n%s\n", str);
> > >>>>>>>  }
> > >>>>>>>
> > >>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
> > >>>>>>> +{
> > >>>>>>> +       (void)buf;
> > >>>>>>> +       (void)udata_size;
> > >>>>>>> +       ODP_UNIMPLEMENTED();
> > >>>>>>> +       return 0;
> > >>>>>>> +}
> > >>>>>>> +
> > >>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf)
> > >>>>>>> +{
> > >>>>>>> +       (void)buf;
> > >>>>>>> +       ODP_UNIMPLEMENTED();
> > >>>>>>> +       return 0;
> > >>>>>>> +}
> > >>>>>>> +
> > >>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t
> > buf,
> > >>>>>>> +                                                size_t ndx)
> > >>>>>>> +{
> > >>>>>>> +       (void)buf;
> > >>>>>>> +       (void)ndx;
> > >>>>>>> +       ODP_UNIMPLEMENTED();
> > >>>>>>> +       return 0;
> > >>>>>>> +}
> > >>>>>>> +
> > >>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
> > >>>>>>> +                                            odp_buffer_segment_t
> > seg)
> > >>>>>>> +{
> > >>>>>>> +       (void)buf;
> > >>>>>>> +       (void)seg;
> > >>>>>>> +       ODP_UNIMPLEMENTED();
> > >>>>>>> +       return 0;
> > >>>>>>> +}
> > >>>>>>> +
> > >>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf,
> > odp_buffer_segment_t
> > >>>>>>> seg,
> > >>>>>>> +                            size_t *seglen)
> > >>>>>>> +{
> > >>>>>>> +       (void)buf;
> > >>>>>>> +       (void)seg;
> > >>>>>>> +       (void)seglen;
> > >>>>>>> +       ODP_UNIMPLEMENTED();
> > >>>>>>> +       return 0;
> > >>>>>>> +}
> > >>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
> > >>>>>>> +size_t *seglen)
> > >>>>>>> +{
> > >>>>>>> +       (void)buf;
> > >>>>>>> +       (void)offset;
> > >>>>>>> +       (void)seglen;
> > >>>>>>> +       ODP_UNIMPLEMENTED();
> > >>>>>>> +       return 0;
> > >>>>>>> +}
> > >>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
> > >>>>>>> +{
> > >>>>>>> +       (void)buf;
> > >>>>>>> +       (void)offset;
> > >>>>>>> +       ODP_UNIMPLEMENTED();
> > >>>>>>> +       return;
> > >>>>>>> +}
> > >>>>>>> +
> > >>>>>>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t
> > >>>>>>> buf_src)
> > >>>>>>>  {
> > >>>>>>>         (void)buf_dst;
> > >>>>>>>         (void)buf_src;
> > >>>>>>>  }
> > >>>>>>> +
> > >>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
> > >>>>>>> +{
> > >>>>>>> +       (void)buf;
> > >>>>>>> +       (void)offset;
> > >>>>>>> +       ODP_UNIMPLEMENTED();
> > >>>>>>> +       return 0;
> > >>>>>>> +}
> > >>>>>>> +
> > >>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t
> > buf2)
> > >>>>>>> +{
> > >>>>>>> +       (void)buf1;
> > >>>>>>> +       (void)buf2;
> > >>>>>>> +       ODP_UNIMPLEMENTED();
> > >>>>>>> +       return 0;
> > >>>>>>> +}
> > >>>>>>> +
> > >>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
> > >>>>>>> +{
> > >>>>>>> +       (void)buf;
> > >>>>>>> +       (void)offset;
> > >>>>>>> +       ODP_UNIMPLEMENTED();
> > >>>>>>> +       return 0;
> > >>>>>>> +}
> > >>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
> > >>>>>>> +{
> > >>>>>>> +       (void)buf;
> > >>>>>>> +       (void)ext;
> > >>>>>>> +       ODP_UNIMPLEMENTED();
> > >>>>>>> +       return 0;
> > >>>>>>> +}
> > >>>>>>> +
> > >>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
> > >>>>>>> +{
> > >>>>>>> +       (void)buf;
> > >>>>>>> +       ODP_UNIMPLEMENTED();
> > >>>>>>> +       return 0;
> > >>>>>>> +}
> > >>>>>>> +
> > >>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
> > >>>>>>> +{
> > >>>>>>> +       (void)buf;
> > >>>>>>> +       ODP_UNIMPLEMENTED();
> > >>>>>>> +       return 0;
> > >>>>>>> +}
> > >>>>>>> +
> > >>>>>>> diff --git a/platform/linux-generic/odp_buffer_pool.c
> > >>>>>>> b/platform/linux-generic/odp_buffer_pool.c
> > >>>>>>> index a48d7d6..bff4db5 100644
> > >>>>>>> --- a/platform/linux-generic/odp_buffer_pool.c
> > >>>>>>> +++ b/platform/linux-generic/odp_buffer_pool.c
> > >>>>>>> @@ -471,6 +471,13 @@ odp_buffer_t
> > odp_buffer_alloc(odp_buffer_pool_t
> > >>>>>>> pool_hdl)
> > >>>>>>>         return handle.u32;
> > >>>>>>>  }
> > >>>>>>>
> > >>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool,
> size_t
> > >>>>>>> size)
> > >>>>>>> +{
> > >>>>>>> +       (void)pool;
> > >>>>>>> +       (void) size;
> > >>>>>>> +       ODP_ERR("%s function is yet to be implemented",
> __func__);
> > >>>>>>> +       return 0;
> > >>>>>>> +}
> > >>>>>>>
> > >>>>>>>  void odp_buffer_free(odp_buffer_t buf)
> > >>>>>>>  {
> > >>>>>>> --
> > >>>>>>> 2.0.1.472.g6f92e5f
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> _______________________________________________
> > >>>>>>> lng-odp mailing list
> > >>>>>>> lng-odp@lists.linaro.org
> > >>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> _______________________________________________
> > >>>>>>> lng-odp mailing list
> > >>>>>>> lng-odp@lists.linaro.org
> > >>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>
> > >>>>>>
> > >>>>>>
> > >>>>>> _______________________________________________
> > >>>>>> lng-odp mailing list
> > >>>>>> lng-odp@lists.linaro.org
> > >>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
> > >>>>>>
> > >>>>>
> > >>>>>
> > >>>>> _______________________________________________
> > >>>>> lng-odp mailing list
> > >>>>> lng-odp@lists.linaro.org
> > >>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
> > >>>>>
> > >>>>
> > >>>
> > >>
> > >>
> > >> _______________________________________________
> > >> lng-odp mailing list
> > >> lng-odp@lists.linaro.org
> > >> http://lists.linaro.org/mailman/listinfo/lng-odp
> > >>
>
Bill Fischofer Oct. 31, 2014, 2:54 p.m. UTC | #19
This patch does not apply to the current repository.  Is there a revised
version available?

Thanks.

Bill

On Wed, Oct 22, 2014 at 8:47 AM, Bill Fischofer <bill.fischofer@linaro.org>
wrote:

> I had previously detailed some of the problems that arise if we remove
> segmentation support from buffers while trying to keep it as part of
> packets.  I'd still like to see a response to these questions.  Given that
> we support unsegmented buffers I don't see what the objection is here.
> Those that don't want to deal with segments need not deal with them at
> all.  That may limit the platforms they can run on, but applications will
> always choose which implementations are best suited to their needs.
>
> Bill
>
> On Wed, Oct 22, 2014 at 7:27 AM, Savolainen, Petri (NSN - FI/Espoo) <
> petri.savolainen@nsn.com> wrote:
>
>> Hi,
>>
>> In short, I think we must not bring segmentation support to the buffer
>> level "just in case" someone would need it there. Real use cases for
>> segmentation are on packet level (large packets, packet
>> fragmentation/reassembly, etc), so the feature should be implemented there.
>>
>> -Petri
>>
>> > -----Original Message-----
>> > From: ext Ciprian Barbu [mailto:ciprian.barbu@linaro.org]
>> > Sent: Wednesday, October 22, 2014 3:00 PM
>> > To: Bill Fischofer
>> > Cc: Ola Liljedahl; Savolainen, Petri (NSN - FI/Espoo); lng-
>> > odp@lists.linaro.org
>> > Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>> >
>> > On Wed, Oct 22, 2014 at 2:47 PM, Ciprian Barbu <
>> ciprian.barbu@linaro.org>
>> > wrote:
>> > > This thread has been cold for 5 days, so the assumption is that we can
>> > > go forward with the design right now. This patch series proposed by
>> > > Bala updates some part of the API to the final form of the Buffer
>> > > Design Document, we should have it merged if there are no more
>> > > objections. For that more people with the right expertise should have
>> > > a look at it and get the thread back on track.
>> > >
>> > > I for example have observed the following issue. All the examples
>> > > create buffer pools over shared memory, which doesn't make sense for
>> > > some platforms, linux-dpdk for example, which ignores the base_addr
>> > > argument altogether. I think we need more clarity on this subject, for
>> > > sure the creation of buffer pools will differ from platform to
>> > > platform, which migrates to the application responsibility.
>> > >
>> > > I think we should have a helper function to easily create buffer pools
>> > > without worrying too much about the difference in buffer management
>> > > between platforms, so that one can write a simple portable application
>> > > with no sweat. For the hardcore programmers the API still gives fine
>> > > control to buffer management that depending on the platform could
>> > > involve additional prerequisites, like creating a shared memory
>> > > segment to hold the buffer pool.
>> >
>> > Ok, so I had another look at the Buffer Management final design. I now
>> > see that the option of creating buffer pools from regions has been
>> > removed, so in this case things will be simpler for the applications.
>> > In other words we should really start working on the full
>> > implementation of the API because from there the problem I just stated
>> > above (having to create shared memory segments) will disappear.
>> >
>> > >
>> > > On Fri, Oct 17, 2014 at 4:33 PM, Bill Fischofer
>> > > <bill.fischofer@linaro.org> wrote:
>> > >> Let's consider the implications of removing segmentation support from
>> > >> buffers and only having that concept be part of packets.
>> > >>
>> > >> The first question that arises is what is the relationship between
>> the
>> > >> abstract types odp_packet_t and odp_buffer_t? This is important
>> because
>> > >> currently we say that packets are allocated from ODP buffer pools,
>> not
>> > from
>> > >> packet pools.  Do we need a separate odp_packet_pool_t that is used
>> for
>> > >> packets?
>> > >>
>> > >> Today, when I allocate a packet I'm allocating a single object that
>> > happens
>> > >> to be a single buffer object of type ODP_BUFFER_TYPE_PACKET.  But
>> that
>> > only
>> > >> works if the two objects have compatible semantics (including
>> > segmentation).
>> > >> If the semantics are not compatible, then an odp_packet_t may in fact
>> > be
>> > >> composed of multiple odp_buffer_t's because the packet may consist of
>> > >> multiple segments and buffers no longer recognize the concept of
>> > segments so
>> > >> a single buffer can only be a single segment.
>> > >>
>> > >> So now an odp_packet_segment_t may be an odp_buffer_t but an
>> > odp_packet_t in
>> > >> fact is some meta-object that is constructed (by whom?) from multiple
>> > >> odp_packet_segment_ts that are themselves odp_buffer_ts.  So
>> > >> odp_packet_to_buffer() no longer makes sense since there is no
>> longer a
>> > >> one-to-one correspondence between packets and buffers.  We could have
>> > an
>> > >> odp_packet_segment_to_buffer() routine instead.
>> > >>
>> > >> Next question: What about meta data?  If an odp_packet_t is a type of
>> > an
>> > >> odp_buffer_t then this is very straightforward since all buffer meta
>> > data is
>> > >> reusable as packet meta data and the packet type can just add its own
>> > >> specific meta data to this set.  But if an odp_packet_t is now a
>> > separate
>> > >> object then where does the storage for its meta data come from? If we
>> > try to
>> > >> map it into an odp_buffer_t that doesn't work since an odp_packet_t
>> may
>> > >> consist of multiple underlying odp_buffer_ts, one for each
>> > >> odp_packet_segment_t.  Is the packet meta data duplicated in each
>> > segment?
>> > >> Is the first segment of a packet special
>> (odp_packet_first_segment_t)?
>> > And
>> > >> what about user meta data, since this is of potentially variable
>> size?
>> > >>
>> > >> I submit that there are a lot of implications to this that need to be
>> > fully
>> > >> thought through, which is why I believe it's simpler to keep
>> > segmentation as
>> > >> part of buffers that (for now) only happens to be used by a
>> particular
>> > type
>> > >> of buffer, namely packets.
>> > >>
>> > >> Bill
>> > >>
>> > >> On Fri, Oct 17, 2014 at 8:05 AM, Ola Liljedahl
>> > <ola.liljedahl@linaro.org>
>> > >> wrote:
>> > >>>
>> > >>> Personally I don't see any need for segmentation support in
>> buffers. I
>> > am
>> > >>> just trying to shoot down what I think is flawed reasoning.
>> > >>>
>> > >>> -- Ola#1
>> > >>>
>> > >>> On 17 October 2014 15:03, Ola Liljedahl <ola.liljedahl@linaro.org>
>> > wrote:
>> > >>>>
>> > >>>> But segmentation is already needed in a current and known subclass
>> > (i.e.
>> > >>>> packets). We are not talking about some other feature which we
>> don't
>> > know if
>> > >>>> it will be needed. So this is not a case of "just in case".
>> > >>>>
>> > >>>> -- Ola#1
>> > >>>>
>> > >>>>
>> > >>>> On 17 October 2014 14:45, Ola Dahl <dahl.ola@gmail.com> wrote:
>> > >>>>>
>> > >>>>> Hi,
>> > >>>>>
>> > >>>>> I do not think it is wise to put features in the base class "just
>> in
>> > >>>>> case" they would be needed in some future (not yet known)
>> subclass.
>> > >>>>>
>> > >>>>> So if the concept of segmentation is relevant for packets but not
>> > for
>> > >>>>> timers then I think it should be implemented as a feature of
>> > packets.
>> > >>>>>
>> > >>>>> Best regards,
>> > >>>>>
>> > >>>>> Ola D
>> > >>>>>
>> > >>>>> On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer
>> > >>>>> <bill.fischofer@linaro.org> wrote:
>> > >>>>>>
>> > >>>>>> I agree that packets are the buffer type that most likely uses
>> > >>>>>> segments, however there are many advantages to putting this
>> support
>> > in the
>> > >>>>>> base class rather than the subclass independent of the number of
>> > buffer
>> > >>>>>> subclasses that will use this support today.
>> > >>>>>>
>> > >>>>>> It's simpler
>> > >>>>>> It's more extensible
>> > >>>>>> It results in cleaner and more efficient application code
>> > >>>>>>
>> > >>>>>> Allow me to expand on these points.  First simplicity.  Call the
>> > work
>> > >>>>>> required to support segmentation in the implementation X.  That X
>> > is going
>> > >>>>>> to be pretty much constant no matter where it is done.  But if
>> the
>> > >>>>>> implementation has a choice between doing X at a low level vs.
>> > doing it at a
>> > >>>>>> high level then it's simpler for the implementation to do it once
>> > and be
>> > >>>>>> done with it.  If the implementation does it at a higher level
>> then
>> > it is
>> > >>>>>> either constrained to map that higher-level implementation to be
>> > built on a
>> > >>>>>> set of lower-level functions that may or may not be appropriate
>> or
>> > else it
>> > >>>>>> needs to do a completely parallel implementation that is optimal
>> > but highly
>> > >>>>>> duplicative.
>> > >>>>>>
>> > >>>>>> Extensibility should be clear.  If at some future point we decide
>> > >>>>>> segmentation would be useful for some new buffer type (e.g., IPC)
>> > then
>> > >>>>>> that's trivial to do if the base class supports it and awkward if
>> > it's only
>> > >>>>>> part of packets.
>> > >>>>>>
>> > >>>>>> From an application standpoint, it's cleaner because the packet
>> > APIs
>> > >>>>>> are just wrappers around their corresponding buffer APIs and can
>> be
>> > mapped
>> > >>>>>> directly.  Otherwise we have a set of APIs that don't map and are
>> > not easily
>> > >>>>>> translatable.
>> > >>>>>>
>> > >>>>>> With regard to efficient segment access, that's what the
>> > >>>>>> odp_packet_addr() routine provides--one-step fast-path
>> > addressability to the
>> > >>>>>> first segment of a packet.  An odp_packet_t is an abstract opaque
>> > type.  It
>> > >>>>>> is not, and cannot be treated as an address by the application.
>> > >>>>>>
>> > >>>>>> Does that make sense?
>> > >>>>>>
>> > >>>>>> Bill
>> > >>>>>>
>> > >>>>>>
>> > >>>>>>
>> > >>>>>>
>> > >>>>>> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN -
>> FI/Espoo)
>> > >>>>>> <petri.savolainen@nsn.com> wrote:
>> > >>>>>>>
>> > >>>>>>> Hi,
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> 1. The only segmentation use case is for segmented packet, not
>> for
>> > >>>>>>> segmented buffers.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> 2. Common case for packets is that everything application needs
>> is
>> > in
>> > >>>>>>> the first segment. Odp_packet_t could refer always into that
>> > “first
>> > >>>>>>> segment”, so that application (in the common case) would not
>> need
>> > to use
>> > >>>>>>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx() calls.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> When buffer level features are minimized, the need for
>> > >>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All
>> > packet
>> > >>>>>>> manipulation should happen through odp_packet_xxx(pkt, …) calls.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> -Petri
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> From: ext Bill Fischofer [mailto:bill.fischofer@linaro.org]
>> > >>>>>>> Sent: Friday, October 17, 2014 1:17 PM
>> > >>>>>>> To: Savolainen, Petri (NSN - FI/Espoo)
>> > >>>>>>> Cc: ext Jacob, Jerin; lng-odp@lists.linaro.org
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
>> > API
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> I'm not sure how to understand these two statements:
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> 1. There's no use case for segmented buffers
>> > >>>>>>>
>> > >>>>>>> 2. We should optimize for the common case (with segments)
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> These seem contradictory.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> The use case for segmented buffers is that some platforms have a
>> > >>>>>>> HW-defined and managed segmented buffer model. If we insist that
>> > the
>> > >>>>>>> application be able to specify and control packet segment sizes
>> we
>> > are
>> > >>>>>>> making the decision to exclude such platforms from supporting
>> ODP.
>> > The
>> > >>>>>>> optimization suggested is precisely what is being proposed here.
>> > By default
>> > >>>>>>> packets are assumed to be contained in implementation-managed
>> > segmented
>> > >>>>>>> buffers and the first segment will be large enough to contain
>> all
>> > packet
>> > >>>>>>> headers for non-pathological cases.  The case where the
>> > application wishes
>> > >>>>>>> to traverse the entire packet in SW is expected to be rare
>> because
>> > in the
>> > >>>>>>> data plane you simply do not have the cycles to do this at line
>> > rate for all
>> > >>>>>>> packets.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs,
>> > this is
>> > >>>>>>> simply syntax to avoid the constant need for explicit conversion
>> > functions
>> > >>>>>>> since unlike C++, C does not support generic functions.  So you
>> > cannot pass
>> > >>>>>>> an odp_packet_t to a function that expects an odp_buffer_t
>> > argument without
>> > >>>>>>> a conversion call.  Do we really want to force applications to
>> > constantly be
>> > >>>>>>> writing code like:
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> rather than
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> odp_packet_xxx(pkt,...)
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> Not only is this awkward, it is also inefficient.  By having the
>> > >>>>>>> explicit odp_packet_xxx() calls, the implementation is free to
>> > optimize
>> > >>>>>>> these references in whatever manner is appropriate to that
>> > implementation.
>> > >>>>>>> For some this may be a simple preprocessor-type expansion while
>> > for others
>> > >>>>>>> there may be more sophisticated handling.  But the application
>> > should
>> > >>>>>>> neither know nor care about how the implementation chooses to do
>> > this.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN -
>> > FI/Espoo)
>> > >>>>>>> <petri.savolainen@nsn.com> wrote:
>> > >>>>>>>
>> > >>>>>>> Hi,
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> This is also my opinion. There’s no use case for segmented
>> buffers
>> > in
>> > >>>>>>> v1.0 - so let’s keep it simple and define that buffers (and thus
>> > buffer
>> > >>>>>>> pools) are always unsegmented. Segmentation comes into play only
>> > with
>> > >>>>>>> packets (and only with those packets that cannot fit into a
>> single
>> > buffer).
>> > >>>>>>> For example, if implementation has max buffer size 256, any
>> > packets larger
>> > >>>>>>> than that are segmented and segments are handled with
>> > packet_seg_xxx calls.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> Also, I’d propose that we optimize for the common case (with
>> > segments)
>> > >>>>>>> - so that the odp_packet_t handle would refer always to the head
>> > of packet
>> > >>>>>>> segment. If the first segment (data/data_len pointed by the
>> > odp_packet_t)
>> > >>>>>>> carries all data application is interested in (=protocol
>> headers),
>> > the
>> > >>>>>>> application would not have to use the segment API at all. Most
>> > applications
>> > >>>>>>> would not see any difference between small/large or
>> > segmented/unsegmented
>> > >>>>>>> packets as long as all headers fit into the first segment.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> -Petri
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> From: lng-odp-bounces@lists.linaro.org
>> > >>>>>>> [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of ext
>> Jacob,
>> > Jerin
>> > >>>>>>> Sent: Friday, October 17, 2014 9:34 AM
>> > >>>>>>> To: Bill Fischofer
>> > >>>>>>> Cc: lng-odp@lists.linaro.org
>> > >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
>> > API
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> The need for segment API infrastructure is very clear.The
>> question
>> > is,
>> > >>>>>>> Do we need separate APIs for
>> > >>>>>>>
>> > >>>>>>> segment management at odp_buffer_segment* AND
>> odp_packet_segment*
>> > >>>>>>> levels ?
>> > >>>>>>>
>> > >>>>>>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be
>> always
>> > >>>>>>> unsegmented and if there is a
>> > >>>>>>>
>> > >>>>>>> API for odp_packet_segement* then there will be not be any
>> > consumer
>> > >>>>>>> for odp_buffer_segment* API for 1.0
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> ________________________________
>> > >>>>>>>
>> > >>>>>>> From: Bill Fischofer <bill.fischofer@linaro.org>
>> > >>>>>>> Sent: Thursday, October 16, 2014 9:08 PM
>> > >>>>>>> To: Jacob, Jerin
>> > >>>>>>> Cc: Ola Liljedahl; Balasubramanian Manoharan; lng-
>> > odp@lists.linaro.org
>> > >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
>> > API
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> From the buffer design doc (p. 8-9):
>> > >>>>>>>
>> > >>>>>>> Buffer Pool Options
>> > >>>>>>>
>> > >>>>>>> The odp_buffer_opts_e enum is used to specify additional options
>> > >>>>>>> relating to the buffer pool.  Buffer pool options defined are:
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> ·     ODP_BUFFER_OPTS_NONE
>> > >>>>>>>
>> > >>>>>>> ·     ODP_BUFFER_OPTS_UNSEGMENTED
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> These options are additive so an application can simply specify
>> a
>> > >>>>>>> buf_opts by ORing together the options needed.  Note that buffer
>> > pool
>> > >>>>>>> options are themselves OPTIONAL and a given implementation MAY
>> > fail the
>> > >>>>>>> buffer pool creation request with an appropriate errno if the
>> > requested
>> > >>>>>>> option is not supported by the underlying ODP implementation,
>> with
>> > the
>> > >>>>>>> exception that UNSEGMENTED pools MUST be supported for
>> non-packet
>> > types and
>> > >>>>>>> for packet types as long as the requested size is less than the
>> > >>>>>>> implementation-defined native packet segment size.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options
>> > with
>> > >>>>>>> no additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies
>> > that the
>> > >>>>>>> buffer pool should be unsegmented.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> So unsegmented buffer pool support is available.  As far as RAW
>> > >>>>>>> buffers go, again from the doc (p. 14):
>> > >>>>>>>
>> > >>>>>>> ODP_BUFFER_TYPE_RAW
>> > >>>>>>>
>> > >>>>>>> This is the “basic” buffer type which simply consists of a
>> single
>> > >>>>>>> fixed-sized block of contiguous memory.  Buffers of this type do
>> > not support
>> > >>>>>>> user meta data and the only built-in meta data supported for
>> this
>> > type of
>> > >>>>>>> buffer are those that are statically computable, such as pool
>> and
>> > size. This
>> > >>>>>>> type of buffer is entirely under application control and most of
>> > the buffer
>> > >>>>>>> APIs defined in this document are not available.  APIs for this
>> > type of
>> > >>>>>>> buffer are described in this document.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> So RAW buffers are always unsegmented.  The intent is that
>> Packets
>> > are
>> > >>>>>>> by default segmented but can be unsegmented while the other
>> buffer
>> > types are
>> > >>>>>>> by default unsegmented but (with the exception of RAW buffers)
>> can
>> > be made
>> > >>>>>>> segmented.  This is because all buffers start out as a single
>> > segment and
>> > >>>>>>> hence are unsegmented until they are expanded to overflow that
>> > single
>> > >>>>>>> segment.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> Hope that clarifies things.  Again, this is all very
>> > straightforward
>> > >>>>>>> and only comes into play when actually needed.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin
>> > >>>>>>> <Jerin.Jacob@caviumnetworks.com> wrote:
>> > >>>>>>>
>> > >>>>>>> If there is no valid use case for supporting segmentation for
>> raw
>> > >>>>>>> buffers then lets drop it. At least it will reduce the effort of
>> > >>>>>>>
>> > >>>>>>> implementing and testing/verification buffer APIs on  different
>> > >>>>>>> platforms.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> ________________________________
>> > >>>>>>>
>> > >>>>>>> From: lng-odp-bounces@lists.linaro.org
>> > >>>>>>> <lng-odp-bounces@lists.linaro.org> on behalf of Ola Liljedahl
>> > >>>>>>> <ola.liljedahl@linaro.org>
>> > >>>>>>> Sent: Wednesday, October 8, 2014 1:37 PM
>> > >>>>>>> To: Balasubramanian Manoharan
>> > >>>>>>> Cc: lng-odp@lists.linaro.org
>> > >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support
>> > API
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> As I wrote in my comment to the architecture discussion
>> yesterday,
>> > I
>> > >>>>>>> am against segmentation for buffers. Or at least there must be
>> the
>> > >>>>>>> possibility to create a buffer pool with guaranteed
>> non-segmented
>> > buffers.
>> > >>>>>>> Segmented packets are OK but not all usages for buffers relate
>> to
>> > packets. A
>> > >>>>>>> lot of internal usages (timeouts, SW messages, internal data
>> > structures)
>> > >>>>>>> will not be able to handle segmented buffers so you must be able
>> > to force
>> > >>>>>>> the creation of buffer pools with non-segmented buffers.
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> -- Ola
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> On 8 October 2014 09:50, Balasubramanian Manoharan
>> > >>>>>>> <bala.manoharan@linaro.org> wrote:
>> > >>>>>>>
>> > >>>>>>> This patch contains ODP Buffer Management missing APIs
>> > >>>>>>> The intent of this patch is to port the missing APIs from Buffer
>> > >>>>>>> Management design document into Linux-generic repo.
>> > >>>>>>> The dummy functions will be replaced during linux-generic
>> > >>>>>>> implementation.
>> > >>>>>>>
>> > >>>>>>> Signed-off-by: Balasubramanian Manoharan
>> > <bala.manoharan@linaro.org>
>> > >>>>>>> ---
>> > >>>>>>>  platform/linux-generic/include/api/odp_buffer.h    | 203
>> > >>>>>>> ++++++++++++++++++++-
>> > >>>>>>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
>> > >>>>>>>  platform/linux-generic/odp_buffer.c                | 120
>> > ++++++++++++
>> > >>>>>>>  platform/linux-generic/odp_buffer_pool.c           |   7 +
>> > >>>>>>>  4 files changed, 351 insertions(+), 9 deletions(-)
>> > >>>>>>>
>> > >>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer.h
>> > >>>>>>> b/platform/linux-generic/include/api/odp_buffer.h
>> > >>>>>>> index d8577fd..aeb75ed 100644
>> > >>>>>>> --- a/platform/linux-generic/include/api/odp_buffer.h
>> > >>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer.h
>> > >>>>>>> @@ -28,8 +28,34 @@ extern "C" {
>> > >>>>>>>   */
>> > >>>>>>>  typedef uint32_t odp_buffer_t;
>> > >>>>>>>
>> > >>>>>>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>> > >>>>>>> +/**
>> > >>>>>>> +* ODP buffer segment
>> > >>>>>>> +*/
>> > >>>>>>> +typedef uint32_t odp_buffer_segment_t;
>> > >>>>>>>
>> > >>>>>>> +/**
>> > >>>>>>> +* ODP buffer type
>> > >>>>>>> +*/
>> > >>>>>>> +typedef enum odp_buffer_type {
>> > >>>>>>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type invalid
>> > */
>> > >>>>>>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can
>> hold
>> > any
>> > >>>>>>> other
>> > >>>>>>> +                                       buffer type */
>> > >>>>>>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
>> > >>>>>>> +                                       no additional metadata
>> */
>> > >>>>>>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
>> > >>>>>>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
>> > >>>>>>> +} odp_buffer_type_e;
>> > >>>>>>> +
>> > >>>>>>> +/**
>> > >>>>>>> +* ODP buffer options
>> > >>>>>>> +*/
>> > >>>>>>> +typedef enum odp_buffer_opts {
>> > >>>>>>> +       ODP_BUFFER_OPTS_NONE,
>> > >>>>>>> +       ODP_BUFFER_OPTS_UNSEGMENTED
>> > >>>>>>> +} odp_buffer_opts_e;
>> > >>>>>>> +
>> > >>>>>>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>> > >>>>>>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment
>> */
>> > >>>>>>>
>> > >>>>>>>  /**
>> > >>>>>>>   * Buffer start address
>> > >>>>>>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
>> > >>>>>>>   */
>> > >>>>>>>  int odp_buffer_type(odp_buffer_t buf);
>> > >>>>>>>
>> > >>>>>>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid
>> */
>> > >>>>>>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold
>> > any
>> > >>>>>>> other
>> > >>>>>>> -                                         buffer type */
>> > >>>>>>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no
>> > additional
>> > >>>>>>> metadata */
>> > >>>>>>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
>> > >>>>>>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
>> > >>>>>>> -
>> > >>>>>>> -
>> > >>>>>>>  /**
>> > >>>>>>>   * Tests if buffer is valid
>> > >>>>>>>   *
>> > >>>>>>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
>> > >>>>>>>  int odp_buffer_is_valid(odp_buffer_t buf);
>> > >>>>>>>
>> > >>>>>>>  /**
>> > >>>>>>> + * Tests if buffer is segmented
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  buf     Buffer handle
>> > >>>>>>> + *
>> > >>>>>>> + * @return             1 if buffer has more than one segment,
>> > >>>>>>> + *                     otherwise 0
>> > >>>>>>> + */
>> > >>>>>>> +
>> > >>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf);
>> > >>>>>>> +
>> > >>>>>>> +/**
>> > >>>>>>> + * Get address and size of user meta data associated with a
>> > buffer
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  buf             Buffer handle
>> > >>>>>>> + * @param[out] udata_size      Number of bytes of user meta
>> data
>> > >>>>>>> available
>> > >>>>>>> + *                             at the returned address
>> > >>>>>>> + * @return                     Address of the user meta data
>> for
>> > this
>> > >>>>>>> buffer
>> > >>>>>>> + *                             or NULL if the buffer has no
>> user
>> > meta
>> > >>>>>>> data.
>> > >>>>>>> + */
>> > >>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
>> > >>>>>>> +
>> > >>>>>>> +/**
>> > >>>>>>> + * Get address of user meta data associated with a buffer
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  buf     Buffer handle
>> > >>>>>>> + *
>> > >>>>>>> + * @return             Address of the user meta data for this
>> > buffer
>> > >>>>>>> + *                     or NULL if the buffer has no user meta
>> > data.
>> > >>>>>>> + */
>> > >>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf);
>> > >>>>>>> +
>> > >>>>>>> +/**
>> > >>>>>>> + * Get count of number of segments in a buffer
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  buf     Buffer handle
>> > >>>>>>> + *
>> > >>>>>>> + * @return             Count of the number of segments in buf
>> > >>>>>>> + */
>> > >>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf);
>> > >>>>>>> +
>> > >>>>>>> +/**
>> > >>>>>>> + * Get the segment identifier for a buffer segment by index
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  buf     Buffer handle
>> > >>>>>>> + * @param[in]  ndx     Segment index of segment of interest
>> > >>>>>>> + *
>> > >>>>>>> + * @return             Segment identifier or
>> ODP_SEGMENT_INVALID
>> > if
>> > >>>>>>> the
>> > >>>>>>> + *                     supplied ndx is out of range.
>> > >>>>>>> + */
>> > >>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t
>> > buf,
>> > >>>>>>> size_t ndx);
>> > >>>>>>> +
>> > >>>>>>> +/**
>> > >>>>>>> + * Get the next segment identifier for a buffer segment
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  buf     Buffer handle
>> > >>>>>>> + * @param[in]  seg     Segment identifier of the previous
>> segment
>> > >>>>>>> + *
>> > >>>>>>> + * @return             Segment identifier of the next segment,
>> > >>>>>>> +                       or ODP_SEGMENT_INVALID.
>> > >>>>>>> + */
>> > >>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>> > >>>>>>> +
>> odp_buffer_segment_t
>> > >>>>>>> seg);
>> > >>>>>>> +/**
>> > >>>>>>> + * Get start address for a specified buffer segment
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  buf     Buffer handle
>> > >>>>>>> + * @param[in]  seg     Segment identifier of the buffer to be
>> > >>>>>>> addressed
>> > >>>>>>> + * @param[out] seglen  Returned number of bytes in this buffer
>> > >>>>>>> + *                     segment available at returned address
>> > >>>>>>> + *
>> > >>>>>>> + * @return             Segment start address or NULL
>> > >>>>>>> + */
>> > >>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf,
>> > odp_buffer_segment_t
>> > >>>>>>> seg,
>> > >>>>>>> +size_t *seglen);
>> > >>>>>>> +
>> > >>>>>>> +/**
>> > >>>>>>> + *Unmap a buffer segment
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  seg     Buffer segment handle
>> > >>>>>>> + */
>> > >>>>>>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
>> > >>>>>>> +
>> > >>>>>>> +/**
>> > >>>>>>> +* Get start address for a specified buffer offset
>> > >>>>>>> +*
>> > >>>>>>> +* @param[in]   buf     Buffer handle
>> > >>>>>>> +* @param[in]   offset  Byte offset within the buffer to be
>> > addressed
>> > >>>>>>> +* @param[out]  seglen  Returned number of bytes in this buffer
>> > >>>>>>> +*                      segment available at returned address
>> > >>>>>>> +*
>> > >>>>>>> +* @return              Offset start address or NULL
>> > >>>>>>> +*/
>> > >>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>> > >>>>>>> +size_t *seglen);
>> > >>>>>>> +
>> > >>>>>>> +/**
>> > >>>>>>> + * Unmap a buffer segment by offset
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  buf     Buffer handle
>> > >>>>>>> + * @param[in]  offset  Buffer offset
>> > >>>>>>> + */
>> > >>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
>> > >>>>>>> +
>> > >>>>>>> +/**
>> > >>>>>>>   * Print buffer metadata to STDOUT
>> > >>>>>>>   *
>> > >>>>>>>   * @param buf      Buffer handle
>> > >>>>>>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
>> > >>>>>>>   */
>> > >>>>>>>  void odp_buffer_print(odp_buffer_t buf);
>> > >>>>>>>
>> > >>>>>>> +/**
>> > >>>>>>> + * Split a buffer into two buffers at a specified split point
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  buf     Handle of buffer to split
>> > >>>>>>> + * @param[in]  offset  Byte offset within buf to split buffer
>> > >>>>>>> + *
>> > >>>>>>> + * @return             Buffer handle of the created split
>> buffer
>> > >>>>>>> + */
>> > >>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
>> > >>>>>>> +
>> > >>>>>>> +/**
>> > >>>>>>> + * Join two buffers into a single buffer
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  buf1    Buffer handle of first buffer to join
>> > >>>>>>> + * @param[in]  buf2    Buffer handle of second buffer to join
>> > >>>>>>> + *
>> > >>>>>>> + * @return             Buffer handle of the joined buffer
>> > >>>>>>> + */
>> > >>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t
>> > buf2);
>> > >>>>>>> +
>> > >>>>>>> +/**
>> > >>>>>>> + * Trim a buffer at a specified trim point
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  buf     Buffer handle of buffer to trim
>> > >>>>>>> + * @param[in]  offset  byte offset within buf to trim
>> > >>>>>>> + *
>> > >>>>>>> + * @return             Handle of the trimmed buffer or
>> > >>>>>>> + *                     ODP_BUFFER_INVALID if the operation was
>> > not
>> > >>>>>>> performed
>> > >>>>>>> + */
>> > >>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
>> > >>>>>>> +/**
>> > >>>>>>> + * Extend a buffer for a specified number of bytes
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  buf     Buffer handle of buffer to expand
>> > >>>>>>> + * @param[in]  ext     size, in bytes, of the extent to add to
>> > the
>> > >>>>>>> + *                     existing buffer.
>> > >>>>>>> + *
>> > >>>>>>> + * @return             Handle of the extended buffer or
>> > >>>>>>> ODP_BUFFER_INVALID
>> > >>>>>>> + *                     if the operation was not performed
>> > >>>>>>> + */
>> > >>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
>> > >>>>>>> +
>> > >>>>>>> +/**
>> > >>>>>>> + * Clone a buffer, returning an exact copy of it
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  buf     Buffer handle of buffer to duplicate
>> > >>>>>>> + *
>> > >>>>>>> + * @return             Handle of the duplicated buffer or
>> > >>>>>>> ODP_BUFFER_INVALID
>> > >>>>>>> + *                     if the operation was not performed
>> > >>>>>>> + */
>> > >>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
>> > >>>>>>> +
>> > >>>>>>> +/**
>> > >>>>>>> + * Copy a buffer, returning an exact copy of it
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  buf     Buffer handle of buffer to copy
>> > >>>>>>> + *
>> > >>>>>>> + * @return             Handle of the copied buffer or
>> > >>>>>>> ODP_BUFFER_INVALID
>> > >>>>>>> + *                     if the operation was not performed
>> > >>>>>>> + */
>> > >>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
>> > >>>>>>> +
>> > >>>>>>> +
>> > >>>>>>>
>> > >>>>>>>  #ifdef __cplusplus
>> > >>>>>>>  }
>> > >>>>>>> diff --git
>> a/platform/linux-generic/include/api/odp_buffer_pool.h
>> > >>>>>>> b/platform/linux-generic/include/api/odp_buffer_pool.h
>> > >>>>>>> index fe88898..f85d96c 100644
>> > >>>>>>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
>> > >>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
>> > >>>>>>> @@ -52,6 +52,27 @@ odp_buffer_pool_t
>> odp_buffer_pool_create(const
>> > char
>> > >>>>>>> *name,
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>  /**
>> > >>>>>>> + * Get the next buffer pool from its predecessor
>> > >>>>>>> + *
>> > >>>>>>> + * @param[in]  pool            Buffer pool handle
>> > >>>>>>> + * @param[out] name            Name of the pool
>> > >>>>>>> + *                             (max ODP_BUFFER_POOL_NAME_LEN -
>> 1
>> > >>>>>>> chars)
>> > >>>>>>> + * @param[out] udata_size      Size of user meta data used by
>> > this
>> > >>>>>>> pool.
>> > >>>>>>> + * @param[out] buf_num         Number of buffers contained in
>> > this
>> > >>>>>>> pool
>> > >>>>>>> + * @param[out] buf_size        Default size of application data
>> > in
>> > >>>>>>> each buffer
>> > >>>>>>> + * @param[out] buf_type        Buffer type of the pool
>> > >>>>>>> + * @param[out] buf_opts        Buffer options for this pool
>> > >>>>>>> + * @param[out] predef          Predefined (1) or Created (0).
>> > >>>>>>> + *
>> > >>>>>>> + * @return                     Buffer pool handle
>> > >>>>>>> + */
>> > >>>>>>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
>> > >>>>>>> +                                      char *name, size_t
>> > *udata_size,
>> > >>>>>>> +                                      size_t *buf_num, size_t
>> > >>>>>>> *buf_size,
>> > >>>>>>> +                                      enum odp_buffer_type
>> > *buf_type,
>> > >>>>>>> +                                      enum odp_buffer_opts
>> > *buf_opts,
>> > >>>>>>> +                                      uint32_t *predef);
>> > >>>>>>> +/**
>> > >>>>>>>   * Find a buffer pool by name
>> > >>>>>>>   *
>> > >>>>>>>   * @param name      Name of the pool
>> > >>>>>>> @@ -80,6 +101,15 @@ void odp_buffer_pool_print(odp_buffer_pool_t
>> > >>>>>>> pool);
>> > >>>>>>>   */
>> > >>>>>>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
>> > >>>>>>>
>> > >>>>>>> +/**
>> > >>>>>>> +* Allocate a buffer from a buffer pool
>> > >>>>>>> +*
>> > >>>>>>> +* @param[in]   pool    Pool handle
>> > >>>>>>> +* @param[in]   size    Size of object to store in buffer
>> > >>>>>>> +*
>> > >>>>>>> +* @return              Buffer handle or ODP_BUFFER_INVALID
>> > >>>>>>> +*/
>> > >>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool,
>> size_t
>> > >>>>>>> size);
>> > >>>>>>>
>> > >>>>>>>  /**
>> > >>>>>>>   * Buffer free
>> > >>>>>>> diff --git a/platform/linux-generic/odp_buffer.c
>> > >>>>>>> b/platform/linux-generic/odp_buffer.c
>> > >>>>>>> index e54e0e7..7f4b4f0 100644
>> > >>>>>>> --- a/platform/linux-generic/odp_buffer.c
>> > >>>>>>> +++ b/platform/linux-generic/odp_buffer.c
>> > >>>>>>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
>> > >>>>>>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
>> > >>>>>>>  }
>> > >>>>>>>
>> > >>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf)
>> > >>>>>>> +{
>> > >>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>> > >>>>>>> +
>> > >>>>>>> +       if (buf_hdr->scatter.num_bufs == 0)
>> > >>>>>>> +               return 0;
>> > >>>>>>> +       else
>> > >>>>>>> +               return 1;
>> > >>>>>>> +}
>> > >>>>>>> +
>> > >>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf)
>> > >>>>>>> +{
>> > >>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>> > >>>>>>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
>> > >>>>>>> +}
>> > >>>>>>>
>> > >>>>>>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
>> > >>>>>>>  {
>> > >>>>>>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
>> > >>>>>>>         printf("\n%s\n", str);
>> > >>>>>>>  }
>> > >>>>>>>
>> > >>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
>> > >>>>>>> +{
>> > >>>>>>> +       (void)buf;
>> > >>>>>>> +       (void)udata_size;
>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>> > >>>>>>> +       return 0;
>> > >>>>>>> +}
>> > >>>>>>> +
>> > >>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf)
>> > >>>>>>> +{
>> > >>>>>>> +       (void)buf;
>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>> > >>>>>>> +       return 0;
>> > >>>>>>> +}
>> > >>>>>>> +
>> > >>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t
>> > buf,
>> > >>>>>>> +                                                size_t ndx)
>> > >>>>>>> +{
>> > >>>>>>> +       (void)buf;
>> > >>>>>>> +       (void)ndx;
>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>> > >>>>>>> +       return 0;
>> > >>>>>>> +}
>> > >>>>>>> +
>> > >>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>> > >>>>>>> +
>> odp_buffer_segment_t
>> > seg)
>> > >>>>>>> +{
>> > >>>>>>> +       (void)buf;
>> > >>>>>>> +       (void)seg;
>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>> > >>>>>>> +       return 0;
>> > >>>>>>> +}
>> > >>>>>>> +
>> > >>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf,
>> > odp_buffer_segment_t
>> > >>>>>>> seg,
>> > >>>>>>> +                            size_t *seglen)
>> > >>>>>>> +{
>> > >>>>>>> +       (void)buf;
>> > >>>>>>> +       (void)seg;
>> > >>>>>>> +       (void)seglen;
>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>> > >>>>>>> +       return 0;
>> > >>>>>>> +}
>> > >>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>> > >>>>>>> +size_t *seglen)
>> > >>>>>>> +{
>> > >>>>>>> +       (void)buf;
>> > >>>>>>> +       (void)offset;
>> > >>>>>>> +       (void)seglen;
>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>> > >>>>>>> +       return 0;
>> > >>>>>>> +}
>> > >>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
>> > >>>>>>> +{
>> > >>>>>>> +       (void)buf;
>> > >>>>>>> +       (void)offset;
>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>> > >>>>>>> +       return;
>> > >>>>>>> +}
>> > >>>>>>> +
>> > >>>>>>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t
>> > >>>>>>> buf_src)
>> > >>>>>>>  {
>> > >>>>>>>         (void)buf_dst;
>> > >>>>>>>         (void)buf_src;
>> > >>>>>>>  }
>> > >>>>>>> +
>> > >>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
>> > >>>>>>> +{
>> > >>>>>>> +       (void)buf;
>> > >>>>>>> +       (void)offset;
>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>> > >>>>>>> +       return 0;
>> > >>>>>>> +}
>> > >>>>>>> +
>> > >>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t
>> > buf2)
>> > >>>>>>> +{
>> > >>>>>>> +       (void)buf1;
>> > >>>>>>> +       (void)buf2;
>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>> > >>>>>>> +       return 0;
>> > >>>>>>> +}
>> > >>>>>>> +
>> > >>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
>> > >>>>>>> +{
>> > >>>>>>> +       (void)buf;
>> > >>>>>>> +       (void)offset;
>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>> > >>>>>>> +       return 0;
>> > >>>>>>> +}
>> > >>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
>> > >>>>>>> +{
>> > >>>>>>> +       (void)buf;
>> > >>>>>>> +       (void)ext;
>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>> > >>>>>>> +       return 0;
>> > >>>>>>> +}
>> > >>>>>>> +
>> > >>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
>> > >>>>>>> +{
>> > >>>>>>> +       (void)buf;
>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>> > >>>>>>> +       return 0;
>> > >>>>>>> +}
>> > >>>>>>> +
>> > >>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
>> > >>>>>>> +{
>> > >>>>>>> +       (void)buf;
>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>> > >>>>>>> +       return 0;
>> > >>>>>>> +}
>> > >>>>>>> +
>> > >>>>>>> diff --git a/platform/linux-generic/odp_buffer_pool.c
>> > >>>>>>> b/platform/linux-generic/odp_buffer_pool.c
>> > >>>>>>> index a48d7d6..bff4db5 100644
>> > >>>>>>> --- a/platform/linux-generic/odp_buffer_pool.c
>> > >>>>>>> +++ b/platform/linux-generic/odp_buffer_pool.c
>> > >>>>>>> @@ -471,6 +471,13 @@ odp_buffer_t
>> > odp_buffer_alloc(odp_buffer_pool_t
>> > >>>>>>> pool_hdl)
>> > >>>>>>>         return handle.u32;
>> > >>>>>>>  }
>> > >>>>>>>
>> > >>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool,
>> size_t
>> > >>>>>>> size)
>> > >>>>>>> +{
>> > >>>>>>> +       (void)pool;
>> > >>>>>>> +       (void) size;
>> > >>>>>>> +       ODP_ERR("%s function is yet to be implemented",
>> __func__);
>> > >>>>>>> +       return 0;
>> > >>>>>>> +}
>> > >>>>>>>
>> > >>>>>>>  void odp_buffer_free(odp_buffer_t buf)
>> > >>>>>>>  {
>> > >>>>>>> --
>> > >>>>>>> 2.0.1.472.g6f92e5f
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> _______________________________________________
>> > >>>>>>> lng-odp mailing list
>> > >>>>>>> lng-odp@lists.linaro.org
>> > >>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>> _______________________________________________
>> > >>>>>>> lng-odp mailing list
>> > >>>>>>> lng-odp@lists.linaro.org
>> > >>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>>
>> > >>>>>>
>> > >>>>>>
>> > >>>>>>
>> > >>>>>> _______________________________________________
>> > >>>>>> lng-odp mailing list
>> > >>>>>> lng-odp@lists.linaro.org
>> > >>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>> > >>>>>>
>> > >>>>>
>> > >>>>>
>> > >>>>> _______________________________________________
>> > >>>>> lng-odp mailing list
>> > >>>>> lng-odp@lists.linaro.org
>> > >>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>> > >>>>>
>> > >>>>
>> > >>>
>> > >>
>> > >>
>> > >> _______________________________________________
>> > >> lng-odp mailing list
>> > >> lng-odp@lists.linaro.org
>> > >> http://lists.linaro.org/mailman/listinfo/lng-odp
>> > >>
>>
>
>
Balasubramanian Manoharan Nov. 1, 2014, 7:49 a.m. UTC | #20
Hi,

This patch will have to be modified as we have decided to move the
segmentation support in packet header file.
I will provide an updated patch for the same.

Regards,
Bala

On 31 October 2014 20:24, Bill Fischofer <bill.fischofer@linaro.org> wrote:

> This patch does not apply to the current repository.  Is there a revised
> version available?
>
> Thanks.
>
> Bill
>
> On Wed, Oct 22, 2014 at 8:47 AM, Bill Fischofer <bill.fischofer@linaro.org
> > wrote:
>
>> I had previously detailed some of the problems that arise if we remove
>> segmentation support from buffers while trying to keep it as part of
>> packets.  I'd still like to see a response to these questions.  Given that
>> we support unsegmented buffers I don't see what the objection is here.
>> Those that don't want to deal with segments need not deal with them at
>> all.  That may limit the platforms they can run on, but applications will
>> always choose which implementations are best suited to their needs.
>>
>> Bill
>>
>> On Wed, Oct 22, 2014 at 7:27 AM, Savolainen, Petri (NSN - FI/Espoo) <
>> petri.savolainen@nsn.com> wrote:
>>
>>> Hi,
>>>
>>> In short, I think we must not bring segmentation support to the buffer
>>> level "just in case" someone would need it there. Real use cases for
>>> segmentation are on packet level (large packets, packet
>>> fragmentation/reassembly, etc), so the feature should be implemented there.
>>>
>>> -Petri
>>>
>>> > -----Original Message-----
>>> > From: ext Ciprian Barbu [mailto:ciprian.barbu@linaro.org]
>>> > Sent: Wednesday, October 22, 2014 3:00 PM
>>> > To: Bill Fischofer
>>> > Cc: Ola Liljedahl; Savolainen, Petri (NSN - FI/Espoo); lng-
>>> > odp@lists.linaro.org
>>> > Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment Support API
>>> >
>>> > On Wed, Oct 22, 2014 at 2:47 PM, Ciprian Barbu <
>>> ciprian.barbu@linaro.org>
>>> > wrote:
>>> > > This thread has been cold for 5 days, so the assumption is that we
>>> can
>>> > > go forward with the design right now. This patch series proposed by
>>> > > Bala updates some part of the API to the final form of the Buffer
>>> > > Design Document, we should have it merged if there are no more
>>> > > objections. For that more people with the right expertise should have
>>> > > a look at it and get the thread back on track.
>>> > >
>>> > > I for example have observed the following issue. All the examples
>>> > > create buffer pools over shared memory, which doesn't make sense for
>>> > > some platforms, linux-dpdk for example, which ignores the base_addr
>>> > > argument altogether. I think we need more clarity on this subject,
>>> for
>>> > > sure the creation of buffer pools will differ from platform to
>>> > > platform, which migrates to the application responsibility.
>>> > >
>>> > > I think we should have a helper function to easily create buffer
>>> pools
>>> > > without worrying too much about the difference in buffer management
>>> > > between platforms, so that one can write a simple portable
>>> application
>>> > > with no sweat. For the hardcore programmers the API still gives fine
>>> > > control to buffer management that depending on the platform could
>>> > > involve additional prerequisites, like creating a shared memory
>>> > > segment to hold the buffer pool.
>>> >
>>> > Ok, so I had another look at the Buffer Management final design. I now
>>> > see that the option of creating buffer pools from regions has been
>>> > removed, so in this case things will be simpler for the applications.
>>> > In other words we should really start working on the full
>>> > implementation of the API because from there the problem I just stated
>>> > above (having to create shared memory segments) will disappear.
>>> >
>>> > >
>>> > > On Fri, Oct 17, 2014 at 4:33 PM, Bill Fischofer
>>> > > <bill.fischofer@linaro.org> wrote:
>>> > >> Let's consider the implications of removing segmentation support
>>> from
>>> > >> buffers and only having that concept be part of packets.
>>> > >>
>>> > >> The first question that arises is what is the relationship between
>>> the
>>> > >> abstract types odp_packet_t and odp_buffer_t? This is important
>>> because
>>> > >> currently we say that packets are allocated from ODP buffer pools,
>>> not
>>> > from
>>> > >> packet pools.  Do we need a separate odp_packet_pool_t that is used
>>> for
>>> > >> packets?
>>> > >>
>>> > >> Today, when I allocate a packet I'm allocating a single object that
>>> > happens
>>> > >> to be a single buffer object of type ODP_BUFFER_TYPE_PACKET.  But
>>> that
>>> > only
>>> > >> works if the two objects have compatible semantics (including
>>> > segmentation).
>>> > >> If the semantics are not compatible, then an odp_packet_t may in
>>> fact
>>> > be
>>> > >> composed of multiple odp_buffer_t's because the packet may consist
>>> of
>>> > >> multiple segments and buffers no longer recognize the concept of
>>> > segments so
>>> > >> a single buffer can only be a single segment.
>>> > >>
>>> > >> So now an odp_packet_segment_t may be an odp_buffer_t but an
>>> > odp_packet_t in
>>> > >> fact is some meta-object that is constructed (by whom?) from
>>> multiple
>>> > >> odp_packet_segment_ts that are themselves odp_buffer_ts.  So
>>> > >> odp_packet_to_buffer() no longer makes sense since there is no
>>> longer a
>>> > >> one-to-one correspondence between packets and buffers.  We could
>>> have
>>> > an
>>> > >> odp_packet_segment_to_buffer() routine instead.
>>> > >>
>>> > >> Next question: What about meta data?  If an odp_packet_t is a type
>>> of
>>> > an
>>> > >> odp_buffer_t then this is very straightforward since all buffer meta
>>> > data is
>>> > >> reusable as packet meta data and the packet type can just add its
>>> own
>>> > >> specific meta data to this set.  But if an odp_packet_t is now a
>>> > separate
>>> > >> object then where does the storage for its meta data come from? If
>>> we
>>> > try to
>>> > >> map it into an odp_buffer_t that doesn't work since an odp_packet_t
>>> may
>>> > >> consist of multiple underlying odp_buffer_ts, one for each
>>> > >> odp_packet_segment_t.  Is the packet meta data duplicated in each
>>> > segment?
>>> > >> Is the first segment of a packet special
>>> (odp_packet_first_segment_t)?
>>> > And
>>> > >> what about user meta data, since this is of potentially variable
>>> size?
>>> > >>
>>> > >> I submit that there are a lot of implications to this that need to
>>> be
>>> > fully
>>> > >> thought through, which is why I believe it's simpler to keep
>>> > segmentation as
>>> > >> part of buffers that (for now) only happens to be used by a
>>> particular
>>> > type
>>> > >> of buffer, namely packets.
>>> > >>
>>> > >> Bill
>>> > >>
>>> > >> On Fri, Oct 17, 2014 at 8:05 AM, Ola Liljedahl
>>> > <ola.liljedahl@linaro.org>
>>> > >> wrote:
>>> > >>>
>>> > >>> Personally I don't see any need for segmentation support in
>>> buffers. I
>>> > am
>>> > >>> just trying to shoot down what I think is flawed reasoning.
>>> > >>>
>>> > >>> -- Ola#1
>>> > >>>
>>> > >>> On 17 October 2014 15:03, Ola Liljedahl <ola.liljedahl@linaro.org>
>>> > wrote:
>>> > >>>>
>>> > >>>> But segmentation is already needed in a current and known subclass
>>> > (i.e.
>>> > >>>> packets). We are not talking about some other feature which we
>>> don't
>>> > know if
>>> > >>>> it will be needed. So this is not a case of "just in case".
>>> > >>>>
>>> > >>>> -- Ola#1
>>> > >>>>
>>> > >>>>
>>> > >>>> On 17 October 2014 14:45, Ola Dahl <dahl.ola@gmail.com> wrote:
>>> > >>>>>
>>> > >>>>> Hi,
>>> > >>>>>
>>> > >>>>> I do not think it is wise to put features in the base class
>>> "just in
>>> > >>>>> case" they would be needed in some future (not yet known)
>>> subclass.
>>> > >>>>>
>>> > >>>>> So if the concept of segmentation is relevant for packets but not
>>> > for
>>> > >>>>> timers then I think it should be implemented as a feature of
>>> > packets.
>>> > >>>>>
>>> > >>>>> Best regards,
>>> > >>>>>
>>> > >>>>> Ola D
>>> > >>>>>
>>> > >>>>> On Fri, Oct 17, 2014 at 2:33 PM, Bill Fischofer
>>> > >>>>> <bill.fischofer@linaro.org> wrote:
>>> > >>>>>>
>>> > >>>>>> I agree that packets are the buffer type that most likely uses
>>> > >>>>>> segments, however there are many advantages to putting this
>>> support
>>> > in the
>>> > >>>>>> base class rather than the subclass independent of the number of
>>> > buffer
>>> > >>>>>> subclasses that will use this support today.
>>> > >>>>>>
>>> > >>>>>> It's simpler
>>> > >>>>>> It's more extensible
>>> > >>>>>> It results in cleaner and more efficient application code
>>> > >>>>>>
>>> > >>>>>> Allow me to expand on these points.  First simplicity.  Call the
>>> > work
>>> > >>>>>> required to support segmentation in the implementation X.  That
>>> X
>>> > is going
>>> > >>>>>> to be pretty much constant no matter where it is done.  But if
>>> the
>>> > >>>>>> implementation has a choice between doing X at a low level vs.
>>> > doing it at a
>>> > >>>>>> high level then it's simpler for the implementation to do it
>>> once
>>> > and be
>>> > >>>>>> done with it.  If the implementation does it at a higher level
>>> then
>>> > it is
>>> > >>>>>> either constrained to map that higher-level implementation to be
>>> > built on a
>>> > >>>>>> set of lower-level functions that may or may not be appropriate
>>> or
>>> > else it
>>> > >>>>>> needs to do a completely parallel implementation that is optimal
>>> > but highly
>>> > >>>>>> duplicative.
>>> > >>>>>>
>>> > >>>>>> Extensibility should be clear.  If at some future point we
>>> decide
>>> > >>>>>> segmentation would be useful for some new buffer type (e.g.,
>>> IPC)
>>> > then
>>> > >>>>>> that's trivial to do if the base class supports it and awkward
>>> if
>>> > it's only
>>> > >>>>>> part of packets.
>>> > >>>>>>
>>> > >>>>>> From an application standpoint, it's cleaner because the packet
>>> > APIs
>>> > >>>>>> are just wrappers around their corresponding buffer APIs and
>>> can be
>>> > mapped
>>> > >>>>>> directly.  Otherwise we have a set of APIs that don't map and
>>> are
>>> > not easily
>>> > >>>>>> translatable.
>>> > >>>>>>
>>> > >>>>>> With regard to efficient segment access, that's what the
>>> > >>>>>> odp_packet_addr() routine provides--one-step fast-path
>>> > addressability to the
>>> > >>>>>> first segment of a packet.  An odp_packet_t is an abstract
>>> opaque
>>> > type.  It
>>> > >>>>>> is not, and cannot be treated as an address by the application.
>>> > >>>>>>
>>> > >>>>>> Does that make sense?
>>> > >>>>>>
>>> > >>>>>> Bill
>>> > >>>>>>
>>> > >>>>>>
>>> > >>>>>>
>>> > >>>>>>
>>> > >>>>>> On Fri, Oct 17, 2014 at 5:37 AM, Savolainen, Petri (NSN -
>>> FI/Espoo)
>>> > >>>>>> <petri.savolainen@nsn.com> wrote:
>>> > >>>>>>>
>>> > >>>>>>> Hi,
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> 1. The only segmentation use case is for segmented packet, not
>>> for
>>> > >>>>>>> segmented buffers.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> 2. Common case for packets is that everything application
>>> needs is
>>> > in
>>> > >>>>>>> the first segment. Odp_packet_t could refer always into that
>>> > “first
>>> > >>>>>>> segment”, so that application (in the common case) would not
>>> need
>>> > to use
>>> > >>>>>>> odp_packet_seg_xxx() calls at all – only odp_packet_xxx()
>>> calls.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> When buffer level features are minimized, the need for
>>> > >>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...) is minimized. All
>>> > packet
>>> > >>>>>>> manipulation should happen through odp_packet_xxx(pkt, …)
>>> calls.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> -Petri
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> From: ext Bill Fischofer [mailto:bill.fischofer@linaro.org]
>>> > >>>>>>> Sent: Friday, October 17, 2014 1:17 PM
>>> > >>>>>>> To: Savolainen, Petri (NSN - FI/Espoo)
>>> > >>>>>>> Cc: ext Jacob, Jerin; lng-odp@lists.linaro.org
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment
>>> Support
>>> > API
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> I'm not sure how to understand these two statements:
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> 1. There's no use case for segmented buffers
>>> > >>>>>>>
>>> > >>>>>>> 2. We should optimize for the common case (with segments)
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> These seem contradictory.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> The use case for segmented buffers is that some platforms have
>>> a
>>> > >>>>>>> HW-defined and managed segmented buffer model. If we insist
>>> that
>>> > the
>>> > >>>>>>> application be able to specify and control packet segment
>>> sizes we
>>> > are
>>> > >>>>>>> making the decision to exclude such platforms from supporting
>>> ODP.
>>> > The
>>> > >>>>>>> optimization suggested is precisely what is being proposed
>>> here.
>>> > By default
>>> > >>>>>>> packets are assumed to be contained in implementation-managed
>>> > segmented
>>> > >>>>>>> buffers and the first segment will be large enough to contain
>>> all
>>> > packet
>>> > >>>>>>> headers for non-pathological cases.  The case where the
>>> > application wishes
>>> > >>>>>>> to traverse the entire packet in SW is expected to be rare
>>> because
>>> > in the
>>> > >>>>>>> data plane you simply do not have the cycles to do this at line
>>> > rate for all
>>> > >>>>>>> packets.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> As for having both odp_buffer_xxx() and odp_packet_xxx() APIs,
>>> > this is
>>> > >>>>>>> simply syntax to avoid the constant need for explicit
>>> conversion
>>> > functions
>>> > >>>>>>> since unlike C++, C does not support generic functions.  So you
>>> > cannot pass
>>> > >>>>>>> an odp_packet_t to a function that expects an odp_buffer_t
>>> > argument without
>>> > >>>>>>> a conversion call.  Do we really want to force applications to
>>> > constantly be
>>> > >>>>>>> writing code like:
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> odp_buffer_xxx(odp_packet_to_buffer(pkt),...)
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> rather than
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> odp_packet_xxx(pkt,...)
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> Not only is this awkward, it is also inefficient.  By having
>>> the
>>> > >>>>>>> explicit odp_packet_xxx() calls, the implementation is free to
>>> > optimize
>>> > >>>>>>> these references in whatever manner is appropriate to that
>>> > implementation.
>>> > >>>>>>> For some this may be a simple preprocessor-type expansion while
>>> > for others
>>> > >>>>>>> there may be more sophisticated handling.  But the application
>>> > should
>>> > >>>>>>> neither know nor care about how the implementation chooses to
>>> do
>>> > this.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> On Fri, Oct 17, 2014 at 2:27 AM, Savolainen, Petri (NSN -
>>> > FI/Espoo)
>>> > >>>>>>> <petri.savolainen@nsn.com> wrote:
>>> > >>>>>>>
>>> > >>>>>>> Hi,
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> This is also my opinion. There’s no use case for segmented
>>> buffers
>>> > in
>>> > >>>>>>> v1.0 - so let’s keep it simple and define that buffers (and
>>> thus
>>> > buffer
>>> > >>>>>>> pools) are always unsegmented. Segmentation comes into play
>>> only
>>> > with
>>> > >>>>>>> packets (and only with those packets that cannot fit into a
>>> single
>>> > buffer).
>>> > >>>>>>> For example, if implementation has max buffer size 256, any
>>> > packets larger
>>> > >>>>>>> than that are segmented and segments are handled with
>>> > packet_seg_xxx calls.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> Also, I’d propose that we optimize for the common case (with
>>> > segments)
>>> > >>>>>>> - so that the odp_packet_t handle would refer always to the
>>> head
>>> > of packet
>>> > >>>>>>> segment. If the first segment (data/data_len pointed by the
>>> > odp_packet_t)
>>> > >>>>>>> carries all data application is interested in (=protocol
>>> headers),
>>> > the
>>> > >>>>>>> application would not have to use the segment API at all. Most
>>> > applications
>>> > >>>>>>> would not see any difference between small/large or
>>> > segmented/unsegmented
>>> > >>>>>>> packets as long as all headers fit into the first segment.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> -Petri
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> From: lng-odp-bounces@lists.linaro.org
>>> > >>>>>>> [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of ext
>>> Jacob,
>>> > Jerin
>>> > >>>>>>> Sent: Friday, October 17, 2014 9:34 AM
>>> > >>>>>>> To: Bill Fischofer
>>> > >>>>>>> Cc: lng-odp@lists.linaro.org
>>> > >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment
>>> Support
>>> > API
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> The need for segment API infrastructure is very clear.The
>>> question
>>> > is,
>>> > >>>>>>> Do we need separate APIs for
>>> > >>>>>>>
>>> > >>>>>>> segment management at odp_buffer_segment* AND
>>> odp_packet_segment*
>>> > >>>>>>> levels ?
>>> > >>>>>>>
>>> > >>>>>>> as ODP_BUFFER_TYPE_TIMEOUT and ODP_BUFFER_TYPE_RAW will be
>>> always
>>> > >>>>>>> unsegmented and if there is a
>>> > >>>>>>>
>>> > >>>>>>> API for odp_packet_segement* then there will be not be any
>>> > consumer
>>> > >>>>>>> for odp_buffer_segment* API for 1.0
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> ________________________________
>>> > >>>>>>>
>>> > >>>>>>> From: Bill Fischofer <bill.fischofer@linaro.org>
>>> > >>>>>>> Sent: Thursday, October 16, 2014 9:08 PM
>>> > >>>>>>> To: Jacob, Jerin
>>> > >>>>>>> Cc: Ola Liljedahl; Balasubramanian Manoharan; lng-
>>> > odp@lists.linaro.org
>>> > >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment
>>> Support
>>> > API
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> From the buffer design doc (p. 8-9):
>>> > >>>>>>>
>>> > >>>>>>> Buffer Pool Options
>>> > >>>>>>>
>>> > >>>>>>> The odp_buffer_opts_e enum is used to specify additional
>>> options
>>> > >>>>>>> relating to the buffer pool.  Buffer pool options defined are:
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> ·     ODP_BUFFER_OPTS_NONE
>>> > >>>>>>>
>>> > >>>>>>> ·     ODP_BUFFER_OPTS_UNSEGMENTED
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> These options are additive so an application can simply
>>> specify a
>>> > >>>>>>> buf_opts by ORing together the options needed.  Note that
>>> buffer
>>> > pool
>>> > >>>>>>> options are themselves OPTIONAL and a given implementation MAY
>>> > fail the
>>> > >>>>>>> buffer pool creation request with an appropriate errno if the
>>> > requested
>>> > >>>>>>> option is not supported by the underlying ODP implementation,
>>> with
>>> > the
>>> > >>>>>>> exception that UNSEGMENTED pools MUST be supported for
>>> non-packet
>>> > types and
>>> > >>>>>>> for packet types as long as the requested size is less than the
>>> > >>>>>>> implementation-defined native packet segment size.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> Use ODP_BUFFER_OPTS_NONE to specify default buffer pool options
>>> > with
>>> > >>>>>>> no additions.  The ODP_BUFFER_OPTS_UNSEGMENTED option specifies
>>> > that the
>>> > >>>>>>> buffer pool should be unsegmented.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> So unsegmented buffer pool support is available.  As far as RAW
>>> > >>>>>>> buffers go, again from the doc (p. 14):
>>> > >>>>>>>
>>> > >>>>>>> ODP_BUFFER_TYPE_RAW
>>> > >>>>>>>
>>> > >>>>>>> This is the “basic” buffer type which simply consists of a
>>> single
>>> > >>>>>>> fixed-sized block of contiguous memory.  Buffers of this type
>>> do
>>> > not support
>>> > >>>>>>> user meta data and the only built-in meta data supported for
>>> this
>>> > type of
>>> > >>>>>>> buffer are those that are statically computable, such as pool
>>> and
>>> > size. This
>>> > >>>>>>> type of buffer is entirely under application control and most
>>> of
>>> > the buffer
>>> > >>>>>>> APIs defined in this document are not available.  APIs for this
>>> > type of
>>> > >>>>>>> buffer are described in this document.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> So RAW buffers are always unsegmented.  The intent is that
>>> Packets
>>> > are
>>> > >>>>>>> by default segmented but can be unsegmented while the other
>>> buffer
>>> > types are
>>> > >>>>>>> by default unsegmented but (with the exception of RAW buffers)
>>> can
>>> > be made
>>> > >>>>>>> segmented.  This is because all buffers start out as a single
>>> > segment and
>>> > >>>>>>> hence are unsegmented until they are expanded to overflow that
>>> > single
>>> > >>>>>>> segment.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> Hope that clarifies things.  Again, this is all very
>>> > straightforward
>>> > >>>>>>> and only comes into play when actually needed.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> On Wed, Oct 8, 2014 at 4:03 AM, Jacob, Jerin
>>> > >>>>>>> <Jerin.Jacob@caviumnetworks.com> wrote:
>>> > >>>>>>>
>>> > >>>>>>> If there is no valid use case for supporting segmentation for
>>> raw
>>> > >>>>>>> buffers then lets drop it. At least it will reduce the effort
>>> of
>>> > >>>>>>>
>>> > >>>>>>> implementing and testing/verification buffer APIs on  different
>>> > >>>>>>> platforms.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> ________________________________
>>> > >>>>>>>
>>> > >>>>>>> From: lng-odp-bounces@lists.linaro.org
>>> > >>>>>>> <lng-odp-bounces@lists.linaro.org> on behalf of Ola Liljedahl
>>> > >>>>>>> <ola.liljedahl@linaro.org>
>>> > >>>>>>> Sent: Wednesday, October 8, 2014 1:37 PM
>>> > >>>>>>> To: Balasubramanian Manoharan
>>> > >>>>>>> Cc: lng-odp@lists.linaro.org
>>> > >>>>>>> Subject: Re: [lng-odp] [ODP/PATCH v1] ODP Buffer Segment
>>> Support
>>> > API
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> As I wrote in my comment to the architecture discussion
>>> yesterday,
>>> > I
>>> > >>>>>>> am against segmentation for buffers. Or at least there must be
>>> the
>>> > >>>>>>> possibility to create a buffer pool with guaranteed
>>> non-segmented
>>> > buffers.
>>> > >>>>>>> Segmented packets are OK but not all usages for buffers relate
>>> to
>>> > packets. A
>>> > >>>>>>> lot of internal usages (timeouts, SW messages, internal data
>>> > structures)
>>> > >>>>>>> will not be able to handle segmented buffers so you must be
>>> able
>>> > to force
>>> > >>>>>>> the creation of buffer pools with non-segmented buffers.
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> -- Ola
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> On 8 October 2014 09:50, Balasubramanian Manoharan
>>> > >>>>>>> <bala.manoharan@linaro.org> wrote:
>>> > >>>>>>>
>>> > >>>>>>> This patch contains ODP Buffer Management missing APIs
>>> > >>>>>>> The intent of this patch is to port the missing APIs from
>>> Buffer
>>> > >>>>>>> Management design document into Linux-generic repo.
>>> > >>>>>>> The dummy functions will be replaced during linux-generic
>>> > >>>>>>> implementation.
>>> > >>>>>>>
>>> > >>>>>>> Signed-off-by: Balasubramanian Manoharan
>>> > <bala.manoharan@linaro.org>
>>> > >>>>>>> ---
>>> > >>>>>>>  platform/linux-generic/include/api/odp_buffer.h    | 203
>>> > >>>>>>> ++++++++++++++++++++-
>>> > >>>>>>>  .../linux-generic/include/api/odp_buffer_pool.h    |  30 +++
>>> > >>>>>>>  platform/linux-generic/odp_buffer.c                | 120
>>> > ++++++++++++
>>> > >>>>>>>  platform/linux-generic/odp_buffer_pool.c           |   7 +
>>> > >>>>>>>  4 files changed, 351 insertions(+), 9 deletions(-)
>>> > >>>>>>>
>>> > >>>>>>> diff --git a/platform/linux-generic/include/api/odp_buffer.h
>>> > >>>>>>> b/platform/linux-generic/include/api/odp_buffer.h
>>> > >>>>>>> index d8577fd..aeb75ed 100644
>>> > >>>>>>> --- a/platform/linux-generic/include/api/odp_buffer.h
>>> > >>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer.h
>>> > >>>>>>> @@ -28,8 +28,34 @@ extern "C" {
>>> > >>>>>>>   */
>>> > >>>>>>>  typedef uint32_t odp_buffer_t;
>>> > >>>>>>>
>>> > >>>>>>> -#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>>> > >>>>>>> +/**
>>> > >>>>>>> +* ODP buffer segment
>>> > >>>>>>> +*/
>>> > >>>>>>> +typedef uint32_t odp_buffer_segment_t;
>>> > >>>>>>>
>>> > >>>>>>> +/**
>>> > >>>>>>> +* ODP buffer type
>>> > >>>>>>> +*/
>>> > >>>>>>> +typedef enum odp_buffer_type {
>>> > >>>>>>> +       ODP_BUFFER_TYPE_INVALID = -1,   /**< Buffer type
>>> invalid
>>> > */
>>> > >>>>>>> +       ODP_BUFFER_TYPE_ANY = 0,        /**< Buffer that can
>>> hold
>>> > any
>>> > >>>>>>> other
>>> > >>>>>>> +                                       buffer type */
>>> > >>>>>>> +       ODP_BUFFER_TYPE_RAW = 1,        /**< Raw buffer,
>>> > >>>>>>> +                                       no additional metadata
>>> */
>>> > >>>>>>> +       ODP_BUFFER_TYPE_PACKET = 2,     /**< Packet buffer */
>>> > >>>>>>> +       ODP_BUFFER_TYPE_TIMEOUT = 3     /**< Timeout buffer */
>>> > >>>>>>> +} odp_buffer_type_e;
>>> > >>>>>>> +
>>> > >>>>>>> +/**
>>> > >>>>>>> +* ODP buffer options
>>> > >>>>>>> +*/
>>> > >>>>>>> +typedef enum odp_buffer_opts {
>>> > >>>>>>> +       ODP_BUFFER_OPTS_NONE,
>>> > >>>>>>> +       ODP_BUFFER_OPTS_UNSEGMENTED
>>> > >>>>>>> +} odp_buffer_opts_e;
>>> > >>>>>>> +
>>> > >>>>>>> +#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
>>> > >>>>>>> +#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment
>>> */
>>> > >>>>>>>
>>> > >>>>>>>  /**
>>> > >>>>>>>   * Buffer start address
>>> > >>>>>>> @@ -58,14 +84,6 @@ size_t odp_buffer_size(odp_buffer_t buf);
>>> > >>>>>>>   */
>>> > >>>>>>>  int odp_buffer_type(odp_buffer_t buf);
>>> > >>>>>>>
>>> > >>>>>>> -#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid
>>> */
>>> > >>>>>>> -#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold
>>> > any
>>> > >>>>>>> other
>>> > >>>>>>> -                                         buffer type */
>>> > >>>>>>> -#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no
>>> > additional
>>> > >>>>>>> metadata */
>>> > >>>>>>> -#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
>>> > >>>>>>> -#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
>>> > >>>>>>> -
>>> > >>>>>>> -
>>> > >>>>>>>  /**
>>> > >>>>>>>   * Tests if buffer is valid
>>> > >>>>>>>   *
>>> > >>>>>>> @@ -76,6 +94,110 @@ int odp_buffer_type(odp_buffer_t buf);
>>> > >>>>>>>  int odp_buffer_is_valid(odp_buffer_t buf);
>>> > >>>>>>>
>>> > >>>>>>>  /**
>>> > >>>>>>> + * Tests if buffer is segmented
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  buf     Buffer handle
>>> > >>>>>>> + *
>>> > >>>>>>> + * @return             1 if buffer has more than one segment,
>>> > >>>>>>> + *                     otherwise 0
>>> > >>>>>>> + */
>>> > >>>>>>> +
>>> > >>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf);
>>> > >>>>>>> +
>>> > >>>>>>> +/**
>>> > >>>>>>> + * Get address and size of user meta data associated with a
>>> > buffer
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  buf             Buffer handle
>>> > >>>>>>> + * @param[out] udata_size      Number of bytes of user meta
>>> data
>>> > >>>>>>> available
>>> > >>>>>>> + *                             at the returned address
>>> > >>>>>>> + * @return                     Address of the user meta data
>>> for
>>> > this
>>> > >>>>>>> buffer
>>> > >>>>>>> + *                             or NULL if the buffer has no
>>> user
>>> > meta
>>> > >>>>>>> data.
>>> > >>>>>>> + */
>>> > >>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
>>> > >>>>>>> +
>>> > >>>>>>> +/**
>>> > >>>>>>> + * Get address of user meta data associated with a buffer
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  buf     Buffer handle
>>> > >>>>>>> + *
>>> > >>>>>>> + * @return             Address of the user meta data for this
>>> > buffer
>>> > >>>>>>> + *                     or NULL if the buffer has no user meta
>>> > data.
>>> > >>>>>>> + */
>>> > >>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf);
>>> > >>>>>>> +
>>> > >>>>>>> +/**
>>> > >>>>>>> + * Get count of number of segments in a buffer
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  buf     Buffer handle
>>> > >>>>>>> + *
>>> > >>>>>>> + * @return             Count of the number of segments in buf
>>> > >>>>>>> + */
>>> > >>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf);
>>> > >>>>>>> +
>>> > >>>>>>> +/**
>>> > >>>>>>> + * Get the segment identifier for a buffer segment by index
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  buf     Buffer handle
>>> > >>>>>>> + * @param[in]  ndx     Segment index of segment of interest
>>> > >>>>>>> + *
>>> > >>>>>>> + * @return             Segment identifier or
>>> ODP_SEGMENT_INVALID
>>> > if
>>> > >>>>>>> the
>>> > >>>>>>> + *                     supplied ndx is out of range.
>>> > >>>>>>> + */
>>> > >>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t
>>> > buf,
>>> > >>>>>>> size_t ndx);
>>> > >>>>>>> +
>>> > >>>>>>> +/**
>>> > >>>>>>> + * Get the next segment identifier for a buffer segment
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  buf     Buffer handle
>>> > >>>>>>> + * @param[in]  seg     Segment identifier of the previous
>>> segment
>>> > >>>>>>> + *
>>> > >>>>>>> + * @return             Segment identifier of the next segment,
>>> > >>>>>>> +                       or ODP_SEGMENT_INVALID.
>>> > >>>>>>> + */
>>> > >>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>>> > >>>>>>> +
>>> odp_buffer_segment_t
>>> > >>>>>>> seg);
>>> > >>>>>>> +/**
>>> > >>>>>>> + * Get start address for a specified buffer segment
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  buf     Buffer handle
>>> > >>>>>>> + * @param[in]  seg     Segment identifier of the buffer to be
>>> > >>>>>>> addressed
>>> > >>>>>>> + * @param[out] seglen  Returned number of bytes in this buffer
>>> > >>>>>>> + *                     segment available at returned address
>>> > >>>>>>> + *
>>> > >>>>>>> + * @return             Segment start address or NULL
>>> > >>>>>>> + */
>>> > >>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf,
>>> > odp_buffer_segment_t
>>> > >>>>>>> seg,
>>> > >>>>>>> +size_t *seglen);
>>> > >>>>>>> +
>>> > >>>>>>> +/**
>>> > >>>>>>> + *Unmap a buffer segment
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  seg     Buffer segment handle
>>> > >>>>>>> + */
>>> > >>>>>>> +void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
>>> > >>>>>>> +
>>> > >>>>>>> +/**
>>> > >>>>>>> +* Get start address for a specified buffer offset
>>> > >>>>>>> +*
>>> > >>>>>>> +* @param[in]   buf     Buffer handle
>>> > >>>>>>> +* @param[in]   offset  Byte offset within the buffer to be
>>> > addressed
>>> > >>>>>>> +* @param[out]  seglen  Returned number of bytes in this buffer
>>> > >>>>>>> +*                      segment available at returned address
>>> > >>>>>>> +*
>>> > >>>>>>> +* @return              Offset start address or NULL
>>> > >>>>>>> +*/
>>> > >>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>>> > >>>>>>> +size_t *seglen);
>>> > >>>>>>> +
>>> > >>>>>>> +/**
>>> > >>>>>>> + * Unmap a buffer segment by offset
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  buf     Buffer handle
>>> > >>>>>>> + * @param[in]  offset  Buffer offset
>>> > >>>>>>> + */
>>> > >>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
>>> > >>>>>>> +
>>> > >>>>>>> +/**
>>> > >>>>>>>   * Print buffer metadata to STDOUT
>>> > >>>>>>>   *
>>> > >>>>>>>   * @param buf      Buffer handle
>>> > >>>>>>> @@ -83,6 +205,69 @@ int odp_buffer_is_valid(odp_buffer_t buf);
>>> > >>>>>>>   */
>>> > >>>>>>>  void odp_buffer_print(odp_buffer_t buf);
>>> > >>>>>>>
>>> > >>>>>>> +/**
>>> > >>>>>>> + * Split a buffer into two buffers at a specified split point
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  buf     Handle of buffer to split
>>> > >>>>>>> + * @param[in]  offset  Byte offset within buf to split buffer
>>> > >>>>>>> + *
>>> > >>>>>>> + * @return             Buffer handle of the created split
>>> buffer
>>> > >>>>>>> + */
>>> > >>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t
>>> offset);
>>> > >>>>>>> +
>>> > >>>>>>> +/**
>>> > >>>>>>> + * Join two buffers into a single buffer
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  buf1    Buffer handle of first buffer to join
>>> > >>>>>>> + * @param[in]  buf2    Buffer handle of second buffer to join
>>> > >>>>>>> + *
>>> > >>>>>>> + * @return             Buffer handle of the joined buffer
>>> > >>>>>>> + */
>>> > >>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t
>>> > buf2);
>>> > >>>>>>> +
>>> > >>>>>>> +/**
>>> > >>>>>>> + * Trim a buffer at a specified trim point
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  buf     Buffer handle of buffer to trim
>>> > >>>>>>> + * @param[in]  offset  byte offset within buf to trim
>>> > >>>>>>> + *
>>> > >>>>>>> + * @return             Handle of the trimmed buffer or
>>> > >>>>>>> + *                     ODP_BUFFER_INVALID if the operation was
>>> > not
>>> > >>>>>>> performed
>>> > >>>>>>> + */
>>> > >>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
>>> > >>>>>>> +/**
>>> > >>>>>>> + * Extend a buffer for a specified number of bytes
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  buf     Buffer handle of buffer to expand
>>> > >>>>>>> + * @param[in]  ext     size, in bytes, of the extent to add to
>>> > the
>>> > >>>>>>> + *                     existing buffer.
>>> > >>>>>>> + *
>>> > >>>>>>> + * @return             Handle of the extended buffer or
>>> > >>>>>>> ODP_BUFFER_INVALID
>>> > >>>>>>> + *                     if the operation was not performed
>>> > >>>>>>> + */
>>> > >>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
>>> > >>>>>>> +
>>> > >>>>>>> +/**
>>> > >>>>>>> + * Clone a buffer, returning an exact copy of it
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  buf     Buffer handle of buffer to duplicate
>>> > >>>>>>> + *
>>> > >>>>>>> + * @return             Handle of the duplicated buffer or
>>> > >>>>>>> ODP_BUFFER_INVALID
>>> > >>>>>>> + *                     if the operation was not performed
>>> > >>>>>>> + */
>>> > >>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
>>> > >>>>>>> +
>>> > >>>>>>> +/**
>>> > >>>>>>> + * Copy a buffer, returning an exact copy of it
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  buf     Buffer handle of buffer to copy
>>> > >>>>>>> + *
>>> > >>>>>>> + * @return             Handle of the copied buffer or
>>> > >>>>>>> ODP_BUFFER_INVALID
>>> > >>>>>>> + *                     if the operation was not performed
>>> > >>>>>>> + */
>>> > >>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
>>> > >>>>>>> +
>>> > >>>>>>> +
>>> > >>>>>>>
>>> > >>>>>>>  #ifdef __cplusplus
>>> > >>>>>>>  }
>>> > >>>>>>> diff --git
>>> a/platform/linux-generic/include/api/odp_buffer_pool.h
>>> > >>>>>>> b/platform/linux-generic/include/api/odp_buffer_pool.h
>>> > >>>>>>> index fe88898..f85d96c 100644
>>> > >>>>>>> --- a/platform/linux-generic/include/api/odp_buffer_pool.h
>>> > >>>>>>> +++ b/platform/linux-generic/include/api/odp_buffer_pool.h
>>> > >>>>>>> @@ -52,6 +52,27 @@ odp_buffer_pool_t
>>> odp_buffer_pool_create(const
>>> > char
>>> > >>>>>>> *name,
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>  /**
>>> > >>>>>>> + * Get the next buffer pool from its predecessor
>>> > >>>>>>> + *
>>> > >>>>>>> + * @param[in]  pool            Buffer pool handle
>>> > >>>>>>> + * @param[out] name            Name of the pool
>>> > >>>>>>> + *                             (max ODP_BUFFER_POOL_NAME_LEN
>>> - 1
>>> > >>>>>>> chars)
>>> > >>>>>>> + * @param[out] udata_size      Size of user meta data used by
>>> > this
>>> > >>>>>>> pool.
>>> > >>>>>>> + * @param[out] buf_num         Number of buffers contained in
>>> > this
>>> > >>>>>>> pool
>>> > >>>>>>> + * @param[out] buf_size        Default size of application
>>> data
>>> > in
>>> > >>>>>>> each buffer
>>> > >>>>>>> + * @param[out] buf_type        Buffer type of the pool
>>> > >>>>>>> + * @param[out] buf_opts        Buffer options for this pool
>>> > >>>>>>> + * @param[out] predef          Predefined (1) or Created (0).
>>> > >>>>>>> + *
>>> > >>>>>>> + * @return                     Buffer pool handle
>>> > >>>>>>> + */
>>> > >>>>>>> +odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
>>> > >>>>>>> +                                      char *name, size_t
>>> > *udata_size,
>>> > >>>>>>> +                                      size_t *buf_num, size_t
>>> > >>>>>>> *buf_size,
>>> > >>>>>>> +                                      enum odp_buffer_type
>>> > *buf_type,
>>> > >>>>>>> +                                      enum odp_buffer_opts
>>> > *buf_opts,
>>> > >>>>>>> +                                      uint32_t *predef);
>>> > >>>>>>> +/**
>>> > >>>>>>>   * Find a buffer pool by name
>>> > >>>>>>>   *
>>> > >>>>>>>   * @param name      Name of the pool
>>> > >>>>>>> @@ -80,6 +101,15 @@ void
>>> odp_buffer_pool_print(odp_buffer_pool_t
>>> > >>>>>>> pool);
>>> > >>>>>>>   */
>>> > >>>>>>>  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
>>> > >>>>>>>
>>> > >>>>>>> +/**
>>> > >>>>>>> +* Allocate a buffer from a buffer pool
>>> > >>>>>>> +*
>>> > >>>>>>> +* @param[in]   pool    Pool handle
>>> > >>>>>>> +* @param[in]   size    Size of object to store in buffer
>>> > >>>>>>> +*
>>> > >>>>>>> +* @return              Buffer handle or ODP_BUFFER_INVALID
>>> > >>>>>>> +*/
>>> > >>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool,
>>> size_t
>>> > >>>>>>> size);
>>> > >>>>>>>
>>> > >>>>>>>  /**
>>> > >>>>>>>   * Buffer free
>>> > >>>>>>> diff --git a/platform/linux-generic/odp_buffer.c
>>> > >>>>>>> b/platform/linux-generic/odp_buffer.c
>>> > >>>>>>> index e54e0e7..7f4b4f0 100644
>>> > >>>>>>> --- a/platform/linux-generic/odp_buffer.c
>>> > >>>>>>> +++ b/platform/linux-generic/odp_buffer.c
>>> > >>>>>>> @@ -45,6 +45,21 @@ int odp_buffer_is_valid(odp_buffer_t buf)
>>> > >>>>>>>         return (handle.index != ODP_BUFFER_INVALID_INDEX);
>>> > >>>>>>>  }
>>> > >>>>>>>
>>> > >>>>>>> +int odp_buffer_is_segmented(odp_buffer_t buf)
>>> > >>>>>>> +{
>>> > >>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>>> > >>>>>>> +
>>> > >>>>>>> +       if (buf_hdr->scatter.num_bufs == 0)
>>> > >>>>>>> +               return 0;
>>> > >>>>>>> +       else
>>> > >>>>>>> +               return 1;
>>> > >>>>>>> +}
>>> > >>>>>>> +
>>> > >>>>>>> +size_t odp_buffer_segment_count(odp_buffer_t buf)
>>> > >>>>>>> +{
>>> > >>>>>>> +       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
>>> > >>>>>>> +       return (size_t)buf_hdr->scatter.num_bufs + 1;
>>> > >>>>>>> +}
>>> > >>>>>>>
>>> > >>>>>>>  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
>>> > >>>>>>>  {
>>> > >>>>>>> @@ -101,8 +116,113 @@ void odp_buffer_print(odp_buffer_t buf)
>>> > >>>>>>>         printf("\n%s\n", str);
>>> > >>>>>>>  }
>>> > >>>>>>>
>>> > >>>>>>> +void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
>>> > >>>>>>> +{
>>> > >>>>>>> +       (void)buf;
>>> > >>>>>>> +       (void)udata_size;
>>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>>> > >>>>>>> +       return 0;
>>> > >>>>>>> +}
>>> > >>>>>>> +
>>> > >>>>>>> +void *odp_buffer_udata_addr(odp_buffer_t buf)
>>> > >>>>>>> +{
>>> > >>>>>>> +       (void)buf;
>>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>>> > >>>>>>> +       return 0;
>>> > >>>>>>> +}
>>> > >>>>>>> +
>>> > >>>>>>> +odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t
>>> > buf,
>>> > >>>>>>> +                                                size_t ndx)
>>> > >>>>>>> +{
>>> > >>>>>>> +       (void)buf;
>>> > >>>>>>> +       (void)ndx;
>>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>>> > >>>>>>> +       return 0;
>>> > >>>>>>> +}
>>> > >>>>>>> +
>>> > >>>>>>> +odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
>>> > >>>>>>> +
>>> odp_buffer_segment_t
>>> > seg)
>>> > >>>>>>> +{
>>> > >>>>>>> +       (void)buf;
>>> > >>>>>>> +       (void)seg;
>>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>>> > >>>>>>> +       return 0;
>>> > >>>>>>> +}
>>> > >>>>>>> +
>>> > >>>>>>> +void *odp_buffer_segment_map(odp_buffer_t buf,
>>> > odp_buffer_segment_t
>>> > >>>>>>> seg,
>>> > >>>>>>> +                            size_t *seglen)
>>> > >>>>>>> +{
>>> > >>>>>>> +       (void)buf;
>>> > >>>>>>> +       (void)seg;
>>> > >>>>>>> +       (void)seglen;
>>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>>> > >>>>>>> +       return 0;
>>> > >>>>>>> +}
>>> > >>>>>>> +void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
>>> > >>>>>>> +size_t *seglen)
>>> > >>>>>>> +{
>>> > >>>>>>> +       (void)buf;
>>> > >>>>>>> +       (void)offset;
>>> > >>>>>>> +       (void)seglen;
>>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>>> > >>>>>>> +       return 0;
>>> > >>>>>>> +}
>>> > >>>>>>> +void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
>>> > >>>>>>> +{
>>> > >>>>>>> +       (void)buf;
>>> > >>>>>>> +       (void)offset;
>>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>>> > >>>>>>> +       return;
>>> > >>>>>>> +}
>>> > >>>>>>> +
>>> > >>>>>>>  void odp_buffer_copy_scatter(odp_buffer_t buf_dst,
>>> odp_buffer_t
>>> > >>>>>>> buf_src)
>>> > >>>>>>>  {
>>> > >>>>>>>         (void)buf_dst;
>>> > >>>>>>>         (void)buf_src;
>>> > >>>>>>>  }
>>> > >>>>>>> +
>>> > >>>>>>> +odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
>>> > >>>>>>> +{
>>> > >>>>>>> +       (void)buf;
>>> > >>>>>>> +       (void)offset;
>>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>>> > >>>>>>> +       return 0;
>>> > >>>>>>> +}
>>> > >>>>>>> +
>>> > >>>>>>> +odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t
>>> > buf2)
>>> > >>>>>>> +{
>>> > >>>>>>> +       (void)buf1;
>>> > >>>>>>> +       (void)buf2;
>>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>>> > >>>>>>> +       return 0;
>>> > >>>>>>> +}
>>> > >>>>>>> +
>>> > >>>>>>> +odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
>>> > >>>>>>> +{
>>> > >>>>>>> +       (void)buf;
>>> > >>>>>>> +       (void)offset;
>>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>>> > >>>>>>> +       return 0;
>>> > >>>>>>> +}
>>> > >>>>>>> +odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
>>> > >>>>>>> +{
>>> > >>>>>>> +       (void)buf;
>>> > >>>>>>> +       (void)ext;
>>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>>> > >>>>>>> +       return 0;
>>> > >>>>>>> +}
>>> > >>>>>>> +
>>> > >>>>>>> +odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
>>> > >>>>>>> +{
>>> > >>>>>>> +       (void)buf;
>>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>>> > >>>>>>> +       return 0;
>>> > >>>>>>> +}
>>> > >>>>>>> +
>>> > >>>>>>> +odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
>>> > >>>>>>> +{
>>> > >>>>>>> +       (void)buf;
>>> > >>>>>>> +       ODP_UNIMPLEMENTED();
>>> > >>>>>>> +       return 0;
>>> > >>>>>>> +}
>>> > >>>>>>> +
>>> > >>>>>>> diff --git a/platform/linux-generic/odp_buffer_pool.c
>>> > >>>>>>> b/platform/linux-generic/odp_buffer_pool.c
>>> > >>>>>>> index a48d7d6..bff4db5 100644
>>> > >>>>>>> --- a/platform/linux-generic/odp_buffer_pool.c
>>> > >>>>>>> +++ b/platform/linux-generic/odp_buffer_pool.c
>>> > >>>>>>> @@ -471,6 +471,13 @@ odp_buffer_t
>>> > odp_buffer_alloc(odp_buffer_pool_t
>>> > >>>>>>> pool_hdl)
>>> > >>>>>>>         return handle.u32;
>>> > >>>>>>>  }
>>> > >>>>>>>
>>> > >>>>>>> +odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool,
>>> size_t
>>> > >>>>>>> size)
>>> > >>>>>>> +{
>>> > >>>>>>> +       (void)pool;
>>> > >>>>>>> +       (void) size;
>>> > >>>>>>> +       ODP_ERR("%s function is yet to be implemented",
>>> __func__);
>>> > >>>>>>> +       return 0;
>>> > >>>>>>> +}
>>> > >>>>>>>
>>> > >>>>>>>  void odp_buffer_free(odp_buffer_t buf)
>>> > >>>>>>>  {
>>> > >>>>>>> --
>>> > >>>>>>> 2.0.1.472.g6f92e5f
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> _______________________________________________
>>> > >>>>>>> lng-odp mailing list
>>> > >>>>>>> lng-odp@lists.linaro.org
>>> > >>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>> _______________________________________________
>>> > >>>>>>> lng-odp mailing list
>>> > >>>>>>> lng-odp@lists.linaro.org
>>> > >>>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>>
>>> > >>>>>>
>>> > >>>>>>
>>> > >>>>>>
>>> > >>>>>> _______________________________________________
>>> > >>>>>> lng-odp mailing list
>>> > >>>>>> lng-odp@lists.linaro.org
>>> > >>>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>> > >>>>>>
>>> > >>>>>
>>> > >>>>>
>>> > >>>>> _______________________________________________
>>> > >>>>> lng-odp mailing list
>>> > >>>>> lng-odp@lists.linaro.org
>>> > >>>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>> > >>>>>
>>> > >>>>
>>> > >>>
>>> > >>
>>> > >>
>>> > >> _______________________________________________
>>> > >> lng-odp mailing list
>>> > >> lng-odp@lists.linaro.org
>>> > >> http://lists.linaro.org/mailman/listinfo/lng-odp
>>> > >>
>>>
>>
>>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
>
diff mbox

Patch

diff --git a/platform/linux-generic/include/api/odp_buffer.h b/platform/linux-generic/include/api/odp_buffer.h
index d8577fd..aeb75ed 100644
--- a/platform/linux-generic/include/api/odp_buffer.h
+++ b/platform/linux-generic/include/api/odp_buffer.h
@@ -28,8 +28,34 @@  extern "C" {
  */
 typedef uint32_t odp_buffer_t;
 
-#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
+/**
+* ODP buffer segment
+*/
+typedef uint32_t odp_buffer_segment_t;
 
+/**
+* ODP buffer type
+*/
+typedef enum odp_buffer_type {
+	ODP_BUFFER_TYPE_INVALID = -1,	/**< Buffer type invalid */
+	ODP_BUFFER_TYPE_ANY = 0,	/**< Buffer that can hold any other
+					buffer type */
+	ODP_BUFFER_TYPE_RAW = 1,	/**< Raw buffer,
+					no additional metadata */
+	ODP_BUFFER_TYPE_PACKET = 2,	/**< Packet buffer */
+	ODP_BUFFER_TYPE_TIMEOUT = 3	/**< Timeout buffer */
+} odp_buffer_type_e;
+
+/**
+* ODP buffer options
+*/
+typedef enum odp_buffer_opts {
+	ODP_BUFFER_OPTS_NONE,
+	ODP_BUFFER_OPTS_UNSEGMENTED
+} odp_buffer_opts_e;
+
+#define ODP_BUFFER_INVALID (0xffffffff) /**< Invalid buffer */
+#define ODP_SEGMENT_INVALID (0xffffffff) /**< Invalid segment */
 
 /**
  * Buffer start address
@@ -58,14 +84,6 @@  size_t odp_buffer_size(odp_buffer_t buf);
  */
 int odp_buffer_type(odp_buffer_t buf);
 
-#define ODP_BUFFER_TYPE_INVALID (-1) /**< Buffer type invalid */
-#define ODP_BUFFER_TYPE_ANY       0  /**< Buffer that can hold any other
-					  buffer type */
-#define ODP_BUFFER_TYPE_RAW       1  /**< Raw buffer, no additional metadata */
-#define ODP_BUFFER_TYPE_PACKET    2  /**< Packet buffer */
-#define ODP_BUFFER_TYPE_TIMEOUT   3  /**< Timeout buffer */
-
-
 /**
  * Tests if buffer is valid
  *
@@ -76,6 +94,110 @@  int odp_buffer_type(odp_buffer_t buf);
 int odp_buffer_is_valid(odp_buffer_t buf);
 
 /**
+ * Tests if buffer is segmented
+ *
+ * @param[in]	buf	Buffer handle
+ *
+ * @return		1 if buffer has more than one segment,
+ *			otherwise 0
+ */
+
+int odp_buffer_is_segmented(odp_buffer_t buf);
+
+/**
+ * Get address and size of user meta data associated with a buffer
+ *
+ * @param[in]	buf		Buffer handle
+ * @param[out]	udata_size	Number of bytes of user meta data available
+ *				at the returned address
+ * @return			Address of the user meta data for this buffer
+ *				or NULL if the buffer has no user meta data.
+ */
+void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size);
+
+/**
+ * Get address of user meta data associated with a buffer
+ *
+ * @param[in]	buf	Buffer handle
+ *
+ * @return		Address of the user meta data for this buffer
+ *			or NULL if the buffer has no user meta data.
+ */
+void *odp_buffer_udata_addr(odp_buffer_t buf);
+
+/**
+ * Get count of number of segments in a buffer
+ *
+ * @param[in]	buf	Buffer handle
+ *
+ * @return		Count of the number of segments in buf
+ */
+size_t odp_buffer_segment_count(odp_buffer_t buf);
+
+/**
+ * Get the segment identifier for a buffer segment by index
+ *
+ * @param[in]	buf	Buffer handle
+ * @param[in]	ndx	Segment index of segment of interest
+ *
+ * @return		Segment identifier or ODP_SEGMENT_INVALID if the
+ *			supplied ndx is out of range.
+ */
+odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf, size_t ndx);
+
+/**
+ * Get the next segment identifier for a buffer segment
+ *
+ * @param[in]	buf	Buffer handle
+ * @param[in]	seg	Segment identifier of the previous segment
+ *
+ * @return		Segment identifier of the next segment,
+			or ODP_SEGMENT_INVALID.
+ */
+odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
+					     odp_buffer_segment_t seg);
+/**
+ * Get start address for a specified buffer segment
+ *
+ * @param[in]	buf	Buffer handle
+ * @param[in]	seg	Segment identifier of the buffer to be addressed
+ * @param[out]	seglen	Returned number of bytes in this buffer
+ *			segment available at returned address
+ *
+ * @return		Segment start address or NULL
+ */
+void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
+size_t *seglen);
+
+/**
+ *Unmap a buffer segment
+ *
+ * @param[in]	seg	Buffer segment handle
+ */
+void odp_buffer_segment_unmap(odp_buffer_segment_t seg);
+
+/**
+* Get start address for a specified buffer offset
+*
+* @param[in]	buf	Buffer handle
+* @param[in]	offset	Byte offset within the buffer to be addressed
+* @param[out]	seglen	Returned number of bytes in this buffer
+*			segment available at returned address
+*
+* @return		Offset start address or NULL
+*/
+void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
+size_t *seglen);
+
+/**
+ * Unmap a buffer segment by offset
+ *
+ * @param[in]	buf	Buffer handle
+ * @param[in]	offset	Buffer offset
+ */
+void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset);
+
+/**
  * Print buffer metadata to STDOUT
  *
  * @param buf      Buffer handle
@@ -83,6 +205,69 @@  int odp_buffer_is_valid(odp_buffer_t buf);
  */
 void odp_buffer_print(odp_buffer_t buf);
 
+/**
+ * Split a buffer into two buffers at a specified split point
+ *
+ * @param[in]	buf	Handle of buffer to split
+ * @param[in]	offset	Byte offset within buf to split buffer
+ *
+ * @return		Buffer handle of the created split buffer
+ */
+odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset);
+
+/**
+ * Join two buffers into a single buffer
+ *
+ * @param[in]	buf1	Buffer handle of first buffer to join
+ * @param[in]	buf2	Buffer handle of second buffer to join
+ *
+ * @return		Buffer handle of the joined buffer
+ */
+odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2);
+
+/**
+ * Trim a buffer at a specified trim point
+ *
+ * @param[in]	buf	Buffer handle of buffer to trim
+ * @param[in]	offset	byte offset within buf to trim
+ *
+ * @return		Handle of the trimmed buffer or
+ *			ODP_BUFFER_INVALID if the operation was not performed
+ */
+odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset);
+/**
+ * Extend a buffer for a specified number of bytes
+ *
+ * @param[in]	buf	Buffer handle of buffer to expand
+ * @param[in]	ext	size, in bytes, of the extent to add to the
+ *			existing buffer.
+ *
+ * @return		Handle of the extended buffer or ODP_BUFFER_INVALID
+ *			if the operation was not performed
+ */
+odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext);
+
+/**
+ * Clone a buffer, returning an exact copy of it
+ *
+ * @param[in]	buf	Buffer handle of buffer to duplicate
+ *
+ * @return		Handle of the duplicated buffer or ODP_BUFFER_INVALID
+ *			if the operation was not performed
+ */
+odp_buffer_t odp_buffer_clone(odp_buffer_t buf);
+
+/**
+ * Copy a buffer, returning an exact copy of it
+ *
+ * @param[in]	buf	Buffer handle of buffer to copy
+ *
+ * @return		Handle of the copied buffer or ODP_BUFFER_INVALID
+ *			if the operation was not performed
+ */
+odp_buffer_t odp_buffer_copy(odp_buffer_t buf);
+
+
 
 #ifdef __cplusplus
 }
diff --git a/platform/linux-generic/include/api/odp_buffer_pool.h b/platform/linux-generic/include/api/odp_buffer_pool.h
index fe88898..f85d96c 100644
--- a/platform/linux-generic/include/api/odp_buffer_pool.h
+++ b/platform/linux-generic/include/api/odp_buffer_pool.h
@@ -52,6 +52,27 @@  odp_buffer_pool_t odp_buffer_pool_create(const char *name,
 
 
 /**
+ * Get the next buffer pool from its predecessor
+ *
+ * @param[in]	pool		Buffer pool handle
+ * @param[out]	name		Name of the pool
+ *				(max ODP_BUFFER_POOL_NAME_LEN - 1 chars)
+ * @param[out]	udata_size	Size of user meta data used by this pool.
+ * @param[out]	buf_num		Number of buffers contained in this pool
+ * @param[out]	buf_size	Default size of application data in each buffer
+ * @param[out]	buf_type	Buffer type of the pool
+ * @param[out]	buf_opts	Buffer options for this pool
+ * @param[out]	predef		Predefined (1) or Created (0).
+ *
+ * @return			Buffer pool handle
+ */
+odp_buffer_pool_t odp_buffer_pool_next(odp_buffer_pool_t pool,
+				       char *name, size_t *udata_size,
+				       size_t *buf_num, size_t *buf_size,
+				       enum odp_buffer_type *buf_type,
+				       enum odp_buffer_opts *buf_opts,
+				       uint32_t *predef);
+/**
  * Find a buffer pool by name
  *
  * @param name      Name of the pool
@@ -80,6 +101,15 @@  void odp_buffer_pool_print(odp_buffer_pool_t pool);
  */
 odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool);
 
+/**
+* Allocate a buffer from a buffer pool
+*
+* @param[in]	pool	Pool handle
+* @param[in]	size	Size of object to store in buffer
+*
+* @return		Buffer handle or ODP_BUFFER_INVALID
+*/
+odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size);
 
 /**
  * Buffer free
diff --git a/platform/linux-generic/odp_buffer.c b/platform/linux-generic/odp_buffer.c
index e54e0e7..7f4b4f0 100644
--- a/platform/linux-generic/odp_buffer.c
+++ b/platform/linux-generic/odp_buffer.c
@@ -45,6 +45,21 @@  int odp_buffer_is_valid(odp_buffer_t buf)
 	return (handle.index != ODP_BUFFER_INVALID_INDEX);
 }
 
+int odp_buffer_is_segmented(odp_buffer_t buf)
+{
+	odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
+
+	if (buf_hdr->scatter.num_bufs == 0)
+		return 0;
+	else
+		return 1;
+}
+
+size_t odp_buffer_segment_count(odp_buffer_t buf)
+{
+	odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
+	return (size_t)buf_hdr->scatter.num_bufs + 1;
+}
 
 int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
 {
@@ -101,8 +116,113 @@  void odp_buffer_print(odp_buffer_t buf)
 	printf("\n%s\n", str);
 }
 
+void *odp_buffer_udata(odp_buffer_t buf, size_t *udata_size)
+{
+	(void)buf;
+	(void)udata_size;
+	ODP_UNIMPLEMENTED();
+	return 0;
+}
+
+void *odp_buffer_udata_addr(odp_buffer_t buf)
+{
+	(void)buf;
+	ODP_UNIMPLEMENTED();
+	return 0;
+}
+
+odp_buffer_segment_t odp_buffer_segment_by_index(odp_buffer_t buf,
+						 size_t ndx)
+{
+	(void)buf;
+	(void)ndx;
+	ODP_UNIMPLEMENTED();
+	return 0;
+}
+
+odp_buffer_segment_t odp_buffer_segment_next(odp_buffer_t buf,
+					     odp_buffer_segment_t seg)
+{
+	(void)buf;
+	(void)seg;
+	ODP_UNIMPLEMENTED();
+	return 0;
+}
+
+void *odp_buffer_segment_map(odp_buffer_t buf, odp_buffer_segment_t seg,
+			     size_t *seglen)
+{
+	(void)buf;
+	(void)seg;
+	(void)seglen;
+	ODP_UNIMPLEMENTED();
+	return 0;
+}
+void *odp_buffer_offset_map(odp_buffer_t buf, size_t offset,
+size_t *seglen)
+{
+	(void)buf;
+	(void)offset;
+	(void)seglen;
+	ODP_UNIMPLEMENTED();
+	return 0;
+}
+void odp_buffer_offset_unmap(odp_buffer_t buf, size_t offset)
+{
+	(void)buf;
+	(void)offset;
+	ODP_UNIMPLEMENTED();
+	return;
+}
+
 void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t buf_src)
 {
 	(void)buf_dst;
 	(void)buf_src;
 }
+
+odp_buffer_t odp_buffer_split(odp_buffer_t buf, size_t offset)
+{
+	(void)buf;
+	(void)offset;
+	ODP_UNIMPLEMENTED();
+	return 0;
+}
+
+odp_buffer_t odp_buffer_join(odp_buffer_t buf1, odp_buffer_t buf2)
+{
+	(void)buf1;
+	(void)buf2;
+	ODP_UNIMPLEMENTED();
+	return 0;
+}
+
+odp_buffer_t odp_buffer_trim(odp_buffer_t buf, size_t offset)
+{
+	(void)buf;
+	(void)offset;
+	ODP_UNIMPLEMENTED();
+	return 0;
+}
+odp_buffer_t odp_buffer_extend(odp_buffer_t buf, size_t ext)
+{
+	(void)buf;
+	(void)ext;
+	ODP_UNIMPLEMENTED();
+	return 0;
+}
+
+odp_buffer_t odp_buffer_clone(odp_buffer_t buf)
+{
+	(void)buf;
+	ODP_UNIMPLEMENTED();
+	return 0;
+}
+
+odp_buffer_t odp_buffer_copy(odp_buffer_t buf)
+{
+	(void)buf;
+	ODP_UNIMPLEMENTED();
+	return 0;
+}
+
diff --git a/platform/linux-generic/odp_buffer_pool.c b/platform/linux-generic/odp_buffer_pool.c
index a48d7d6..bff4db5 100644
--- a/platform/linux-generic/odp_buffer_pool.c
+++ b/platform/linux-generic/odp_buffer_pool.c
@@ -471,6 +471,13 @@  odp_buffer_t odp_buffer_alloc(odp_buffer_pool_t pool_hdl)
 	return handle.u32;
 }
 
+odp_buffer_t odp_buffer_alloc_size(odp_buffer_pool_t pool, size_t size)
+{
+	(void)pool;
+	(void) size;
+	ODP_ERR("%s function is yet to be implemented", __func__);
+	return 0;
+}
 
 void odp_buffer_free(odp_buffer_t buf)
 {