Skip to content

Instantly share code, notes, and snippets.

Last active Aug 29, 2015
What would you like to do?
pbuf vs. netbuf
pbuf -- internal representation of a packet (should not be directly accessed
when using netconn or socket API).
PBUF_POOL -- one struct containing header + data buffer (+ space reserved for
headers) obtained from a pool of limited amount of statically allocated
structs (i.e. slab allocator).
The size of the whole struct is fixed, in case the data are bigger than the
pre-allocated buffer in a struct, multiple pbufs are chained together
This kind of pbuf is mostly used for RX.
PBUF_RAM -- Pbuf allocated dynamically on a heap (internal heap of the lwip).
The advantage is that the exact amount of buffer space is allocated (data +
headers). The disadvantage is that the allocation takes some time (+ general
heap allocation issues like fragmentation etc.)
This kind of pbuf is mostly used for TX.
PBUF_ROM -- Pbuf header is allocated on heap, the payload is stored on some
ROM/Flash device, referenced from the pbuf header.
Used for transmitting statically allocated payloads/data (hard-coded HTML
netbuf -- may contain chain of pbufs. Datatype used when receiving/transmitting
with the netconn API
Reusing pbufs (
> I have a simple application that sends out a UDP packet every few seconds.
> When using the raw API, I created a raw pbuf in ram, filled the payload,
> and then had udp_send() send that same pbuf over and over from my lwip
> task.
This is only valid when you don't have a DMA-enabled MAC. Or in other words you
may only re-use the pbufs (after udp_send returns), when their reference
coutner (p->ref) is 1 (which means noone else is using it). With a DMA-enabled
MAC, the driver calls pbuf_ref (p->ref++) and enqueues the packet for sending,
which means udp_send can return before the packet is sent. If you then pass the
pbuf to udp_send again, the IP and ethernet headers (which are in the same
pbuf!) get changed and the previous packet may get corrupted while sending
through DMA.
> Are netbufs only designed to be used once and then thrown away?
I think they are.
|/----------------\ |
||/-----\ | |
||| Raw | Netconn | BSD sockets |
||\-----/ | |
|\----------------/ |
* non-blocking (does not require thread context -- used without an OS)
* event-driven (callbacks)
* without an OS
* zero-copy
tcp_recv() sets a callback used to receive the data. You must call tcp_recved()
to tell lwip when you have processed the received data.
Netconn API
* sequential blocking API (requires thread context)
* used with an OS
* zero-copy
netconn_recv() returns a netbuf which may contain a chain of pbufs
BSD sockets
* compatible with BSD sockets (surprisingly)
LwIP configuration
include/arch/lwipopts.h: (
user-defined options. Might be overridden by include/lwip/opt.h
| >I want to know why there is need for two files lwipopts.h , opts.h.
| >They look redundant.
| opt.h defines what can be configured and a standard option for this.
| lwipopts.h is for the user to configure the stack. The two file are
| needed because the options are tested using #if LWIP_XXX, which means
| they _must_ exist (in contrast to #ifdef). If opt.h was not included,
| nobody would know all the existing options...
MEM_SIZE -- lwip heap size. Used for allocating PBUF_RAM pbufs.
MEMP_NUM_TCP_PCB -- Each active TCP connection is represented by the TCB structure
in the OS (holding information about IP addresses, ports, sliding window, etc.).
The number of simultaneously active TCP connections.
MEMP_NUM_TCP_PCB_LISTEN -- The number of listening TCP connections.
PBUF_POOL_SIZE -- The number of statically allocated PBUF_POOL pbufs. These are
mostly used for RX.
LWIP_SO_SNDTIMEO -- Enable send timeout for sockets/netconns
LWIP_SO_RCVTIMEO -- Enable receive timeout for sockets/netconns
The maximum segment size (MSS) is a parameter of the TCP protocol that
specifies the largest amount of data, specified in octets, that a computer
or communications device can receive in a single TCP segment. It does not
count the TCP header or the IP header.
For maximum throughput, set this as high as possible for your network
(i.e. 1460 bytes for standard Ethernet).
TCP_WND -- TCP window size.
Do keep in mind that this should be at least twice the size of TCP_MSS.
If memory allows it, set this as high as possible (16-bit, so 0xFFFF is
the highest value), but keep in mind that for every active connection,
the full window may have to be buffered until it is acknowledged by the
remote side.
Further reading
Adam Dunkels, 2001, LwIP Technical Report
old but still *very* valid document describing the LwIP architecture
Atmel Application Note, Using the LwIP network stack
Good explanation of different APIs, pbuf structure, code examples
Official LwIP wiki
Full of annoying ads but still a good source of information
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment