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.

Packet header mbuf

Packet header mbuf

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 their om_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. if om_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.

OS mbuf structure

OS mbuf structure

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.

Packet

Packet

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 initialize

  • ev_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 mbuf

  • leadingspace: 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 mbuf

  • user_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 initialize

  • mp: The memory pool that will hold this mbuf pool

  • buf_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 from

  • leadingspace: 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 of

  • user_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 from

  • off: The offset into the mbuf chain to begin copying from

  • len: The length of the data to copy

  • dst: 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 onto

  • data: The data to append onto the mbuf

  • len: 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 adjust

  • req_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 contiguous

  • len: 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 pack

  • m2: 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.

Public Members

uint16_t omp_len

Overall length of the packet.

uint16_t omp_flags

Flags.

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.

Public Members

struct os_event mq_ev

Event to post when new buffers are available on the queue.