diff options
author | Jakub Kicinski <kuba@kernel.org> | 2022-05-09 09:04:55 -0700 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2022-05-10 17:48:35 -0700 |
commit | 9ec7ea1462084df695f34c5ac2d2d2250d9d6897 (patch) | |
tree | 688e1936d6e9e6b37beb090fb7e8cc65318662f3 /include/linux/skbuff.h | |
parent | ddccc9ef55992716ad477d38fbcd9f8f1d34fc67 (diff) | |
download | lwn-9ec7ea1462084df695f34c5ac2d2d2250d9d6897.tar.gz lwn-9ec7ea1462084df695f34c5ac2d2d2250d9d6897.zip |
skbuff: rewrite the doc for data-only skbs
The comment about shinfo->dataref split is really unhelpful,
at least to me. Rewrite it and render it to skb documentation.
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'include/linux/skbuff.h')
-rw-r--r-- | include/linux/skbuff.h | 42 |
1 files changed, 30 insertions, 12 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 69802624276d..0e492f9bf532 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -727,16 +727,32 @@ struct skb_shared_info { skb_frag_t frags[MAX_SKB_FRAGS]; }; -/* We divide dataref into two halves. The higher 16 bits hold references - * to the payload part of skb->data. The lower 16 bits hold references to - * the entire skb->data. A clone of a headerless skb holds the length of - * the header in skb->hdr_len. - * - * All users must obey the rule that the skb->data reference count must be - * greater than or equal to the payload reference count. - * - * Holding a reference to the payload part means that the user does not - * care about modifications to the header part of skb->data. +/** + * DOC: dataref and headerless skbs + * + * Transport layers send out clones of payload skbs they hold for + * retransmissions. To allow lower layers of the stack to prepend their headers + * we split &skb_shared_info.dataref into two halves. + * The lower 16 bits count the overall number of references. + * The higher 16 bits indicate how many of the references are payload-only. + * skb_header_cloned() checks if skb is allowed to add / write the headers. + * + * The creator of the skb (e.g. TCP) marks its skb as &sk_buff.nohdr + * (via __skb_header_release()). Any clone created from marked skb will get + * &sk_buff.hdr_len populated with the available headroom. + * If there's the only clone in existence it's able to modify the headroom + * at will. The sequence of calls inside the transport layer is:: + * + * <alloc skb> + * skb_reserve() + * __skb_header_release() + * skb_clone() + * // send the clone down the stack + * + * This is not a very generic construct and it depends on the transport layers + * doing the right thing. In practice there's usually only one payload-only skb. + * Having multiple payload-only skbs with different lengths of hdr_len is not + * possible. The payload-only skbs should never leave their owner. */ #define SKB_DATAREF_SHIFT 16 #define SKB_DATAREF_MASK ((1 << SKB_DATAREF_SHIFT) - 1) @@ -2027,8 +2043,10 @@ static inline int skb_header_unclone(struct sk_buff *skb, gfp_t pri) } /** - * __skb_header_release - release reference to header - * @skb: buffer to operate on + * __skb_header_release() - allow clones to use the headroom + * @skb: buffer to operate on + * + * See "DOC: dataref and headerless skbs". */ static inline void __skb_header_release(struct sk_buff *skb) { |