[API-NEXT,PATCHv4,1/5] api: packet: add support for packet references

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

Commit Message

Bill Fischofer Jan. 1, 2017, 11:40 p.m.
Introduce three new APIs that support efficient sharing of portions of
packets.

odp_packet_ref_static() creates an alias for a base packet

odp_packet_ref() creates a reference to a base packet

odp_packet_ref_pkt() creates a reference to a base packet from a supplied
header packet

In addition, three other APIs simplify working with references

odp_packet_is_ref() says whether a packet is a reference

odp_packet_has_ref() says whether a packet has had a reference made to it

odp_packet_unshared_len() gives the length of the prefix bytes that are
unique to this reference. These are the only bytes of the packet that may
be modified safely.

Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>

---
Changes in v4:
- Bug fixes
- Expand validation testing to cover extensions on packets with references

Changes in v3:
- Rebased to latest API-NEXT
- Bug fixes
- Eliminate concept of base packets, both references and referenced packets may
  have head extensions as needed

 include/odp/api/spec/packet.h | 190 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 189 insertions(+), 1 deletion(-)

-- 
2.7.4

Comments

Bill Fischofer Jan. 3, 2017, 2:32 p.m. | #1
On Tue, Jan 3, 2017 at 8:14 AM, Bala Manoharan
<bala.manoharan@linaro.org> wrote:
> Regards,

> Bala

>

>

> On 2 January 2017 at 05:10, Bill Fischofer <bill.fischofer@linaro.org> wrote:

>> Introduce three new APIs that support efficient sharing of portions of

>> packets.

>>

>> odp_packet_ref_static() creates an alias for a base packet

>>

>> odp_packet_ref() creates a reference to a base packet

>>

>> odp_packet_ref_pkt() creates a reference to a base packet from a supplied

>> header packet

>>

>> In addition, three other APIs simplify working with references

>>

>> odp_packet_is_ref() says whether a packet is a reference

>>

>> odp_packet_has_ref() says whether a packet has had a reference made to it

>>

>> odp_packet_unshared_len() gives the length of the prefix bytes that are

>> unique to this reference. These are the only bytes of the packet that may

>> be modified safely.

>>

>> Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>

>> ---

>> Changes in v4:

>> - Bug fixes

>> - Expand validation testing to cover extensions on packets with references

>>

>> Changes in v3:

>> - Rebased to latest API-NEXT

>> - Bug fixes

>> - Eliminate concept of base packets, both references and referenced packets may

>>   have head extensions as needed

>>

>>  include/odp/api/spec/packet.h | 190 +++++++++++++++++++++++++++++++++++++++++-

>>  1 file changed, 189 insertions(+), 1 deletion(-)

>>

>> diff --git a/include/odp/api/spec/packet.h b/include/odp/api/spec/packet.h

>> index 4a86eba..0791496 100644

>> --- a/include/odp/api/spec/packet.h

>> +++ b/include/odp/api/spec/packet.h

>> @@ -256,6 +256,20 @@ uint32_t odp_packet_seg_len(odp_packet_t pkt);

>>  uint32_t odp_packet_len(odp_packet_t pkt);

>>

>>  /**

>> + * Packet unshared data len

>> + *

>> + * Returns the sum of data lengths over all unshared packet segments. These

>> + * are the only bytes that should be modified by the caller. The rest of the

>> + * packet should be treated as read only. odp_packet_unshared_len() will be

>> + * equal to odp_packet_len() if odp_packet_has_ref() is 0.

>> + *

>> + * @param pkt Packet handle

>> + *

>> + * @return Packet unshared data length

>> + */

>> +uint32_t odp_packet_unshared_len(odp_packet_t pkt);

>> +

>> +/**

>>   * Packet headroom length

>>   *

>>   * Returns the current packet level headroom length.

>> @@ -795,7 +809,7 @@ uint32_t odp_packet_seg_data_len(odp_packet_t pkt, odp_packet_seg_t seg);

>>   * data pointers. Otherwise, all old pointers remain valid.

>>   *

>>   * The resulting packet is always allocated from the same pool as

>> - * the destination packet. The source packet may have been allocate from

>> + * the destination packet. The source packet may have been allocated from

>>   * any pool.

>>   *

>>   * On failure, both handles remain valid and packets are not modified.

>> @@ -848,6 +862,180 @@ int odp_packet_split(odp_packet_t *pkt, uint32_t len, odp_packet_t *tail);

>>

>>  /*

>>   *

>> + * References

>> + * ********************************************************

>> + *

>> + */

>> +

>> +/**

>> + * Create a static reference to a packet

>> + *

>> + * A static reference is used to obtain an additional handle for referring to

>> + * a packet so that the storage behind it is not freed until all references to

>> + * the packet are freed. This can be used, for example, to support efficient

>> + * retransmission processing.

>> + *

>> + * The intent of a static reference is that both the packet and the returned

>> + * reference to it will be treated as read only after this call. Results are

>> + * undefined if this restriction is not observed.

>> + *

>> + * Static references have restrictions but may have performance advantages on

>> + * some platforms if the caller does not intend to modify the reference

>> + * packet. If modification is needed (e.g., to prefix a unique header onto the

>> + * packet) then odp_packet_ref() or odp_packet_ref_pkt() should be used.

>> + *

>> + * @param pkt    Handle of the packet for which a static reference is

>> + *               to be created.

>> + *

>> + * @return                    Handle of the static reference packet

>> + * @retval ODP_PACKET_INVALID Operation failed. pkt remains unchanged.

>> + */

>> +odp_packet_t odp_packet_ref_static(odp_packet_t pkt);

>> +

>> +/**

>> + * Create a reference to a packet

>> + *

>> + * Create a dynamic reference to a packet starting at a specified byte

>> + * offset. This reference may be used as an argument to header manipulation

>> + * APIs to prefix a unique header onto the shared base. The storage associated

>> + * with the referenced packet is not freed until all references to it are

>> + * freed, which permits easy multicasting or retransmission processing to be

>> + * performed. Following a successful call, the shared portions of the

>> + * referenced packet packet should be treated as read only. Results are

>> + * undefined if this restriction is not observed.

>> + *

>> + * This operation logically prepends a zero-length header onto the referenced

>> + * packet beginning at the specified offset. This header is always drawn from

>> + * the same pool as the referenced packet.

>> + *

>> + * Because references are unique packets, any bytes pushed onto the head of a

>> + * reference via odp_packet_push_head() or odp_packet_extend_head() are unique

>> + * to this reference and are not seen by the referenced packet or by any other

>> + * reference to the same packet. Similarly, any bytes pushed onto the

>> + * head of the referenced packet are not visible to any reference created

>> + * prior to the push operation.

>> + *

>> + * Note that the existence of references does not in any way change the

>> + * requirement that a single packet handle may only be manipulated by one

>> + * thread at a time.  The odp_packet_unshared_len() API may be used to

>> + * determine the number of bytes starting at offset zero that are unique to

>> + * this packet handle. Only these bytes should be considered modifiable. All

>> + * other bytes accessible from this handle should be treated as read only.

>> + *

>> + * The packet used as input to this routine may itself by a reference to

>> + * some other packet. Implementations MAY restrict the ability to create

>> + * such compound references. Attempts to exceed any implementation limits in

>> + * this regard will result in this call failing and returning

>> + * ODP_PACKET_INVALID.

>> + *

>> + * If the caller does not indend to push a header onto either the returned

>> + * reference or the packet being referenced, or otherwise modify either

>> + * packet, the odp_packet_ref_static() API may be used. This may be a more

>> + * efficient means of obtaining another reference to a packet if both will be

>> + * treated as read only.

>> + *

>> + * @param pkt    Handle of the packet for which a reference is to be

>> + *               created.

>> + *

>> + * @param offset Byte offset in pkt at which the shared reference is to

>> + *               begin. This must be in the range 0..odp_packet_len(pkt)-1.

>> + *

>> + * @return                    Handle of the reference packet

>> + * @retval ODP_PACKET_INVALID Operation failed. pkt remains unchanged.

>> + *

>> +

>> + */

>> +odp_packet_t odp_packet_ref(odp_packet_t pkt, uint32_t offset);

>> +

>> +/**

>> + * Create a reference to another packet from a header packet

>> + *

>> + * Create a dynamic reference to a packet starting at a specified byte offset

>> + * by prepending a supplied header packet. The resulting reference consists of

>> + * the unshared header followed by the shared referenced packet starting at

>> + * the specified offset. This shared portion should be regarded as read

>> + * only. The storage associated with the shared portion of the reference is

>> + * not freed until all references to it are freed, which permits easy

>> + * multicasting or retransmission processing to be performed.

>> + *

>> + * Because references are unique packets, any bytes pushed onto the head of a

>> + * reference via odp_packet_push_head() or odp_packet_extend_head() are unique

>> + * to this reference and are not seen by the referenced packet or by any other

>> + * reference to the same packet. Similarly, any bytes pushed onto the

>> + * head of the referenced packet are not visible to any reference created

>> + * prior to the push operation.

>> + *

>> + * Note that the existence of references does not in any way change the

>> + * requirement that a single packet handle may only be manipulated by one

>> + * thread at a time.  The odp_packet_unshared_len() API may be used to

>> + * determine the number of bytes starting at offset zero that are unique to

>> + * this packet handle. Only these bytes should be considered modifiable. All

>> + * other bytes accessible from this handle should be treated as read only.

>> + *

>> + * Either packet input to this routine may itself be a reference, however

>> + * individual implementations MAY impose limits on how deeply references may be

>> + * nested and fail the call if those limits are exceeded.

>> + *

>> + * The packets used as input to this routine may reside in different pools,

>> + * however individual implementations MAY require that both reside in the same

>> + * pool and fail the call if this restriction is not observed. For best

>> + * portability, both should reside in the same pool.

>> + *

>> + * odp_packet_pool() on the returned reference returns the pool id of the

>> + * header packet.

>> + *

>> + * @param pkt    Handle of the packet for which a reference is to be

>> + *               created.

>> + *

>> + * @param offset Byte offset in pkt at which the shared reference is to

>> + *               begin. Must be in the range 0..odp_packet_len(pkt)-1.

>> + *

>> + * @param hdr    Handle of the header packet to be prefixed onto pkt to create

>> + *               the reference. If this is specified as ODP_PACKET_INVALID,

>> + *               this call is equivalent to odp_packet_ref(). The supplied hdr

>> + *               must be distinct from pkt and results are undefined if an

>> + *               attempt is made to create circular references.

>> + *

>> + * @return       Handle of the reference packet. This may or may not be the

>> + *               same as the input hdr packet. The caller should only use this

>> + *               handle since the original hdr packet no longer has any

>> + *               independent existence.

>> + *

>> + * @retval ODP_PACKET_INVALID Operation failed. Both pkt and hdr are unchanged.

>> + */

>> +odp_packet_t odp_packet_ref_pkt(odp_packet_t pkt, uint32_t offset,

>> +                               odp_packet_t hdr);

>> +

>> +/**

>> + * Test if a packet is a reference

>> + *

>> + * A packet is a reference if it was created by odp_packet_ref() or

>> + * odp_packet_ref_pkt(). Note that a reference created from another

>> + * reference is considered a compound reference. Calls on such packets will

>> + * result in return values greater than 1.

>> + *

>> + * @param pkt Packet handle

>> + *

>> + * @retval 0  Packet is not a reference

>> + * @retval >0 Packet is a reference consisting of N individual packets.

>> + */

>> +int odp_packet_is_ref(odp_packet_t pkt);

>> +

>> +/**

>> + * Test if a packet has a reference

>> + *

>> + * A packet has a reference if a reference was created to it by

>> + * odp_packet_ref_static(), odp_packet_ref(), or odp_packet_ref_pkt().

>> + *

>> + * @param pkt Packet handle

>> + *

>> + * @retval 0  Packet does not have any references

>> + * @retval >0 Packet has N references to it

>> + */

>> +int odp_packet_has_ref(odp_packet_t pkt);

>

> I haven't gone through this proposal fully but I believe we had an

> understanding that there will not be any difference between reference

> and base packet. So why do you need these two types of reference query

> APIs odp_packet_is_ref() and odp_packet_has_ref().


There are now no differences in terms of whether you can push/extend
additional headers onto packets before or after a reference is
created, but I believe this is still a useful bit of information.

odp_packet_is_ref() > 0 if this handle was created by an odp_packet_ref() call.

odp_packet_has_ref() > 0 if this handle was the argument to an
odp_packet_ref() call and that reference still exists.

>

> Regards,

> Bala

>> +

>> +/*

>> + *

>>   * Copy

>>   * ********************************************************

>>   *

>> --

>> 2.7.4

>>
Balasubramanian Manoharan Jan. 4, 2017, 12:32 p.m. | #2
Regards,
Bala


On 3 January 2017 at 20:02, Bill Fischofer <bill.fischofer@linaro.org> wrote:
> On Tue, Jan 3, 2017 at 8:14 AM, Bala Manoharan

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

>> Regards,

>> Bala

>>

>>

>> On 2 January 2017 at 05:10, Bill Fischofer <bill.fischofer@linaro.org> wrote:

>>> Introduce three new APIs that support efficient sharing of portions of

>>> packets.

>>>

>>> odp_packet_ref_static() creates an alias for a base packet

>>>

>>> odp_packet_ref() creates a reference to a base packet

>>>

>>> odp_packet_ref_pkt() creates a reference to a base packet from a supplied

>>> header packet

>>>

>>> In addition, three other APIs simplify working with references

>>>

>>> odp_packet_is_ref() says whether a packet is a reference

>>>

>>> odp_packet_has_ref() says whether a packet has had a reference made to it

>>>

>>> odp_packet_unshared_len() gives the length of the prefix bytes that are

>>> unique to this reference. These are the only bytes of the packet that may

>>> be modified safely.

>>>

>>> Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>

>>> ---

>>> Changes in v4:

>>> - Bug fixes

>>> - Expand validation testing to cover extensions on packets with references

>>>

>>> Changes in v3:

>>> - Rebased to latest API-NEXT

>>> - Bug fixes

>>> - Eliminate concept of base packets, both references and referenced packets may

>>>   have head extensions as needed

>>>

>>>  include/odp/api/spec/packet.h | 190 +++++++++++++++++++++++++++++++++++++++++-

>>>  1 file changed, 189 insertions(+), 1 deletion(-)

>>>

>>> diff --git a/include/odp/api/spec/packet.h b/include/odp/api/spec/packet.h

>>> index 4a86eba..0791496 100644

>>> --- a/include/odp/api/spec/packet.h

>>> +++ b/include/odp/api/spec/packet.h

>>> @@ -256,6 +256,20 @@ uint32_t odp_packet_seg_len(odp_packet_t pkt);

>>>  uint32_t odp_packet_len(odp_packet_t pkt);

>>>

>>>  /**

>>> + * Packet unshared data len

>>> + *

>>> + * Returns the sum of data lengths over all unshared packet segments. These

>>> + * are the only bytes that should be modified by the caller. The rest of the

>>> + * packet should be treated as read only. odp_packet_unshared_len() will be

>>> + * equal to odp_packet_len() if odp_packet_has_ref() is 0.

>>> + *

>>> + * @param pkt Packet handle

>>> + *

>>> + * @return Packet unshared data length

>>> + */

>>> +uint32_t odp_packet_unshared_len(odp_packet_t pkt);

>>> +

>>> +/**

>>>   * Packet headroom length

>>>   *

>>>   * Returns the current packet level headroom length.

>>> @@ -795,7 +809,7 @@ uint32_t odp_packet_seg_data_len(odp_packet_t pkt, odp_packet_seg_t seg);

>>>   * data pointers. Otherwise, all old pointers remain valid.

>>>   *

>>>   * The resulting packet is always allocated from the same pool as

>>> - * the destination packet. The source packet may have been allocate from

>>> + * the destination packet. The source packet may have been allocated from

>>>   * any pool.

>>>   *

>>>   * On failure, both handles remain valid and packets are not modified.

>>> @@ -848,6 +862,180 @@ int odp_packet_split(odp_packet_t *pkt, uint32_t len, odp_packet_t *tail);

>>>

>>>  /*

>>>   *

>>> + * References

>>> + * ********************************************************

>>> + *

>>> + */

>>> +

>>> +/**

>>> + * Create a static reference to a packet

>>> + *

>>> + * A static reference is used to obtain an additional handle for referring to

>>> + * a packet so that the storage behind it is not freed until all references to

>>> + * the packet are freed. This can be used, for example, to support efficient

>>> + * retransmission processing.

>>> + *

>>> + * The intent of a static reference is that both the packet and the returned

>>> + * reference to it will be treated as read only after this call. Results are

>>> + * undefined if this restriction is not observed.

>>> + *

>>> + * Static references have restrictions but may have performance advantages on

>>> + * some platforms if the caller does not intend to modify the reference

>>> + * packet. If modification is needed (e.g., to prefix a unique header onto the

>>> + * packet) then odp_packet_ref() or odp_packet_ref_pkt() should be used.

>>> + *

>>> + * @param pkt    Handle of the packet for which a static reference is

>>> + *               to be created.

>>> + *

>>> + * @return                    Handle of the static reference packet

>>> + * @retval ODP_PACKET_INVALID Operation failed. pkt remains unchanged.

>>> + */

>>> +odp_packet_t odp_packet_ref_static(odp_packet_t pkt);

>>> +

>>> +/**

>>> + * Create a reference to a packet

>>> + *

>>> + * Create a dynamic reference to a packet starting at a specified byte

>>> + * offset. This reference may be used as an argument to header manipulation

>>> + * APIs to prefix a unique header onto the shared base. The storage associated

>>> + * with the referenced packet is not freed until all references to it are

>>> + * freed, which permits easy multicasting or retransmission processing to be

>>> + * performed. Following a successful call, the shared portions of the

>>> + * referenced packet packet should be treated as read only. Results are

>>> + * undefined if this restriction is not observed.

>>> + *

>>> + * This operation logically prepends a zero-length header onto the referenced

>>> + * packet beginning at the specified offset. This header is always drawn from

>>> + * the same pool as the referenced packet.

>>> + *

>>> + * Because references are unique packets, any bytes pushed onto the head of a

>>> + * reference via odp_packet_push_head() or odp_packet_extend_head() are unique

>>> + * to this reference and are not seen by the referenced packet or by any other

>>> + * reference to the same packet. Similarly, any bytes pushed onto the

>>> + * head of the referenced packet are not visible to any reference created

>>> + * prior to the push operation.

>>> + *

>>> + * Note that the existence of references does not in any way change the

>>> + * requirement that a single packet handle may only be manipulated by one

>>> + * thread at a time.  The odp_packet_unshared_len() API may be used to

>>> + * determine the number of bytes starting at offset zero that are unique to

>>> + * this packet handle. Only these bytes should be considered modifiable. All

>>> + * other bytes accessible from this handle should be treated as read only.

>>> + *

>>> + * The packet used as input to this routine may itself by a reference to

>>> + * some other packet. Implementations MAY restrict the ability to create

>>> + * such compound references. Attempts to exceed any implementation limits in

>>> + * this regard will result in this call failing and returning

>>> + * ODP_PACKET_INVALID.

>>> + *

>>> + * If the caller does not indend to push a header onto either the returned

>>> + * reference or the packet being referenced, or otherwise modify either

>>> + * packet, the odp_packet_ref_static() API may be used. This may be a more

>>> + * efficient means of obtaining another reference to a packet if both will be

>>> + * treated as read only.

>>> + *

>>> + * @param pkt    Handle of the packet for which a reference is to be

>>> + *               created.

>>> + *

>>> + * @param offset Byte offset in pkt at which the shared reference is to

>>> + *               begin. This must be in the range 0..odp_packet_len(pkt)-1.

>>> + *

>>> + * @return                    Handle of the reference packet

>>> + * @retval ODP_PACKET_INVALID Operation failed. pkt remains unchanged.

>>> + *

>>> +

>>> + */

>>> +odp_packet_t odp_packet_ref(odp_packet_t pkt, uint32_t offset);

>>> +

>>> +/**

>>> + * Create a reference to another packet from a header packet

>>> + *

>>> + * Create a dynamic reference to a packet starting at a specified byte offset

>>> + * by prepending a supplied header packet. The resulting reference consists of

>>> + * the unshared header followed by the shared referenced packet starting at

>>> + * the specified offset. This shared portion should be regarded as read

>>> + * only. The storage associated with the shared portion of the reference is

>>> + * not freed until all references to it are freed, which permits easy

>>> + * multicasting or retransmission processing to be performed.

>>> + *

>>> + * Because references are unique packets, any bytes pushed onto the head of a

>>> + * reference via odp_packet_push_head() or odp_packet_extend_head() are unique

>>> + * to this reference and are not seen by the referenced packet or by any other

>>> + * reference to the same packet. Similarly, any bytes pushed onto the

>>> + * head of the referenced packet are not visible to any reference created

>>> + * prior to the push operation.

>>> + *

>>> + * Note that the existence of references does not in any way change the

>>> + * requirement that a single packet handle may only be manipulated by one

>>> + * thread at a time.  The odp_packet_unshared_len() API may be used to

>>> + * determine the number of bytes starting at offset zero that are unique to

>>> + * this packet handle. Only these bytes should be considered modifiable. All

>>> + * other bytes accessible from this handle should be treated as read only.

>>> + *

>>> + * Either packet input to this routine may itself be a reference, however

>>> + * individual implementations MAY impose limits on how deeply references may be

>>> + * nested and fail the call if those limits are exceeded.

>>> + *

>>> + * The packets used as input to this routine may reside in different pools,

>>> + * however individual implementations MAY require that both reside in the same

>>> + * pool and fail the call if this restriction is not observed. For best

>>> + * portability, both should reside in the same pool.


I am not sure how many platforms with HW pool manager will be able to
support this creation of complex reference with packets from multiple
pools coz this will cause an issue when your are trying to free
individual buffers to their allocated pools. If there aren't any
platforms with HW pool manager which support this we can add this as a
global restriction.

>>> + *

>>> + * odp_packet_pool() on the returned reference returns the pool id of the

>>> + * header packet.

>>> + *

>>> + * @param pkt    Handle of the packet for which a reference is to be

>>> + *               created.

>>> + *

>>> + * @param offset Byte offset in pkt at which the shared reference is to

>>> + *               begin. Must be in the range 0..odp_packet_len(pkt)-1.

>>> + *

>>> + * @param hdr    Handle of the header packet to be prefixed onto pkt to create

>>> + *               the reference. If this is specified as ODP_PACKET_INVALID,

>>> + *               this call is equivalent to odp_packet_ref(). The supplied hdr

>>> + *               must be distinct from pkt and results are undefined if an

>>> + *               attempt is made to create circular references.

>>> + *

>>> + * @return       Handle of the reference packet. This may or may not be the

>>> + *               same as the input hdr packet. The caller should only use this

>>> + *               handle since the original hdr packet no longer has any

>>> + *               independent existence.

>>> + *

>>> + * @retval ODP_PACKET_INVALID Operation failed. Both pkt and hdr are unchanged.

>>> + */

>>> +odp_packet_t odp_packet_ref_pkt(odp_packet_t pkt, uint32_t offset,

>>> +                               odp_packet_t hdr);

>>> +

>>> +/**

>>> + * Test if a packet is a reference

>>> + *

>>> + * A packet is a reference if it was created by odp_packet_ref() or

>>> + * odp_packet_ref_pkt(). Note that a reference created from another

>>> + * reference is considered a compound reference. Calls on such packets will

>>> + * result in return values greater than 1.

>>> + *

>>> + * @param pkt Packet handle

>>> + *

>>> + * @retval 0  Packet is not a reference

>>> + * @retval >0 Packet is a reference consisting of N individual packets.

>>> + */

>>> +int odp_packet_is_ref(odp_packet_t pkt);

>>> +

>>> +/**

>>> + * Test if a packet has a reference

>>> + *

>>> + * A packet has a reference if a reference was created to it by

>>> + * odp_packet_ref_static(), odp_packet_ref(), or odp_packet_ref_pkt().

>>> + *

>>> + * @param pkt Packet handle

>>> + *

>>> + * @retval 0  Packet does not have any references

>>> + * @retval >0 Packet has N references to it

>>> + */

>>> +int odp_packet_has_ref(odp_packet_t pkt);

>>

>> I haven't gone through this proposal fully but I believe we had an

>> understanding that there will not be any difference between reference

>> and base packet. So why do you need these two types of reference query

>> APIs odp_packet_is_ref() and odp_packet_has_ref().

>

> There are now no differences in terms of whether you can push/extend

> additional headers onto packets before or after a reference is

> created, but I believe this is still a useful bit of information.

>

> odp_packet_is_ref() > 0 if this handle was created by an odp_packet_ref() call.

>

> odp_packet_has_ref() > 0 if this handle was the argument to an

> odp_packet_ref() call and that reference still exists.


Unless there is an use-case from application where this
differentiation is needed. I would prefer to avoid this
differentiation.
There could be a single API odp_packet_is_ref() which denotes the
number of references currently available for this packet.

Regards,
Bala
>

>>

>> Regards,

>> Bala

>>> +

>>> +/*

>>> + *

>>>   * Copy

>>>   * ********************************************************

>>>   *

>>> --

>>> 2.7.4

>>>
Bill Fischofer Jan. 4, 2017, 12:55 p.m. | #3
On Wed, Jan 4, 2017 at 6:32 AM, Bala Manoharan
<bala.manoharan@linaro.org> wrote:
> Regards,

> Bala

>

>

> On 3 January 2017 at 20:02, Bill Fischofer <bill.fischofer@linaro.org> wrote:

>> On Tue, Jan 3, 2017 at 8:14 AM, Bala Manoharan

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

>>> Regards,

>>> Bala

>>>

>>>

>>> On 2 January 2017 at 05:10, Bill Fischofer <bill.fischofer@linaro.org> wrote:

>>>> Introduce three new APIs that support efficient sharing of portions of

>>>> packets.

>>>>

>>>> odp_packet_ref_static() creates an alias for a base packet

>>>>

>>>> odp_packet_ref() creates a reference to a base packet

>>>>

>>>> odp_packet_ref_pkt() creates a reference to a base packet from a supplied

>>>> header packet

>>>>

>>>> In addition, three other APIs simplify working with references

>>>>

>>>> odp_packet_is_ref() says whether a packet is a reference

>>>>

>>>> odp_packet_has_ref() says whether a packet has had a reference made to it

>>>>

>>>> odp_packet_unshared_len() gives the length of the prefix bytes that are

>>>> unique to this reference. These are the only bytes of the packet that may

>>>> be modified safely.

>>>>

>>>> Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>

>>>> ---

>>>> Changes in v4:

>>>> - Bug fixes

>>>> - Expand validation testing to cover extensions on packets with references

>>>>

>>>> Changes in v3:

>>>> - Rebased to latest API-NEXT

>>>> - Bug fixes

>>>> - Eliminate concept of base packets, both references and referenced packets may

>>>>   have head extensions as needed

>>>>

>>>>  include/odp/api/spec/packet.h | 190 +++++++++++++++++++++++++++++++++++++++++-

>>>>  1 file changed, 189 insertions(+), 1 deletion(-)

>>>>

>>>> diff --git a/include/odp/api/spec/packet.h b/include/odp/api/spec/packet.h

>>>> index 4a86eba..0791496 100644

>>>> --- a/include/odp/api/spec/packet.h

>>>> +++ b/include/odp/api/spec/packet.h

>>>> @@ -256,6 +256,20 @@ uint32_t odp_packet_seg_len(odp_packet_t pkt);

>>>>  uint32_t odp_packet_len(odp_packet_t pkt);

>>>>

>>>>  /**

>>>> + * Packet unshared data len

>>>> + *

>>>> + * Returns the sum of data lengths over all unshared packet segments. These

>>>> + * are the only bytes that should be modified by the caller. The rest of the

>>>> + * packet should be treated as read only. odp_packet_unshared_len() will be

>>>> + * equal to odp_packet_len() if odp_packet_has_ref() is 0.

>>>> + *

>>>> + * @param pkt Packet handle

>>>> + *

>>>> + * @return Packet unshared data length

>>>> + */

>>>> +uint32_t odp_packet_unshared_len(odp_packet_t pkt);

>>>> +

>>>> +/**

>>>>   * Packet headroom length

>>>>   *

>>>>   * Returns the current packet level headroom length.

>>>> @@ -795,7 +809,7 @@ uint32_t odp_packet_seg_data_len(odp_packet_t pkt, odp_packet_seg_t seg);

>>>>   * data pointers. Otherwise, all old pointers remain valid.

>>>>   *

>>>>   * The resulting packet is always allocated from the same pool as

>>>> - * the destination packet. The source packet may have been allocate from

>>>> + * the destination packet. The source packet may have been allocated from

>>>>   * any pool.

>>>>   *

>>>>   * On failure, both handles remain valid and packets are not modified.

>>>> @@ -848,6 +862,180 @@ int odp_packet_split(odp_packet_t *pkt, uint32_t len, odp_packet_t *tail);

>>>>

>>>>  /*

>>>>   *

>>>> + * References

>>>> + * ********************************************************

>>>> + *

>>>> + */

>>>> +

>>>> +/**

>>>> + * Create a static reference to a packet

>>>> + *

>>>> + * A static reference is used to obtain an additional handle for referring to

>>>> + * a packet so that the storage behind it is not freed until all references to

>>>> + * the packet are freed. This can be used, for example, to support efficient

>>>> + * retransmission processing.

>>>> + *

>>>> + * The intent of a static reference is that both the packet and the returned

>>>> + * reference to it will be treated as read only after this call. Results are

>>>> + * undefined if this restriction is not observed.

>>>> + *

>>>> + * Static references have restrictions but may have performance advantages on

>>>> + * some platforms if the caller does not intend to modify the reference

>>>> + * packet. If modification is needed (e.g., to prefix a unique header onto the

>>>> + * packet) then odp_packet_ref() or odp_packet_ref_pkt() should be used.

>>>> + *

>>>> + * @param pkt    Handle of the packet for which a static reference is

>>>> + *               to be created.

>>>> + *

>>>> + * @return                    Handle of the static reference packet

>>>> + * @retval ODP_PACKET_INVALID Operation failed. pkt remains unchanged.

>>>> + */

>>>> +odp_packet_t odp_packet_ref_static(odp_packet_t pkt);

>>>> +

>>>> +/**

>>>> + * Create a reference to a packet

>>>> + *

>>>> + * Create a dynamic reference to a packet starting at a specified byte

>>>> + * offset. This reference may be used as an argument to header manipulation

>>>> + * APIs to prefix a unique header onto the shared base. The storage associated

>>>> + * with the referenced packet is not freed until all references to it are

>>>> + * freed, which permits easy multicasting or retransmission processing to be

>>>> + * performed. Following a successful call, the shared portions of the

>>>> + * referenced packet packet should be treated as read only. Results are

>>>> + * undefined if this restriction is not observed.

>>>> + *

>>>> + * This operation logically prepends a zero-length header onto the referenced

>>>> + * packet beginning at the specified offset. This header is always drawn from

>>>> + * the same pool as the referenced packet.

>>>> + *

>>>> + * Because references are unique packets, any bytes pushed onto the head of a

>>>> + * reference via odp_packet_push_head() or odp_packet_extend_head() are unique

>>>> + * to this reference and are not seen by the referenced packet or by any other

>>>> + * reference to the same packet. Similarly, any bytes pushed onto the

>>>> + * head of the referenced packet are not visible to any reference created

>>>> + * prior to the push operation.

>>>> + *

>>>> + * Note that the existence of references does not in any way change the

>>>> + * requirement that a single packet handle may only be manipulated by one

>>>> + * thread at a time.  The odp_packet_unshared_len() API may be used to

>>>> + * determine the number of bytes starting at offset zero that are unique to

>>>> + * this packet handle. Only these bytes should be considered modifiable. All

>>>> + * other bytes accessible from this handle should be treated as read only.

>>>> + *

>>>> + * The packet used as input to this routine may itself by a reference to

>>>> + * some other packet. Implementations MAY restrict the ability to create

>>>> + * such compound references. Attempts to exceed any implementation limits in

>>>> + * this regard will result in this call failing and returning

>>>> + * ODP_PACKET_INVALID.

>>>> + *

>>>> + * If the caller does not indend to push a header onto either the returned

>>>> + * reference or the packet being referenced, or otherwise modify either

>>>> + * packet, the odp_packet_ref_static() API may be used. This may be a more

>>>> + * efficient means of obtaining another reference to a packet if both will be

>>>> + * treated as read only.

>>>> + *

>>>> + * @param pkt    Handle of the packet for which a reference is to be

>>>> + *               created.

>>>> + *

>>>> + * @param offset Byte offset in pkt at which the shared reference is to

>>>> + *               begin. This must be in the range 0..odp_packet_len(pkt)-1.

>>>> + *

>>>> + * @return                    Handle of the reference packet

>>>> + * @retval ODP_PACKET_INVALID Operation failed. pkt remains unchanged.

>>>> + *

>>>> +

>>>> + */

>>>> +odp_packet_t odp_packet_ref(odp_packet_t pkt, uint32_t offset);

>>>> +

>>>> +/**

>>>> + * Create a reference to another packet from a header packet

>>>> + *

>>>> + * Create a dynamic reference to a packet starting at a specified byte offset

>>>> + * by prepending a supplied header packet. The resulting reference consists of

>>>> + * the unshared header followed by the shared referenced packet starting at

>>>> + * the specified offset. This shared portion should be regarded as read

>>>> + * only. The storage associated with the shared portion of the reference is

>>>> + * not freed until all references to it are freed, which permits easy

>>>> + * multicasting or retransmission processing to be performed.

>>>> + *

>>>> + * Because references are unique packets, any bytes pushed onto the head of a

>>>> + * reference via odp_packet_push_head() or odp_packet_extend_head() are unique

>>>> + * to this reference and are not seen by the referenced packet or by any other

>>>> + * reference to the same packet. Similarly, any bytes pushed onto the

>>>> + * head of the referenced packet are not visible to any reference created

>>>> + * prior to the push operation.

>>>> + *

>>>> + * Note that the existence of references does not in any way change the

>>>> + * requirement that a single packet handle may only be manipulated by one

>>>> + * thread at a time.  The odp_packet_unshared_len() API may be used to

>>>> + * determine the number of bytes starting at offset zero that are unique to

>>>> + * this packet handle. Only these bytes should be considered modifiable. All

>>>> + * other bytes accessible from this handle should be treated as read only.

>>>> + *

>>>> + * Either packet input to this routine may itself be a reference, however

>>>> + * individual implementations MAY impose limits on how deeply references may be

>>>> + * nested and fail the call if those limits are exceeded.

>>>> + *

>>>> + * The packets used as input to this routine may reside in different pools,

>>>> + * however individual implementations MAY require that both reside in the same

>>>> + * pool and fail the call if this restriction is not observed. For best

>>>> + * portability, both should reside in the same pool.

>

> I am not sure how many platforms with HW pool manager will be able to

> support this creation of complex reference with packets from multiple

> pools coz this will cause an issue when your are trying to free

> individual buffers to their allocated pools. If there aren't any

> platforms with HW pool manager which support this we can add this as a

> global restriction.


That's why this is written as shown with the "MAY require" clause and
the recommendation for a single pool for best portability. I have no
problem making this a specification restriction if that's the
consensus, however it means that every implementation would have to
explicitly test for this and reject attempts at cross-pool references
if they are attempted whether or not they could be supported. Leaving
this support up to the implementation seems a more flexible approach.

>

>>>> + *

>>>> + * odp_packet_pool() on the returned reference returns the pool id of the

>>>> + * header packet.

>>>> + *

>>>> + * @param pkt    Handle of the packet for which a reference is to be

>>>> + *               created.

>>>> + *

>>>> + * @param offset Byte offset in pkt at which the shared reference is to

>>>> + *               begin. Must be in the range 0..odp_packet_len(pkt)-1.

>>>> + *

>>>> + * @param hdr    Handle of the header packet to be prefixed onto pkt to create

>>>> + *               the reference. If this is specified as ODP_PACKET_INVALID,

>>>> + *               this call is equivalent to odp_packet_ref(). The supplied hdr

>>>> + *               must be distinct from pkt and results are undefined if an

>>>> + *               attempt is made to create circular references.

>>>> + *

>>>> + * @return       Handle of the reference packet. This may or may not be the

>>>> + *               same as the input hdr packet. The caller should only use this

>>>> + *               handle since the original hdr packet no longer has any

>>>> + *               independent existence.

>>>> + *

>>>> + * @retval ODP_PACKET_INVALID Operation failed. Both pkt and hdr are unchanged.

>>>> + */

>>>> +odp_packet_t odp_packet_ref_pkt(odp_packet_t pkt, uint32_t offset,

>>>> +                               odp_packet_t hdr);

>>>> +

>>>> +/**

>>>> + * Test if a packet is a reference

>>>> + *

>>>> + * A packet is a reference if it was created by odp_packet_ref() or

>>>> + * odp_packet_ref_pkt(). Note that a reference created from another

>>>> + * reference is considered a compound reference. Calls on such packets will

>>>> + * result in return values greater than 1.

>>>> + *

>>>> + * @param pkt Packet handle

>>>> + *

>>>> + * @retval 0  Packet is not a reference

>>>> + * @retval >0 Packet is a reference consisting of N individual packets.

>>>> + */

>>>> +int odp_packet_is_ref(odp_packet_t pkt);

>>>> +

>>>> +/**

>>>> + * Test if a packet has a reference

>>>> + *

>>>> + * A packet has a reference if a reference was created to it by

>>>> + * odp_packet_ref_static(), odp_packet_ref(), or odp_packet_ref_pkt().

>>>> + *

>>>> + * @param pkt Packet handle

>>>> + *

>>>> + * @retval 0  Packet does not have any references

>>>> + * @retval >0 Packet has N references to it

>>>> + */

>>>> +int odp_packet_has_ref(odp_packet_t pkt);

>>>

>>> I haven't gone through this proposal fully but I believe we had an

>>> understanding that there will not be any difference between reference

>>> and base packet. So why do you need these two types of reference query

>>> APIs odp_packet_is_ref() and odp_packet_has_ref().

>>

>> There are now no differences in terms of whether you can push/extend

>> additional headers onto packets before or after a reference is

>> created, but I believe this is still a useful bit of information.

>>

>> odp_packet_is_ref() > 0 if this handle was created by an odp_packet_ref() call.

>>

>> odp_packet_has_ref() > 0 if this handle was the argument to an

>> odp_packet_ref() call and that reference still exists.

>

> Unless there is an use-case from application where this

> differentiation is needed. I would prefer to avoid this

> differentiation.

> There could be a single API odp_packet_is_ref() which denotes the

> number of references currently available for this packet.


The function you describe is what odp_packet_has_ref() does, and I
would retain that name. Every implementation needs this since when an
odp_packet_free() call is made it needs to know whether it should
actually free the segments associated with the packet or retain them
if further references to this packet still exist.

odp_packet_is_ref() is needed internally in odp-linux as part of
dereferencing, so it's there for completeness in the external API. Is
the desire to not expose this API because its defined semantics would
present implementation issues for you? Or is it that the specification
of it returning the reference depth the issue? Note that if an
implementation does not support nested references then
odp_packet_is_ref() would only ever return 0 or 1.

>

> Regards,

> Bala

>>

>>>

>>> Regards,

>>> Bala

>>>> +

>>>> +/*

>>>> + *

>>>>   * Copy

>>>>   * ********************************************************

>>>>   *

>>>> --

>>>> 2.7.4

>>>>

Patch

diff --git a/include/odp/api/spec/packet.h b/include/odp/api/spec/packet.h
index 4a86eba..0791496 100644
--- a/include/odp/api/spec/packet.h
+++ b/include/odp/api/spec/packet.h
@@ -256,6 +256,20 @@  uint32_t odp_packet_seg_len(odp_packet_t pkt);
 uint32_t odp_packet_len(odp_packet_t pkt);
 
 /**
+ * Packet unshared data len
+ *
+ * Returns the sum of data lengths over all unshared packet segments. These
+ * are the only bytes that should be modified by the caller. The rest of the
+ * packet should be treated as read only. odp_packet_unshared_len() will be
+ * equal to odp_packet_len() if odp_packet_has_ref() is 0.
+ *
+ * @param pkt Packet handle
+ *
+ * @return Packet unshared data length
+ */
+uint32_t odp_packet_unshared_len(odp_packet_t pkt);
+
+/**
  * Packet headroom length
  *
  * Returns the current packet level headroom length.
@@ -795,7 +809,7 @@  uint32_t odp_packet_seg_data_len(odp_packet_t pkt, odp_packet_seg_t seg);
  * data pointers. Otherwise, all old pointers remain valid.
  *
  * The resulting packet is always allocated from the same pool as
- * the destination packet. The source packet may have been allocate from
+ * the destination packet. The source packet may have been allocated from
  * any pool.
  *
  * On failure, both handles remain valid and packets are not modified.
@@ -848,6 +862,180 @@  int odp_packet_split(odp_packet_t *pkt, uint32_t len, odp_packet_t *tail);
 
 /*
  *
+ * References
+ * ********************************************************
+ *
+ */
+
+/**
+ * Create a static reference to a packet
+ *
+ * A static reference is used to obtain an additional handle for referring to
+ * a packet so that the storage behind it is not freed until all references to
+ * the packet are freed. This can be used, for example, to support efficient
+ * retransmission processing.
+ *
+ * The intent of a static reference is that both the packet and the returned
+ * reference to it will be treated as read only after this call. Results are
+ * undefined if this restriction is not observed.
+ *
+ * Static references have restrictions but may have performance advantages on
+ * some platforms if the caller does not intend to modify the reference
+ * packet. If modification is needed (e.g., to prefix a unique header onto the
+ * packet) then odp_packet_ref() or odp_packet_ref_pkt() should be used.
+ *
+ * @param pkt    Handle of the packet for which a static reference is
+ *               to be created.
+ *
+ * @return                    Handle of the static reference packet
+ * @retval ODP_PACKET_INVALID Operation failed. pkt remains unchanged.
+ */
+odp_packet_t odp_packet_ref_static(odp_packet_t pkt);
+
+/**
+ * Create a reference to a packet
+ *
+ * Create a dynamic reference to a packet starting at a specified byte
+ * offset. This reference may be used as an argument to header manipulation
+ * APIs to prefix a unique header onto the shared base. The storage associated
+ * with the referenced packet is not freed until all references to it are
+ * freed, which permits easy multicasting or retransmission processing to be
+ * performed. Following a successful call, the shared portions of the
+ * referenced packet packet should be treated as read only. Results are
+ * undefined if this restriction is not observed.
+ *
+ * This operation logically prepends a zero-length header onto the referenced
+ * packet beginning at the specified offset. This header is always drawn from
+ * the same pool as the referenced packet.
+ *
+ * Because references are unique packets, any bytes pushed onto the head of a
+ * reference via odp_packet_push_head() or odp_packet_extend_head() are unique
+ * to this reference and are not seen by the referenced packet or by any other
+ * reference to the same packet. Similarly, any bytes pushed onto the
+ * head of the referenced packet are not visible to any reference created
+ * prior to the push operation.
+ *
+ * Note that the existence of references does not in any way change the
+ * requirement that a single packet handle may only be manipulated by one
+ * thread at a time.  The odp_packet_unshared_len() API may be used to
+ * determine the number of bytes starting at offset zero that are unique to
+ * this packet handle. Only these bytes should be considered modifiable. All
+ * other bytes accessible from this handle should be treated as read only.
+ *
+ * The packet used as input to this routine may itself by a reference to
+ * some other packet. Implementations MAY restrict the ability to create
+ * such compound references. Attempts to exceed any implementation limits in
+ * this regard will result in this call failing and returning
+ * ODP_PACKET_INVALID.
+ *
+ * If the caller does not indend to push a header onto either the returned
+ * reference or the packet being referenced, or otherwise modify either
+ * packet, the odp_packet_ref_static() API may be used. This may be a more
+ * efficient means of obtaining another reference to a packet if both will be
+ * treated as read only.
+ *
+ * @param pkt    Handle of the packet for which a reference is to be
+ *               created.
+ *
+ * @param offset Byte offset in pkt at which the shared reference is to
+ *               begin. This must be in the range 0..odp_packet_len(pkt)-1.
+ *
+ * @return                    Handle of the reference packet
+ * @retval ODP_PACKET_INVALID Operation failed. pkt remains unchanged.
+ *
+
+ */
+odp_packet_t odp_packet_ref(odp_packet_t pkt, uint32_t offset);
+
+/**
+ * Create a reference to another packet from a header packet
+ *
+ * Create a dynamic reference to a packet starting at a specified byte offset
+ * by prepending a supplied header packet. The resulting reference consists of
+ * the unshared header followed by the shared referenced packet starting at
+ * the specified offset. This shared portion should be regarded as read
+ * only. The storage associated with the shared portion of the reference is
+ * not freed until all references to it are freed, which permits easy
+ * multicasting or retransmission processing to be performed.
+ *
+ * Because references are unique packets, any bytes pushed onto the head of a
+ * reference via odp_packet_push_head() or odp_packet_extend_head() are unique
+ * to this reference and are not seen by the referenced packet or by any other
+ * reference to the same packet. Similarly, any bytes pushed onto the
+ * head of the referenced packet are not visible to any reference created
+ * prior to the push operation.
+ *
+ * Note that the existence of references does not in any way change the
+ * requirement that a single packet handle may only be manipulated by one
+ * thread at a time.  The odp_packet_unshared_len() API may be used to
+ * determine the number of bytes starting at offset zero that are unique to
+ * this packet handle. Only these bytes should be considered modifiable. All
+ * other bytes accessible from this handle should be treated as read only.
+ *
+ * Either packet input to this routine may itself be a reference, however
+ * individual implementations MAY impose limits on how deeply references may be
+ * nested and fail the call if those limits are exceeded.
+ *
+ * The packets used as input to this routine may reside in different pools,
+ * however individual implementations MAY require that both reside in the same
+ * pool and fail the call if this restriction is not observed. For best
+ * portability, both should reside in the same pool.
+ *
+ * odp_packet_pool() on the returned reference returns the pool id of the
+ * header packet.
+ *
+ * @param pkt    Handle of the packet for which a reference is to be
+ *               created.
+ *
+ * @param offset Byte offset in pkt at which the shared reference is to
+ *               begin. Must be in the range 0..odp_packet_len(pkt)-1.
+ *
+ * @param hdr    Handle of the header packet to be prefixed onto pkt to create
+ *               the reference. If this is specified as ODP_PACKET_INVALID,
+ *               this call is equivalent to odp_packet_ref(). The supplied hdr
+ *               must be distinct from pkt and results are undefined if an
+ *               attempt is made to create circular references.
+ *
+ * @return       Handle of the reference packet. This may or may not be the
+ *               same as the input hdr packet. The caller should only use this
+ *               handle since the original hdr packet no longer has any
+ *               independent existence.
+ *
+ * @retval ODP_PACKET_INVALID Operation failed. Both pkt and hdr are unchanged.
+ */
+odp_packet_t odp_packet_ref_pkt(odp_packet_t pkt, uint32_t offset,
+				odp_packet_t hdr);
+
+/**
+ * Test if a packet is a reference
+ *
+ * A packet is a reference if it was created by odp_packet_ref() or
+ * odp_packet_ref_pkt(). Note that a reference created from another
+ * reference is considered a compound reference. Calls on such packets will
+ * result in return values greater than 1.
+ *
+ * @param pkt Packet handle
+ *
+ * @retval 0  Packet is not a reference
+ * @retval >0 Packet is a reference consisting of N individual packets.
+ */
+int odp_packet_is_ref(odp_packet_t pkt);
+
+/**
+ * Test if a packet has a reference
+ *
+ * A packet has a reference if a reference was created to it by
+ * odp_packet_ref_static(), odp_packet_ref(), or odp_packet_ref_pkt().
+ *
+ * @param pkt Packet handle
+ *
+ * @retval 0  Packet does not have any references
+ * @retval >0 Packet has N references to it
+ */
+int odp_packet_has_ref(odp_packet_t pkt);
+
+/*
+ *
  * Copy
  * ********************************************************
  *