When attaching a mbuf, indirect mbuf has to point to start of buffer of direct mbuf. By adding buf_off field to rte_mbuf, this becomes more flexible. Indirect mbuf can point to any part of direct mbuf by calling rte_pktmbuf_attach_at().
Possible use-cases could be: - If a packet has multiple layers of encapsulation, multiple indirect buffers can reference different layers of the encapsulated packet. - A large direct mbuf can even contain multiple packets in series and each packet can be referenced by multiple mbuf indirections. Signed-off-by: Yongseok Koh <ys...@mellanox.com> --- lib/librte_mbuf/rte_mbuf.h | 158 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 157 insertions(+), 1 deletion(-) diff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h index 62740254d..053db32d0 100644 --- a/lib/librte_mbuf/rte_mbuf.h +++ b/lib/librte_mbuf/rte_mbuf.h @@ -559,6 +559,11 @@ struct rte_mbuf { }; }; + /** Buffer offset of direct mbuf if attached. Indirect mbuf can point to + * any part of direct mbuf. + */ + uint16_t buf_off; + /** Size of the application private data. In case of an indirect * mbuf, it stores the direct mbuf private data size. */ uint16_t priv_size; @@ -671,7 +676,9 @@ rte_mbuf_data_dma_addr_default(const struct rte_mbuf *mb) static inline struct rte_mbuf * rte_mbuf_from_indirect(struct rte_mbuf *mi) { - return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) + mi->priv_size); + return (struct rte_mbuf *) + RTE_PTR_SUB(mi->buf_addr, + sizeof(*mi) + mi->priv_size + mi->buf_off); } /** @@ -1281,6 +1288,98 @@ static inline int rte_pktmbuf_alloc_bulk(struct rte_mempool *pool, } /** + * Adjust tailroom of indirect mbuf. If offset is positive, enlarge the + * tailroom of the mbuf. If negative, shrink the tailroom. + * + * If length is out of range, then the function will fail and return -1, + * without modifying the indirect mbuf. + * + * @param mi + * The indirect packet mbuf. + * @param len + * The amount of length to adjust (in bytes). + * @return + * - 0: On success. + * - -1: On error. + */ +static inline int rte_pktmbuf_adj_indirect_tail(struct rte_mbuf *mi, int len) +{ + struct rte_mbuf *md; + uint16_t tailroom; + int delta; + + RTE_ASSERT(RTE_MBUF_INDIRECT(mi)); + + md = rte_mbuf_from_indirect(mi); + if (unlikely(mi->buf_len + len <= 0 || + mi->buf_off + mi->buf_len + len >= md->buf_len)) + return -1; + + mi->buf_len += len; + + tailroom = mi->buf_len - mi->data_off - mi->data_len; + delta = tailroom + len; + if (delta > 0) { + /* Adjust tailroom */ + delta = 0; + } else if (delta + mi->data_len < 0) { + /* No data */ + mi->data_off += delta + mi->data_len; + delta = mi->data_len; + } + mi->data_len += delta; + mi->pkt_len += delta; + return 0; +} + +/** + * Shift buffer reference of indirect mbuf. If offset is positive, push + * the offset of the mbuf. If negative, pull the offset. + * + * Returns a pointer to the start address of the new data area. If offset + * is out of range, then the function will fail and return NULL, without + * modifying the indirect mbuf. + * + * @param mi + * The indirect packet mbuf. + * @param off + * The amount of offset to adjust (in bytes). + * @return + * A pointer to the new start of the data. + */ +static inline char *rte_pktmbuf_adj_indirect_head(struct rte_mbuf *mi, int off) +{ + int delta; + + RTE_ASSERT(RTE_MBUF_INDIRECT(mi)); + + if (unlikely(off >= mi->buf_len || mi->buf_off + off < 0)) + return NULL; + + mi->buf_iova += off; + mi->buf_addr = (char *)mi->buf_addr + off; + mi->buf_len -= off; + mi->buf_off += off; + + delta = off - mi->data_off; + if (delta < 0) { + /* Adjust headroom */ + mi->data_off -= off; + delta = 0; + } else if (delta < mi->data_len) { + /* No headroom */ + mi->data_off = 0; + } else { + /* No data */ + mi->data_off = 0; + delta = mi->data_len; + } + mi->data_len -= delta; + mi->pkt_len -= delta; + return (char *)mi->buf_addr + mi->data_off; +} + +/** * Attach packet mbuf to another packet mbuf. * * After attachment we refer the mbuf we attached as 'indirect', @@ -1315,6 +1414,7 @@ static inline void rte_pktmbuf_attach(struct rte_mbuf *mi, struct rte_mbuf *m) mi->buf_iova = m->buf_iova; mi->buf_addr = m->buf_addr; mi->buf_len = m->buf_len; + mi->buf_off = 0; mi->data_off = m->data_off; mi->data_len = m->data_len; @@ -1336,6 +1436,62 @@ static inline void rte_pktmbuf_attach(struct rte_mbuf *mi, struct rte_mbuf *m) } /** + * Attach packet mbuf to another packet mbuf pointing by given offset. + * + * After attachment we refer the mbuf we attached as 'indirect', + * while mbuf we attached to as 'direct'. + * + * The indirect mbuf can reference to anywhere in the buffer of the direct + * mbuf by the given offset. And the indirect mbuf is also be trimmed by + * the given buffer length. + * + * As a result, if a direct mbuf has multiple layers of encapsulation, + * multiple indirect buffers can reference different layers of the packet. + * Or, a large direct mbuf can even contain multiple packets in series and + * each packet can be referenced by multiple mbuf indirections. + * + * Returns a pointer to the start address of the new data area. If offset + * or buffer length is out of range, then the function will fail and return + * NULL, without attaching the mbuf. + * + * @param mi + * The indirect packet mbuf. + * @param m + * The packet mbuf we're attaching to. + * @param off + * The amount of offset to push (in bytes). + * @param buf_len + * The buffer length of the indirect mbuf (in bytes). + * @return + * A pointer to the new start of the data. + */ +static inline char *rte_pktmbuf_attach_at(struct rte_mbuf *mi, + struct rte_mbuf *m, uint16_t off, uint16_t buf_len) +{ + struct rte_mbuf *md; + char *ret; + + if (RTE_MBUF_DIRECT(m)) + md = m; + else + md = rte_mbuf_from_indirect(m); + + if (off + buf_len > md->buf_len) + return NULL; + + rte_pktmbuf_attach(mi, m); + + /* Push reference of indirect mbuf */ + ret = rte_pktmbuf_adj_indirect_head(mi, off); + RTE_ASSERT(ret != NULL); + + /* Trim reference of indirect mbuf */ + rte_pktmbuf_adj_indirect_tail(mi, off + buf_len - md->buf_len); + + return ret; +} + +/** * Detach an indirect packet mbuf. * * - restore original mbuf address and length values. -- 2.11.0