Mbufs¶
The mbuf (short for memory buffer) is a common concept in networking stacks. The mbuf is used to hold packet data as it traverses the stack. The mbuf also generally stores header information or other networking stack information that is carried around with the packet. The mbuf and its associated library of functions were developed to make common networking stack operations (like stripping and adding protocol headers) efficient and as copy-free as possible.
In its simplest form, an mbuf is a memory block with some space reserved for internal information and a pointer which is used to “chain” memory blocks together in order to create a “packet”. This is a very important aspect of the mbuf: the ability to chain mbufs together to create larger “packets” (chains of mbufs).
Why use mbufs?¶
The main reason is to conserve memory. Consider a networking protocol that generally sends small packets but occasionally sends large ones. The Bluetooth Low Energy (BLE) protocol is one such example. A flat buffer would need to be sized so that the maximum packet size could be contained by the buffer. With the mbuf, a number of mbufs can be chained together so that the occasional large packet can be handled while leaving more packet buffers available to the networking stack for smaller packets.
Packet Header mbuf¶
Not all mbufs are created equal. The first mbuf in a chain of mbufs is a
special mbuf called a “packet header mbuf”. The reason that this mbuf is
special is that it contains the length of all the data contained by the
chain of mbufs (the packet length, in other words). The packet header
mbuf may also contain a user defined structure (called a “user header”)
so that networking protocol specific information can be conveyed to
various layers of the networking stack. Any mbufs that are part of the
packet (i.e. in the mbuf chain but not the first one) are “normal” (i.e.
non-packet header) mbufs. A normal mbuf does not have any packet header
or user packet header structures in them; they only contain the basic
mbuf header (struct os_mbuf
). Figure 1 illustrates these two types
of mbufs. Note that the numbers/text in parentheses denote the size of
the structures/elements (in bytes) and that MBLEN is the memory block
length of the memory pool used by the mbuf pool.
Normal mbuf¶
Now let’s take a deeper dive into the mbuf structure. Figure 2 illustrates a normal mbuf and breaks out the various fields in the c:type:os_mbuf structure.
The
om_data
field is a pointer to where the data starts inside the data buffer. Typically, mbufs that are allocated from the mbuf pool (discussed later) have theirom_data
pointer set to the start of the data buffer but there are cases where this may not be desirable (added a protocol header to a packet, for example).The
om_flags
field is a set of flags used internally by the mbuf library. Currently, no flags have been defined.The
om_pkthdr_len
field is the total length of all packet headers in the mbuf. For normal mbufs this is set to 0 as there is no packet or user packet headers. For packet header mbufs, this would be set to the length of the packet header structure (16) plus the size of the user packet header (if any). Note that it is this field which differentiates packet header mbufs from normal mbufs (i.e. ifom_pkthdr_len
is zero, this is a normal mbuf; otherwise it is a packet header mbuf).The
om_len
field contains the amount of user data in the data buffer. When initially allocated, this field is 0 as there is no user data in the mbuf.The
omp_pool
field is a pointer to the pool from which this mbuf has been allocated. This is used internally by the mbuf library.The
omp_next
field is a linked list element which is used to chain mbufs.
Figure 2 also shows a normal mbuf with actual values in the os_mbuf
structure. This mbuf starts at address 0x1000 and is 256 bytes in total
length. In this example, the user has copied 33 bytes into the data
buffer starting at address 0x1010 (this is where om_data
points). Note
that the packet header length in this mbuf is 0 as it is not a packet
header mbuf.
Figure 3 illustrates the packet header mbuf along with some chained
mbufs (i.e a “packet”). In this example, the user header structure is
defined to be 8 bytes. Note that in figure 3 we show a number of
different mbufs with varying om_data
pointers and lengths since we
want to show various examples of valid mbufs. For all the mbufs (both
packet header and normal ones) the total length of the memory block is
128 bytes.
Mbuf pools¶
Mbufs are collected into “mbuf pools” much like memory blocks. The mbuf pool itself contains a pointer to a memory pool. The memory blocks in this memory pool are the actual mbufs; both normal and packet header mbufs. Thus, the memory block (and corresponding memory pool) must be sized correctly. In other words, the memory blocks which make up the memory pool used by the mbuf pool must be at least: sizeof(struct os_mbuf) + sizeof(struct os_mbuf_pkthdr) + sizeof(struct user_defined_header) + desired minimum data buffer length. For example, if the developer wants mbufs to contain at least 64 bytes of user data and they have a user header of 12 bytes, the size of the memory block would be (at least): 64 + 12 + 16 + 8, or 100 bytes. Yes, this is a fair amount of overhead. However, the flexibility provided by the mbuf library usually outweighs overhead concerns.
Create mbuf pool¶
Creating an mbuf pool is fairly simple: create a memory pool and then create the mbuf pool using that memory pool. Once the developer has determined the size of the user data needed per mbuf (this is based on the application/networking stack and is outside the scope of this discussion) and the size of the user header (if any), the memory blocks can be sized. In the example shown below, the application requires 64 bytes of user data per mbuf and also allocates a user header (called struct user_hdr). Note that we do not show the user header data structure as there really is no need; all we need to do is to account for it when creating the memory pool. In the example, we use the macro MBUF_PKTHDR_OVERHEAD to denote the amount of packet header overhead per mbuf and MBUF_MEMBLOCK_OVERHEAD to denote the total amount of overhead required per memory block. The macro MBUF_BUF_SIZE is used to denote the amount of payload that the application requires (aligned on a 32-bit boundary in this case). All this leads to the total memory block size required, denoted by the macro MBUF_MEMBLOCK_OVERHEAD.
#define MBUF_PKTHDR_OVERHEAD sizeof(struct os_mbuf_pkthdr) + sizeof(struct user_hdr)
#define MBUF_MEMBLOCK_OVERHEAD sizeof(struct os_mbuf) + MBUF_PKTHDR_OVERHEAD
#define MBUF_NUM_MBUFS (32)
#define MBUF_PAYLOAD_SIZE (64)
#define MBUF_BUF_SIZE OS_ALIGN(MBUF_PAYLOAD_SIZE, 4)
#define MBUF_MEMBLOCK_SIZE (MBUF_BUF_SIZE + MBUF_MEMBLOCK_OVERHEAD)
#define MBUF_MEMPOOL_SIZE OS_MEMPOOL_SIZE(MBUF_NUM_MBUFS, MBUF_MEMBLOCK_SIZE)
struct os_mbuf_pool g_mbuf_pool;
struct os_mempool g_mbuf_mempool;
os_membuf_t g_mbuf_buffer[MBUF_MEMPOOL_SIZE];
void
create_mbuf_pool(void)
{
int rc;
rc = os_mempool_init(&g_mbuf_mempool, MBUF_NUM_MBUFS,
MBUF_MEMBLOCK_SIZE, &g_mbuf_buffer[0], "mbuf_pool");
assert(rc == 0);
rc = os_mbuf_pool_init(&g_mbuf_pool, &g_mbuf_mempool, MBUF_MEMBLOCK_SIZE,
MBUF_NUM_MBUFS);
assert(rc == 0);
}
Msys¶
Msys stands for “system mbufs” and is a set of API built on top of the mbuf code. The basic idea behind msys is the following. The developer can create different size mbuf pools and register them with msys. The application then allocates mbufs using the msys API (as opposed to the mbuf API). The msys code will choose the mbuf pool with the smallest mbufs that can accommodate the requested size.
Let us walk through an example where the user registers three mbuf pools with msys: one with 32 byte mbufs, one with 256 and one with 2048. If the user requests an mbuf with 10 bytes, the 32-byte mbuf pool is used. If the request is for 33 bytes the 256 byte mbuf pool is used. If an mbuf data size is requested that is larger than any of the pools (say, 4000 bytes) the largest pool is used. While this behaviour may not be optimal in all cases that is the currently implemented behaviour. All this means is that the user is not guaranteed that a single mbuf can hold the requested data.
The msys code will not allocate an mbuf from a larger pool if the chosen mbuf pool is empty. Similarly, the msys code will not chain together a number of smaller mbufs to accommodate the requested size. While this behaviour may change in future implementations the current code will simply return NULL. Using the above example, say the user requests 250 bytes. The msys code chooses the appropriate pool (i.e. the 256 byte mbuf pool) and attempts to allocate an mbuf from that pool. If that pool is empty, NULL is returned even though the 32 and 2048 byte pools are not empty.
Note that no added descriptions on how to use the msys API are presented
here (other than in the API descriptions themselves) as the msys API is
used in exactly the same manner as the mbuf API. The only difference is
that mbuf pools are added to msys by calling os_msys_register().
Using mbufs¶
The following examples illustrate typical mbuf usage. There are two
basic mbuf allocation API: c:func:os_mbuf_get() and
os_mbuf_get_pkthdr()
. The first API obtains a normal mbuf whereas
the latter obtains a packet header mbuf. Typically, application
developers use os_mbuf_get_pkthdr()
and rarely, if ever, need to
call os_mbuf_get()
as the rest of the mbuf API (e.g.
os_mbuf_append()
, os_mbuf_copyinto()
, etc.) typically
deal with allocating and chaining mbufs. It is recommended to use the
provided API to copy data into/out of mbuf chains and/or manipulate mbufs.
In example1
, the developer creates a packet and then sends the
packet to a networking interface. The code sample also provides an
example of copying data out of an mbuf as well as use of the “pullup”
api (another very common mbuf api).
void
mbuf_usage_example1(uint8_t *mydata, int mydata_length)
{
int rc;
struct os_mbuf *om;
/* get a packet header mbuf */
om = os_mbuf_get_pkthdr(&g_mbuf_pool, sizeof(struct user_hdr));
if (om) {
/*
* Copy user data into mbuf. NOTE: if mydata_length is greater than the
* mbuf payload size (64 bytes using above example), mbufs are allocated
* and chained together to accommodate the total packet length.
*/
rc = os_mbuf_copyinto(om, 0, mydata, len);
if (rc) {
/* Error! Could not allocate enough mbufs for total packet length */
return -1;
}
/* Send packet to networking interface */
send_pkt(om);
}
}
In example2
we show use of the pullup api as this illustrates some
of the typical pitfalls developers encounter when using mbufs. The first
pitfall is one of alignment/padding. Depending on the processor and/or
compiler, the sizeof() a structure may vary. Thus, the size of
my_protocol_header may be different inside the packet data of the
mbuf than the size of the structure on the stack or as a global
variable, for instance. While some networking protcols may align
protocol information on convenient processor boundaries many others try
to conserve bytes “on the air” (i.e inside the packet data). Typical
methods used to deal with this are “packing” the structure (i.e. force
compiler to not pad) or creating protocol headers that do not require
padding. example2
assumes that one of these methods was used when
defining the my_protocol_header structure.
Another common pitfall occurs around endianness. A network protocol may
be little endian or big endian; it all depends on the protocol
specification. Processors also have an endianness; this means that the
developer has to be careful that the processor endianness and the
protocol endianness are handled correctly. In example2
, some common
networking functions are used: ntohs()
and ntohl()
. These are
shorthand for “network order to host order, short” and “network order to
host order, long”. Basically, these functions convert data of a certain
size (i.e. 16 bits, 32 bits, etc) to the endianness of the host. Network
byte order is big-endian (most significant byte first), so these
functions convert big-endian byte order to host order (thus, the
implementation of these functions is host dependent). Note that the BLE
networking stack “on the air” format is least signigicant byte first
(i.e. little endian), so a “bletoh” function would have to take little
endian format and convert to host format.
A long story short: the developer must take care when copying structure data to/from mbufs and flat buffers!
A final note: these examples assume the same mbuf struture and definitions used in the first example.
void
mbuf_usage_example2(struct mbuf *rxpkt)
{
int rc;
uint8_t packet_data[16];
struct mbuf *om;
struct my_protocol_header *phdr;
/* Make sure that "my_protocol_header" bytes are contiguous in mbuf */
om = os_mbuf_pullup(&g_mbuf_pool, sizeof(struct my_protocol_header));
if (!om) {
/* Not able to pull up data into contiguous area */
return -1;
}
/*
* Get the protocol information from the packet. In this example we presume that we
* are interested in protocol types that are equal to MY_PROTOCOL_TYPE, are not zero
* length, and have had some time in flight.
*/
phdr = OS_MBUF_DATA(om, struct my_protocol_header *);
type = ntohs(phdr->prot_type);
length = ntohs(phdr->prot_length);
time_in_flight = ntohl(phdr->prot_tif);
if ((type == MY_PROTOCOL_TYPE) && (length > 0) && (time_in_flight > 0)) {
rc = os_mbuf_copydata(rxpkt, sizeof(struct my_protocol_header), 16, packet_data);
if (!rc) {
/* Success! Perform operations on packet data */
<... user code here ...>
}
}
/* Free passed in packet (mbuf chain) since we don't need it anymore */
os_mbuf_free_chain(om);
}
Mqueue¶
The mqueue construct allows a task to wake up when it receives data. Typically, this data is in the form of packets received over a network. A common networking stack operation is to put a packet on a queue and post an event to the task monitoring that queue. When the task handles the event, it processes each packet on the packet queue.
Using Mqueue¶
The following code sample demonstrates how to use an mqueue. In this example:
packets are put on a receive queue
a task processes each packet on the queue (increments a receive counter)
Not shown in the code example is a call my_task_rx_data_func
.
Presumably, some other code will call this API.
uint32_t pkts_rxd;
struct os_mqueue rxpkt_q;
struct os_eventq my_task_evq;
/**
* Removes each packet from the receive queue and processes it.
*/
void
process_rx_data_queue(void)
{
struct os_mbuf *om;
while ((om = os_mqueue_get(&rxpkt_q)) != NULL) {
++pkts_rxd;
os_mbuf_free_chain(om);
}
}
/**
* Called when a packet is received.
*/
int
my_task_rx_data_func(struct os_mbuf *om)
{
int rc;
/* Enqueue the received packet and wake up the listening task. */
rc = os_mqueue_put(&rxpkt_q, &my_task_evq, om);
if (rc != 0) {
return -1;
}
return 0;
}
void
my_task_handler(void *arg)
{
struct os_event *ev;
struct os_callout_func *cf;
int rc;
/* Initialize eventq */
os_eventq_init(&my_task_evq);
/* Initialize mqueue */
os_mqueue_init(&rxpkt_q, NULL);
/* Process each event posted to our eventq. When there are no events to
* process, sleep until one arrives.
*/
while (1) {
os_eventq_run(&my_task_evq);
}
}
API¶
-
int
os_mqueue_init
(struct os_mqueue *mq, os_event_fn *ev_cb, void *arg)¶ Initializes an mqueue.
An mqueue is a queue of mbufs that ties to a particular task’s event queue. Mqueues form a helper API around a common paradigm: wait on an event queue until at least one packet is available, then process a queue of packets.
When mbufs are available on the queue, an event OS_EVENT_T_MQUEUE_DATA will be posted to the task’s mbuf queue.
- Return
0 on success, non-zero on failure.
- Parameters
mq
: The mqueue to initializeev_cb
: The callback to associate with the mqeueue event. Typically, this callback pulls each packet off the mqueue and processes them.arg
: The argument to associate with the mqueue event.
-
struct os_mbuf *
os_mqueue_get
(struct os_mqueue *mq)¶ Remove and return a single mbuf from the mbuf queue.
Does not block.
- Return
The next mbuf in the queue; NULL if queue has no mbufs.
- Parameters
mq
: The mbuf queue to pull an element off of.
-
int
os_mqueue_put
(struct os_mqueue *mq, struct os_eventq *evq, struct os_mbuf *om)¶ Adds a packet (i.e.
packet header mbuf) to an mqueue. The event associated with the mqueue gets posted to the specified eventq.
- Return
0 on success, non-zero on failure.
- Parameters
mq
: The mbuf queue to append the mbuf to.evq
: The event queue to post an event to.om
: The mbuf to append to the mbuf queue.
-
int
os_msys_register
(struct os_mbuf_pool *new_pool)¶ MSYS is a system level mbuf registry.
Allows the system to share packet buffers amongst the various networking stacks that can be running simultaeneously.
Mbuf pools are created in the system initialization code, and then when a mbuf is allocated out of msys, it will try and find the best fit based upon estimated mbuf size.
os_msys_register() registers a mbuf pool with MSYS, and allows MSYS to allocate mbufs out of it.
- Return
0 on success; non-zero on failure
- Parameters
new_pool
: The pool to register with MSYS
-
struct os_mbuf *
os_msys_get
(uint16_t dsize, uint16_t leadingspace)¶ Allocate a mbuf from msys.
Based upon the data size requested, os_msys_get() will choose the mbuf pool that has the best fit.
- Return
A freshly allocated mbuf on success; NULL on failure.
- Parameters
dsize
: The estimated size of the data being stored in the mbufleadingspace
: The amount of leadingspace to allocate in the mbuf
-
void
os_msys_reset
(void)¶ De-registers all mbuf pools from msys.
-
struct os_mbuf *
os_msys_get_pkthdr
(uint16_t dsize, uint16_t user_hdr_len)¶ Allocate a packet header structure from the MSYS pool.
See os_msys_register() for a description of MSYS.
- Return
A freshly allocated mbuf on success; NULL on failure.
- Parameters
dsize
: The estimated size of the data being stored in the mbufuser_hdr_len
: The length to allocate for the packet header structure
-
int
os_msys_count
(void)¶ Count the number of blocks in all the mbuf pools that are allocated.
- Return
total number of blocks allocated in Msys
-
int
os_msys_num_free
(void)¶ Return the number of free blocks in Msys.
- Return
Number of free blocks available in Msys
-
int
os_mbuf_pool_init
(struct os_mbuf_pool *omp, struct os_mempool *mp, uint16_t buf_len, uint16_t nbufs)¶ Initialize a pool of mbufs.
- Return
0 on success; error code on failure.
- Parameters
omp
: The mbuf pool to initializemp
: The memory pool that will hold this mbuf poolbuf_len
: The length of the buffer itself.nbufs
: The number of buffers in the pool
-
struct os_mbuf *
os_mbuf_get
(struct os_mbuf_pool *omp, uint16_t leadingspace)¶ Get an mbuf from the mbuf pool.
The mbuf is allocated, and initialized prior to being returned.
- Return
An initialized mbuf on success; NULL on failure.
- Parameters
omp
: The mbuf pool to return the packet fromleadingspace
: The amount of leadingspace to put before the data section by default.
-
struct os_mbuf *
os_mbuf_get_pkthdr
(struct os_mbuf_pool *omp, uint8_t user_pkthdr_len)¶ Allocate a new packet header mbuf out of the os_mbuf_pool.
- Return
A freshly allocated mbuf on success; NULL on failure.
- Parameters
omp
: The mbuf pool to allocate out ofuser_pkthdr_len
: The packet header length to reserve for the caller.
-
struct os_mbuf *
os_mbuf_dup
(struct os_mbuf *om)¶ Duplicate a chain of mbufs.
Return the start of the duplicated chain.
- Return
A pointer to the new chain of mbufs
- Parameters
om
: The mbuf chain to duplicate
-
struct os_mbuf *
os_mbuf_off
(const struct os_mbuf *om, int off, uint16_t *out_off)¶ Locates the specified absolute offset within an mbuf chain.
The offset can be one past than the total length of the chain, but no greater.
- Return
The mbuf containing the specified offset on success. NULL if the specified offset is out of bounds.
- Parameters
om
: The start of the mbuf chain to seek within.off
: The absolute address to find.out_off
: On success, this points to the relative offset within the returned mbuf.
-
int
os_mbuf_copydata
(const struct os_mbuf *om, int off, int len, void *dst)¶ Copy data from an mbuf chain starting “off” bytes from the beginning, continuing for “len” bytes, into the indicated buffer.
- Return
0 on success; -1 if the mbuf does not contain enough data.
- Parameters
om
: The mbuf chain to copy fromoff
: The offset into the mbuf chain to begin copying fromlen
: The length of the data to copydst
: The destination buffer to copy into
-
uint16_t
os_mbuf_len
(const struct os_mbuf *om)¶ Calculates the length of an mbuf chain.
Calculates the length of an mbuf chain. If the mbuf contains a packet header, you should use
OS_MBUF_PKTLEN()
as a more efficient alternative to this function.- Return
The length, in bytes, of the provided mbuf chain.
- Parameters
om
: The mbuf to measure.
-
int
os_mbuf_append
(struct os_mbuf *om, const void *data, uint16_t len)¶ Append data onto a mbuf.
- Return
0 on success; an error code on failure
- Parameters
om
: The mbuf to append the data ontodata
: The data to append onto the mbuflen
: The length of the data to append
-
int
os_mbuf_appendfrom
(struct os_mbuf *dst, const struct os_mbuf *src, uint16_t src_off, uint16_t len)¶ Reads data from one mbuf and appends it to another.
On error, the specified data range may be partially appended. Neither mbuf is required to contain an mbuf packet header.
- Return
0 on success; OS_EINVAL if the specified range extends beyond the end of the source mbuf chain.
- Parameters
dst
: The mbuf to append to.src
: The mbuf to copy data from.src_off
: The absolute offset within the source mbuf chain to read from.len
: The number of bytes to append.
-
int
os_mbuf_free
(struct os_mbuf *om)¶ Release a mbuf back to the pool.
- Return
0 on success; -1 on failure
- Parameters
om
: The Mbuf to release back to the pool
-
int
os_mbuf_free_chain
(struct os_mbuf *om)¶ Free a chain of mbufs.
- Return
0 on success; -1 on failure
- Parameters
om
: The starting mbuf of the chain to free back into the pool
-
void
os_mbuf_adj
(struct os_mbuf *om, int req_len)¶ Adjust the length of a mbuf, trimming either from the head or the tail of the mbuf.
- Parameters
om
: The mbuf chain to adjustreq_len
: The length to trim from the mbuf. If positive, trims from the head of the mbuf, if negative, trims from the tail of the mbuf.
-
int
os_mbuf_cmpf
(const struct os_mbuf *om, int off, const void *data, int len)¶ Performs a memory compare of the specified region of an mbuf chain against a flat buffer.
- Return
0 if both memory regions are identical; A memcmp return code if there is a mismatch; INT_MAX if the mbuf is too short.
- Parameters
om
: The start of the mbuf chain to compare.off
: The offset within the mbuf chain to start the comparison.data
: The flat buffer to compare.len
: The length of the flat buffer.
-
int
os_mbuf_cmpm
(const struct os_mbuf *om1, uint16_t offset1, const struct os_mbuf *om2, uint16_t offset2, uint16_t len)¶ Compares the contents of two mbuf chains.
The ranges of the two chains to be compared are specified via the two offset parameters and the len parameter. Neither mbuf chain is required to contain a packet header.
- Return
0 if both mbuf segments are identical; A memcmp() return code if the segment contents differ; INT_MAX if a specified range extends beyond the end of its corresponding mbuf chain.
- Parameters
om1
: The first mbuf chain to compare.offset1
: The absolute offset within om1 at which to start the comparison.om2
: The second mbuf chain to compare.offset2
: The absolute offset within om2 at which to start the comparison.len
: The number of bytes to compare.
-
struct os_mbuf *
os_mbuf_prepend
(struct os_mbuf *om, int len)¶ Increases the length of an mbuf chain by adding data to the front.
If there is insufficient room in the leading mbuf, additional mbufs are allocated and prepended as necessary. If this function fails to allocate an mbuf, the entire chain is freed.
The specified mbuf chain does not need to contain a packet header.
- Return
The new head of the chain on success; NULL on failure.
- Parameters
om
: The head of the mbuf chain.len
: The number of bytes to prepend.
-
struct os_mbuf *
os_mbuf_prepend_pullup
(struct os_mbuf *om, uint16_t len)¶ Prepends a chunk of empty data to the specified mbuf chain and ensures the chunk is contiguous.
If either operation fails, the specified mbuf chain is freed and NULL is returned.
- Return
The modified mbuf on success; NULL on failure (and the mbuf chain is freed).
- Parameters
om
: The mbuf chain to prepend to.len
: The number of bytes to prepend and pullup.
-
int
os_mbuf_copyinto
(struct os_mbuf *om, int off, const void *src, int len)¶ Copies the contents of a flat buffer into an mbuf chain, starting at the specified destination offset.
If the mbuf is too small for the source data, it is extended as necessary. If the destination mbuf contains a packet header, the header length is updated.
- Return
0 on success; nonzero on failure.
- Parameters
om
: The mbuf chain to copy into.off
: The offset within the chain to copy to.src
: The source buffer to copy from.len
: The number of bytes to copy.
-
void
os_mbuf_concat
(struct os_mbuf *first, struct os_mbuf *second)¶ Attaches a second mbuf chain onto the end of the first.
If the first chain contains a packet header, the header’s length is updated. If the second chain has a packet header, its header is cleared.
- Parameters
first
: The mbuf chain being attached to.second
: The mbuf chain that gets attached.
-
void *
os_mbuf_extend
(struct os_mbuf *om, uint16_t len)¶ Increases the length of an mbuf chain by the specified amount.
If there is not sufficient room in the last buffer, a new buffer is allocated and appended to the chain. It is an error to request more data than can fit in a single buffer.
- Return
A pointer to the new data on success; NULL on failure.
- Parameters
om
: The head of the chain to extend.len
: The number of bytes to extend by.
-
struct os_mbuf *
os_mbuf_pullup
(struct os_mbuf *om, uint16_t len)¶ Rearrange a mbuf chain so that len bytes are contiguous, and in the data area of an mbuf (so that OS_MBUF_DATA() will work on a structure of size len.) Returns the resulting mbuf chain on success, free’s it and returns NULL on failure.
If there is room, it will add up to “max_protohdr - len” extra bytes to the contiguous region, in an attempt to avoid being called next time.
- Return
The contiguous mbuf chain on success; NULL on failure.
- Parameters
om
: The mbuf chain to make contiguouslen
: The number of bytes in the chain to make contiguous
-
struct os_mbuf *
os_mbuf_trim_front
(struct os_mbuf *om)¶ Removes and frees empty mbufs from the front of a chain.
If the chain contains a packet header, it is preserved.
- Return
The head of the trimmed mbuf chain.
- Parameters
om
: The mbuf chain to trim.
-
int
os_mbuf_widen
(struct os_mbuf *om, uint16_t off, uint16_t len)¶ Increases the length of an mbuf chain by inserting a gap at the specified offset.
The contents of the gap are indeterminate. If the mbuf chain contains a packet header, its total length is increased accordingly.
This function never frees the provided mbuf chain.
- Return
0 on success; SYS_[…] error code on failure.
- Parameters
om
: The mbuf chain to widen.off
: The offset at which to insert the gap.len
: The size of the gap to insert.
-
struct os_mbuf *
os_mbuf_pack_chains
(struct os_mbuf *m1, struct os_mbuf *m2)¶ Creates a single chained mbuf from m1 and m2 utilizing all the available buffer space in all mbufs in the resulting chain.
In other words, ensures there is no leading space in any mbuf in the resulting chain and trailing space only in the last mbuf in the chain. Mbufs from either chain may be freed if not needed. No mbufs are allocated. Note that mbufs from m2 are added to the end of m1. If m1 has a packet header, it is retained and length updated. If m2 has a packet header it is discarded. If m1 is NULL, NULL is returned and m2 is left untouched.
- Return
Pointer to resulting mbuf chain
- Parameters
m1
: Pointer to first mbuf chain to packm2
: Pointer to second mbuf chain to pack
-
OS_MBUF_F_MASK
(__n)¶ Given a flag number, provide the mask for it.
- Parameters
__n
: The number of the flag in the mask
-
OS_MBUF_IS_PKTHDR
(__om)¶ Checks whether a given mbuf is a packet header mbuf.
- Parameters
__om
: The mbuf to check
-
OS_MBUF_PKTHDR
(__om)¶ Get a packet header pointer given an mbuf pointer.
-
OS_MBUF_PKTHDR_TO_MBUF
(__hdr)¶ Given a mbuf packet header pointer, return a pointer to the mbuf.
-
OS_MBUF_PKTLEN
(__om)¶ Gets the length of an entire mbuf chain.
The specified mbuf must have a packet header.
-
OS_MBUF_DATA
(__om, __type)¶ Access the data of a mbuf, and cast it to type.
- Parameters
__om
: The mbuf to access, and cast__type
: The type to cast it to
-
OS_MBUF_USRHDR
(om)¶ Access the “user header” in the head of an mbuf chain.
- Parameters
om
: Pointer to the head of an mbuf chain.
-
OS_MBUF_USRHDR_LEN
(om)¶ Retrieves the length of the user header in an mbuf.
- Parameters
om
: Pointer to the mbuf to query.
-
OS_MBUF_LEADINGSPACE
(__om)¶ Returns the leading space (space at the beginning) of the mbuf.
Works on both packet header, and regular mbufs, as it accounts for the additional space allocated to the packet header.
- Return
Amount of leading space available in the mbuf
- Parameters
__om
: The mbuf in that pool to get the leading space for
-
OS_MBUF_TRAILINGSPACE
(__om)¶ Returns the trailing space (space at the end) of the mbuf.
Works on both packet header and regular mbufs.
- Return
Amount of trailing space available in the mbuf
- Parameters
__om
: The mbuf in that pool to get the trailing space for
-
struct
os_mbuf_pool
¶ - #include <os_mbuf.h>
A mbuf pool from which to allocate mbufs.
This contains a pointer to the os mempool to allocate mbufs out of, the total number of elements in the pool, and the amount of “user” data in a non-packet header mbuf. The total pool size, in bytes, should be: os_mbuf_count * (omp_databuf_len + sizeof(struct os_mbuf))
Public Functions
-
STAILQ_ENTRY (os_mbuf_pool) omp_next
Next mbuf pool in the list.
Public Members
-
uint16_t
omp_databuf_len
¶ Total length of the databuf in each mbuf.
This is the size of the mempool block, minus the mbuf header
-
struct os_mempool *
omp_pool
¶ The memory pool which to allocate mbufs out of.
-
-
struct
os_mbuf_pkthdr
¶ - #include <os_mbuf.h>
A packet header structure that preceeds the mbuf packet headers.
Public Functions
-
STAILQ_ENTRY (os_mbuf_pkthdr) omp_next
Next mbuf packet header in the list.
-
-
struct
os_mbuf
¶ - #include <os_mbuf.h>
Chained memory buffer.
Public Functions
-
SLIST_ENTRY (os_mbuf) om_next
Next mbuf in the list.
Public Members
-
uint8_t *
om_data
¶ Current pointer to data in the structure.
-
uint8_t
om_flags
¶ Flags associated with this buffer, see OS_MBUF_F_* defintions.
-
uint8_t
om_pkthdr_len
¶ Length of packet header.
-
uint16_t
om_len
¶ Length of data in this buffer.
-
struct os_mbuf_pool *
om_omp
¶ The mbuf pool this mbuf was allocated out of.
-
uint8_t
om_databuf
[0]¶ Pointer to the beginning of the data, after this buffer.
-
-
struct
os_mqueue
¶ - #include <os_mbuf.h>
Structure representing a queue of mbufs.
Public Functions
-
STAILQ_HEAD (, os_mbuf_pkthdr) mq_head
A queue of mbuf packet headers.
-