git: ab8a51c45586 - main - mbuf: provide new type for mbuf manipulation - mbuf chain
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 08 Apr 2024 20:29:44 UTC
The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=ab8a51c455863d8c7df6155fae3fe2edd507d100 commit ab8a51c455863d8c7df6155fae3fe2edd507d100 Author: Gleb Smirnoff <glebius@FreeBSD.org> AuthorDate: 2024-04-08 20:16:51 +0000 Commit: Gleb Smirnoff <glebius@FreeBSD.org> CommitDate: 2024-04-08 20:16:51 +0000 mbuf: provide new type for mbuf manipulation - mbuf chain It tracks both the first mbuf and last mbuf, making it handy to use inside functions that are interested in both. It also tracks length of data and memory usage. It can be allocated on stack and passed to an mbuf allocation or another mbuf manipulation function. It can be embedded into some kernel facility internal structure representing most simple data buffer. It uses modern queue(3) based linkage, but is also compatible with old style m_next linkage. Transitioning older code to new type can be done gradually - a code that doesn't understand the chain yet, can be supplied with STAILQ_FIRST(&mc.mc_q). So you can have a mix of old style and new style code in one function as a temporary solution. Reviewed by: markj, tuexen Differential Revision: https://reviews.freebsd.org/D44147 --- sys/sys/mbuf.h | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index b84898fc268e..823b56295c2f 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -1555,6 +1555,10 @@ uint32_t m_infiniband_tcpip_hash(const uint32_t, const struct mbuf *, uint32_t); #define M_PROFILE(m) #endif +/* + * Structure describing a packet queue: mbufs linked by m_stailqpkt. + * Does accounting of number of packets and has a cap. + */ struct mbufq { STAILQ_HEAD(, mbuf) mq_head; int mq_len; @@ -1672,6 +1676,116 @@ mbufq_concat(struct mbufq *mq_dst, struct mbufq *mq_src) mq_src->mq_len = 0; } +/* + * Structure describing a chain of mbufs linked by m_stailq, also tracking + * the pointer to the last. Also does accounting of data length and memory + * usage. + * To be used as an argument to mbuf chain allocation and manipulation KPIs, + * and can be allocated on the stack of a caller. Kernel facilities may use + * it internally as a most simple implementation of a stream data buffer. + */ +struct mchain { + STAILQ_HEAD(, mbuf) mc_q; + u_int mc_len; + u_int mc_mlen; +}; + +#define MCHAIN_INITIALIZER(mc) \ + (struct mchain){ .mc_q = STAILQ_HEAD_INITIALIZER((mc)->mc_q) } + +static inline struct mbuf * +mc_first(struct mchain *mc) +{ + return (STAILQ_FIRST(&mc->mc_q)); +} + +static inline struct mbuf * +mc_last(struct mchain *mc) +{ + return (STAILQ_LAST(&mc->mc_q, mbuf, m_stailq)); +} + +static inline bool +mc_empty(struct mchain *mc) +{ + return (STAILQ_EMPTY(&mc->mc_q)); +} + +/* Account addition of m to mc. */ +static inline void +mc_inc(struct mchain *mc, struct mbuf *m) +{ + mc->mc_len += m->m_len; + mc->mc_mlen += MSIZE; + if (m->m_flags & M_EXT) + mc->mc_mlen += m->m_ext.ext_size; +} + +/* Account removal of m from mc. */ +static inline void +mc_dec(struct mchain *mc, struct mbuf *m) +{ + MPASS(mc->mc_len >= m->m_len); + mc->mc_len -= m->m_len; + MPASS(mc->mc_mlen >= MSIZE); + mc->mc_mlen -= MSIZE; + if (m->m_flags & M_EXT) { + MPASS(mc->mc_mlen >= m->m_ext.ext_size); + mc->mc_mlen -= m->m_ext.ext_size; + } +} + +/* + * Get mchain from a classic mbuf chain linked by m_next. Two hacks here: + * we use the fact that m_next is alias to m_stailq, we use internal queue(3) + * fields. + */ +static inline void +mc_init_m(struct mchain *mc, struct mbuf *m) +{ + struct mbuf *last; + + STAILQ_FIRST(&mc->mc_q) = m; + mc->mc_len = mc->mc_mlen = 0; + STAILQ_FOREACH(m, &mc->mc_q, m_stailq) { + mc_inc(mc, m); + last = m; + } + mc->mc_q.stqh_last = &STAILQ_NEXT(last, m_stailq); +} + +static inline void +mc_freem(struct mchain *mc) +{ + if (!mc_empty(mc)) + m_freem(mc_first(mc)); +} + +static inline void +mc_prepend(struct mchain *mc, struct mbuf *m) +{ + STAILQ_INSERT_HEAD(&mc->mc_q, m, m_stailq); + mc_inc(mc, m); +} + +static inline void +mc_append(struct mchain *mc, struct mbuf *m) +{ + STAILQ_INSERT_TAIL(&mc->mc_q, m, m_stailq); + mc_inc(mc, m); +} + +/* + * Note: STAILQ_REMOVE() is expensive. mc_remove_after() needs to be provided + * as long as there consumers that would benefit from it. + */ +static inline void +mc_remove(struct mchain *mc, struct mbuf *m) +{ + STAILQ_REMOVE(&mc->mc_q, m, mbuf, m_stailq); + mc_dec(mc, m); +} + #ifdef _SYS_TIMESPEC_H_ static inline void mbuf_tstmp2timespec(struct mbuf *m, struct timespec *ts)