Fact-checked by Grok 2 weeks ago

lwIP

lwIP (lightweight IP) is a small, open-source implementation of the protocol suite tailored for resource-constrained embedded systems, enabling efficient networking with minimal memory and code footprint. Originally developed by Adam Dunkels at the Swedish Institute of in 2001, lwIP focuses on reducing RAM requirements to tens of kilobytes and ROM usage to around 40 kilobytes while supporting a full-scale implementation, making it ideal for devices like microcontrollers with limited resources. The stack provides core protocols including IPv4, , , , ICMP, , IGMP, PPPoE, and PPPoS, along with features such as DHCP and DNS clients, IP forwarding, and . It offers flexible , including a for low-level access and a sockets-compatible , and can operate with or without an underlying operating system through an optional layer. Since its initial release, lwIP has been maintained by a global team of developers under the modified BSD license and is widely adopted in commercial and open-source applications, with the latest stable version being 2.2.1 as of February 2025. Add-on modules extend its capabilities to include HTTP and servers, clients, and SNMP agents, further enhancing its utility in and networked devices.

Introduction

Overview

lwIP is an open-source implementation of the / protocol suite designed specifically for resource-constrained environments, such as systems with limited memory. It provides a lightweight alternative to full-featured / stacks, focusing on minimal resource usage while supporting essential networking functionalities like and . The stack is tailored for microcontrollers and similar devices that typically have only tens of kilobytes of available and around 40 kilobytes of for code storage, making it suitable for applications where heavier implementations, such as those in , would exceed limitations. Primary use cases include devices, () applications, and real-time systems requiring efficient network connectivity without compromising performance or memory footprint. lwIP is licensed under a BSD license, permitting free use, modification, and distribution in both commercial and open-source projects. Starting with version 2.0.0, it includes dual-stack support for both IPv4 and protocols, enabling flexible network configurations in modern applications.

Key Features

lwIP's modular architecture enables developers to selectively include or exclude specific protocols and features during compilation, thereby minimizing the code footprint and resource consumption to suit the constraints of applications. This configurability is achieved through the lwipopts.h header file, where options such as LWIP_TCP, LWIP_UDP, and LWIP_IPV6 can be defined or undefined to enable only the necessary components, resulting in a highly customizable stack that can range from a few kilobytes for basic / functionality to a full-featured implementation. The stack employs an event-driven, non-blocking design optimized for single-threaded operation in resource-limited systems, where the core runs in a single context without relying on a multi-threaded operating system. This approach uses callbacks invoked from handlers or a main loop to process network events, ensuring low and efficient CPU utilization without blocking the application , as detailed in the raw API documentation. Such a design is particularly advantageous for bare-metal environments, allowing lwIP to integrate seamlessly into systems with minimal overhead. lwIP provides support for both IPv4 and protocols in a dual-stack configuration, enabling simultaneous operation of both address families on the same network interface, with IPv6 support added starting in version 1.4.0 (2011) and full dual-stack maturity achieved in release 2.0.0 (2016). This dual-stack approach facilitates gradual migration to IPv6 while maintaining with IPv4 networks, and it includes features like neighbor discovery () for IPv6 and address autoconfiguration. Additionally, basic capabilities are provided through netif filters, such as IGMP and MLD MAC filters, which allow applications to implement packet filtering at the network level to control traffic and enforce simple access policies. The stack's high portability across diverse hardware platforms stems from its abstraction layers for system calls and hardware drivers, making it adaptable to various microcontrollers and RTOSes without requiring management. Notably, lwIP supports operation on no-MMU systems, common in low-end devices, by relying on static memory allocation and avoiding dynamic pointer manipulations that depend on units. This design ensures compatibility with a wide range of architectures, from 8-bit to 32-bit processors, as evidenced by its integration in numerous vendor SDKs.

History

Development Origins

lwIP was created in 2001 by Adam Dunkels at the Swedish Institute of Computer Science (SICS) as part of research into lightweight operating systems for resource-constrained devices, including the early development of Contiki OS. This work emerged from Dunkels' master's thesis project in 2001, which explored the design and implementation of a lightweight stack for applications like monitoring athletes, highlighting the need for efficient implementations on tiny hardware. The primary motivation behind lwIP was to address the absence of compact / protocol stacks suitable for 8-bit and 16-bit microcontrollers, which dominated systems but lacked support for standard protocols due to high and demands of traditional implementations. Inspired by the growing demand for networked sensors in areas such as and ad-hoc networks, Dunkels designed lwIP to minimize code size (around 10 KB) and RAM usage (as low as a few hundred bytes), enabling full / functionality—including , ICMP, , and —on systems with severely limited resources. The initial prototype emphasized minimalism, prioritizing for its simplicity in demultiplexing and low-overhead over the more resource-intensive , which constitutes about half of lwIP's code due to features like congestion control and reliable byte streams. By late 2002, lwIP transitioned from a SICS research project to an independent open-source initiative under the lwIP developers group, hosted on Savannah and maintained by a global community of contributors. This shift allowed broader adoption while preserving its core focus on networking efficiency.

Release Milestones

The initial public release of lwIP, version 1.0.0, occurred on August 10, 2004, providing core support for TCP/IPv4 protocols including , , ICMP, and , tailored for resource-constrained systems. Subsequent key upgrades expanded protocol capabilities and performance. Version 1.3.0, released in March 2008, introduced basic support through new modules for IPv6 addressing, , and neighbor discovery, though limited to single-stack operation without full IPv4 integration. Version 2.0.0, released on November 10, 2016, marked a significant advancement by enabling full dual-stack IPv4/IPv6 operation, with unified IP address structures (ip_addr_t as a ) and automatic handling in , , and APIs to support concurrent IPv4 and IPv6 traffic. Building on this, version 2.1.0, released on September 26, 2018, enhanced performance through the new , which allows layering abstractions like TLS for secure connections while optimizing memory and callback efficiency, alongside refinements to IPv6 and socket stability. Version 2.2.0, released on September 25, 2023, added features including full support for Address Conflict Detection (ACD) and various bug fixes. The latest stable release, version 2.2.1, was issued on February 6, 2025, primarily as a update addressing critical bug fixes, including issues in modules and security vulnerabilities in protocol handling. lwIP follows a community-driven model hosted on the GNU Savannah platform, where releases occur irregularly in response to contributor patches, bug reports, and feature proposals, ensuring ongoing compatibility and minimal footprint for embedded applications.

Architecture

Core Components

The core components of lwIP form the foundational structures and processing pathways that enable its lightweight TCP/IP implementation for embedded systems. Central to this design is the network interface abstraction, represented by the netif structure, which provides a unified layer for interacting with diverse hardware drivers. This abstraction handles packet input and output (I/O) by defining callbacks such as netif_input_fn for delivering incoming packets from the driver to the stack, and output functions like netif->output for transmitting packets to the physical medium. Hardware drivers register with lwIP by initializing a netif instance via netif_add(), specifying IP addresses, netmasks, and gateways, while flags like NETIF_FLAG_ETHARP ensure proper routing to layers such as Ethernet or IP. This modular approach allows lwIP to support multiple interfaces, including loopback and PPP, without tight coupling to specific hardware. Protocol control blocks (PCBs) serve as the primary data structures for managing and connections, encapsulating state information for active sessions. For , the tcp_pcb structure tracks connection details including local and remote addresses, ports, sequence numbers, and congestion control parameters, created via tcp_new() and transitioned through states like CLOSED, LISTEN, and ESTABLISHED. employs the udp_pcb structure for datagram-oriented communication, handling binding to local ports with udp_bind() and connection setup via udp_connect(), without maintaining persistent state like . At the level, the ip_pcb structure supports raw handling for custom protocols, including socket options and address bindings, enabling direct manipulation of IP headers for specialized applications. These PCBs are dynamically allocated from memory pools and deallocated upon connection closure to conserve resources. Incoming packet processing follows a chained sequence of functions to demultiplex and validate data efficiently. The ip_input() function receives a packet buffer (pbuf) and associated netif from the driver, parses the to determine the (e.g., or ), performs routing checks based on addresses and , and forwards valid packets to upper layers or discards invalids, returning an err_t status. For segments, tcp_input() extends this by verifying the header, searching matching tcp_pcb instances using source/destination ports and addresses, and invoking tcp_process() to advance the , handling acknowledgments, retransmissions, and data delivery. These processing chains run in a dedicated TCP/IP thread when OS abstractions are used (NO_SYS=0), or directly from the main loop or context in no-OS mode (NO_SYS=1), helping to minimize overhead while ensuring proper concurrency handling. lwIP's event callback system facilitates asynchronous notifications to applications without blocking the stack, primarily through the raw API. Applications register callback functions—such as tcp_recv() for incoming , tcp_sent() for transmission completion, and tcp_err() for errors—associated with PCBs, allowing the stack to invoke them during event occurrences like arrival or establishment. This callback-driven model, often using err_t return types for status, supports non-blocking operation in resource-constrained environments, with polling via tcp_poll() for idle connections. Portability across operating systems and hardware is achieved via the OS in lwip/opt.h, a configuration header that defines compile-time options for . It includes settings for (e.g., MEM_SIZE), threading (e.g., TCPIP_THREAD_PRIO), and protections (e.g., SYS_LIGHTWEIGHT_PROT), allowing selection of no-OS mode (NO_SYS=1) or integration with RTOS via semaphores and mutexes. Custom lwipopts.h files override defaults to tailor the stack, ensuring compatibility without modifying core . This layer briefly interfaces with memory pools for and pbuf allocation, as detailed in dedicated management mechanisms.

Memory and Buffer Management

lwIP employs a specialized system tailored for resource-constrained devices, emphasizing efficiency and predictability to minimize overhead in / operations. The core of this system revolves around packet buffers (pbufs) and a combination of static memory pools and a dynamic , which together handle allocation for blocks, packet data, and other structures without relying on general-purpose operating system allocators. Central to lwIP's buffering is the pbuf structure, a chainable data unit that enables packet handling by allowing packets to span multiple non-contiguous buffers. Pbufs support several types to optimize for different scenarios: PBUF_RAM allocates contiguous memory from the heap for transmit packets, including headers; PBUF_POOL draws from a pre-allocated pool for receive packets; PBUF_REF references external data without copying, facilitating transfers but requiring careful handling to avoid data volatility; and PBUF_ROM points to for immutable content. occurs via the next pointer, with functions like pbuf_chain() linking buffers while updating total length (tot_len), enabling efficient assembly of fragmented packets without unnecessary data movement. via pbuf_ref() and pbuf_free() ensures proper deallocation, supporting shared ownership in multi-layer processing. For broader memory allocation, lwIP uses static memory pools (memp) to provide fixed-size blocks for common objects, configurable via options like MEMP_NUM_PBUF (default 16 for pool-allocated pbufs), MEMP_NUM_TCP_PCB (default 5 for control blocks), and others such as MEMP_NUM_UDP_PCB or MEMP_NUM_ARP_QUEUE. These pools are pre-allocated at from a reserved static segment, promoting fragmentation-free operation and deterministic behavior in real-time systems. Complementing this, the heap subsystem offers dynamic allocation through mem_malloc() and mem_free(), implementing a simple first-fit algorithm on a configurable block (default MEM_SIZE 1600 bytes) for variable-sized requests not covered by pools. Configuration options further tailor memory handling to hardware constraints, such as MEM_ALIGNMENT (default 1, often set to 4 for 32-bit CPUs) to ensure proper data alignment and reduce access penalties. Enabling MEM_USE_POOLS (default 0) replaces heap allocations with tiered pools of fixed sizes, selecting the smallest fitting pool to further mitigate fragmentation at the cost of flexibility. This design trades the predictability and speed of fixed pools—ideal for avoiding runtime allocation failures in embedded contexts—against the adaptability of the dynamic heap, which supports larger or irregular allocations but risks fragmentation and slower performance.

Protocol Implementations

Network and Transport Layers

lwIP provides robust support for both IPv4 and at the network layer, enabling dual-stack operation in resource-constrained environments. IPv4 implementation includes across multiple interfaces when configured via the IP_FORWARD option, which is disabled by to conserve resources. Fragmentation of outgoing IPv4 packets exceeding the MTU is handled through the IP_FRAG option, while incoming fragmented packets are reassembled using IP_REASSEMBLY, with configurable limits such as a maximum of 10 packet buffers (IP_REASS_MAX_PBUFS) and a reassembly timeout of 15 seconds (IP_REASS_MAXAGE). For , similar capabilities are available: forwarding is enabled by LWIP_IPV6_FORWARD, fragmentation by LWIP_IPV6_FRAG, and reassembly by LWIP_IPV6_REASS, with a reassembly timeout of 60 seconds (IPV6_REASS_MAXAGE). decisions in lwIP are managed through the ip_route() function, which selects the appropriate interface based on the destination address and local , supporting basic source-based routing hooks for advanced configurations. The in lwIP centers on and implementations optimized for low memory usage. employs a state machine that progresses through key states such as () for and ESTABLISHED for active , ensuring reliable, ordered with retransmission mechanisms limited to a maximum of 12 attempts for data segments (TCP_MAXRTX) and 6 for packets (TCP_SYNMAXRTX). Congestion control follows a Reno variant, incorporating slow start, congestion avoidance, and fast recovery phases to adapt the congestion window dynamically based on acknowledgments and timeouts, as updated from earlier 2001 compliance to align with 5681 principles. Window scaling is supported via the LWIP_WND_SCALE option, allowing larger receive windows beyond the default 4 times the (TCP_WND), while selective acknowledgments () are enabled through LWIP_TCP_SACK_OUT to report non-contiguous received blocks, improving efficiency in lossy networks with up to 4 blocks (LWIP_TCP_MAX_SACK_NUM). UDP in lwIP offers lightweight, connectionless delivery, with packets processed directly without sequencing or retransmission, relying on the layer for basic routing and verification. UDP-Lite extends this with optional partial coverage, enabled by LWIP_UDPLITE, allowing applications to receive partially corrupted for error-resilient scenarios like , where only critical headers are protected while payload errors are tolerated. Both protocols use a default time-to-live value inherited from settings (UDP_TTL), and lwIP appends receive information such as source addresses to netbufs when LWIP_NETBUF_RECVINFO is enabled. ICMP and ICMPv6 handle error reporting and diagnostics, integral to lwIP's robustness. ICMP for IPv4, enabled by LWIP_ICMP, supports echo request/reply for operations via functions like icmp_send_echo, along with destination unreachable and time exceeded messages for error feedback. , activated with support, extends this to IPv6-specific errors and includes functionality through echo APIs. group management is facilitated by IGMP for IPv4 (LWIP_IGMP), allowing hosts to join and leave groups for efficient traffic distribution, compliant with 1112. For , equivalent multicast listener discovery (MLD) is supported, though limited to version 1 per 2710. IPv6 address resolution in lwIP relies on the (NDP), implemented in the nd6.c module and compliant with RFC 4861 for neighbor discovery and RFC 4862 for stateless address autoconfiguration. NDP replaces by using messages like Neighbor Solicitation and Advertisement to map to link-layer addresses, maintaining a neighbor of up to 10 entries and a destination similarly sized, with reachability confirmed via periodic probes or hints when LWIP_ND6_TCP_REACHABILITY_HINTS is enabled. This enables dynamic discovery of neighbors and routers on the local link without manual . lwIP provides support for essential link-layer protocols to enable communication over various physical media, particularly suited for resource-constrained embedded environments. The Address Resolution Protocol () is implemented to resolve IPv4 addresses to hardware () addresses on local networks, facilitating Ethernet-based connectivity by maintaining an ARP table and handling requests and replies as per RFC 826. This implementation includes options for queuing outgoing packets during resolution and gratuitous for duplicate address detection. For serial and dial-up connections, lwIP incorporates the (PPP), supporting both PPP over Serial (PPPoS) and PPP over Ethernet (PPPoE) for encapsulating IP packets. PPP in lwIP enables authentication through protocols such as (PAP), (CHAP, including MSCHAPv1), and others, allowing secure link establishment with username/password verification. These features integrate with the IP layer to support dynamic addressing and compression options like Van Jacobson header compression for efficiency. At the , lwIP includes lightweight implementations of key protocols for network configuration and management. The built-in DNS resolver supports queries over , with options for secure DNS features and integration with DHCP for automatic server assignment. DHCP client functionality allows automatic assignment, including support for AutoIP (APIPA) for link-local addressing and stateless DHCPv6. For web services, lwIP offers a basic HTTP server capable of handling GET/POST requests, Server-Side Includes (SSI), and (CGI) for dynamic content, while HTTP client support is available through the socket or raw API. is facilitated by an SNMPv2c agent, which includes a MIB compiler for custom objects and trap generation. A simple SMTP client is provided as an optional module for sending emails, adhering minimally to RFC 5321, though full email retrieval via POP3 requires external or contrib implementations. Multicast operations are supported through IGMP for IPv4 (primarily v2 with partial v3 compatibility for source filtering) and MLD for IPv6 (v1 per RFC 2710), enabling hosts to join/leave multicast groups efficiently. These protocols integrate with the IP layer to manage group memberships without native snooping. lwIP does not include native TLS/SSL support at the application layer, necessitating external libraries like mbedTLS integrated via the altcp API for securing protocols such as HTTPS or SNMPv3. This modular approach keeps the core stack lightweight while allowing extensions for encrypted communications.

APIs and Interfaces

Raw API

The raw API in lwIP provides a low-level, event-driven interface for direct interaction with the TCP/IP protocols, optimized for resource-constrained embedded systems without an operating system. It enables applications to handle network events through callbacks, allowing tight integration with the stack while minimizing overhead. This API is non-thread-safe by design, prioritizing efficiency over concurrent access support. Central to the raw API is its callback-driven model, where applications register callback functions to respond to events such as incoming data, connection establishment, or errors. For , the tcp_new() function creates a new block () in the CLOSED state, which serves as the connection's state structure. Applications then bind the PCB to a address and using tcp_bind(), listen for incoming connections with tcp_listen(), and accept them via an accept callback. Data reception is managed through the tcp_recv() callback, invoked by the stack when new data arrives; this callback receives a pointer to the TCP PCB and a pbuf chain containing the data, along with a user-specified argument for context. Upon processing, the application must free the pbuf if returning ERR_OK to acknowledge receipt, or ERR_ABRT to abort the connection. Similar patterns apply to , where udp_new() allocates a UDP PCB, udp_bind() assigns a , and udp_recv() registers a callback for incoming datagrams. For raw protocols, raw_new() creates a PCB for a specific number, and raw_recv() sets the receive callback to handle matching incoming packets. The raw API employs no-copy semantics to enhance performance and reduce memory usage, passing packet data via references to pbuf structures rather than duplicating buffers internally. Pbufs represent packet buffers that can chain multiple segments, allowing direct access to received or transmitted data without unnecessary copying; applications process the pbuf chain in the callback and release it explicitly with pbuf_free() when done. This approach avoids buffering overhead, making it suitable for systems with limited . Sending data follows a similar pattern: for , tcp_write() queues data into the PCB's send buffer (referenced by pbufs), while for , udp_sendto() transmits a pbuf chain directly. For implementing custom protocols or sending raw IP packets, the raw API exposes low-level functions like ip_output(), which allows direct transmission of IP datagrams. This function takes a pbuf containing the packet payload, source and destination addresses, , TOS, and number, then routes the packet through the appropriate network interface without higher-layer processing. It ensures the pbuf reference count is 1 before output to prevent reference issues, enabling applications to inject non-standard or experimental protocols atop the layer. Thread-safety in the raw is limited, as it is intended for single-threaded execution in no-OS environments, with all API calls required to occur from the main lwIP to avoid conditions. Critical sections, such as allocation or pbuf , are protected using lightweight mechanisms enabled by defining SYS_LIGHTWEIGHT_PROT in lwipopts.h; these employ SYS_ARCH_PROTECT() and SYS_ARCH_UNPROTECT() macros to temporarily disable interrupts or acquire a global lock, ensuring atomicity for short operations without full mutex overhead. In multi-threaded ports, applications must serialize access to raw functions externally. A representative example of raw API usage is a simple echo server, which demonstrates the callback model for handling incoming s. The application calls udp_new() to create a UDP , binds it to 7 (the standard echo ) on any local with udp_bind(pcb, IP_ADDR_ANY, 7), and registers a receive callback via udp_recv(pcb, udp_echo_recv, NULL). The udp_echo_recv callback function receives the PCB, a pbuf chain with the datagram, the source IP and , and the user argument; it then echoes the data back using udp_sendto(pcb, pbuf, &source_ip, source_port) and frees the original pbuf with pbuf_free(pbuf). This setup processes packets zero-copy and integrates directly with the lwIP .

Socket API

The lwIP Socket API provides a sockets-compatible interface that allows applications to interact with the TCP/IP stack in a manner similar to systems, facilitating easier of existing code from environments. This optional API is designed to be thread-safe and is intended for use from non-TCPIP threads, building upon the sequential API layer to abstract the underlying raw mechanisms. It supports both and protocols through standard functions, enabling developers to create networked applications without needing to manage low-level protocol details directly. To enable the Socket API, the configuration option LWIP_SOCKET must be set to 1 during compilation, which activates the necessary components including the POSIX header sys/socket.h. Key functions mirror semantics, such as lwip_socket() for creating s, lwip_bind() for associating a socket with a local address, lwip_connect() for establishing connections, lwip_listen() for setting up passive TCP sockets, and lwip_accept() for accepting incoming connections. Data transmission and reception are handled via lwip_send(), lwip_recv(), and related variants, while multiplexing is supported through lwip_select() and lwip_poll() to monitor multiple sockets for readiness. These functions internally translate calls to the sequential API, which in turn interfaces with the raw API for protocol handling. The Socket API includes IPv6 extensions to support modern networking requirements, such as lwip_getaddrinfo() for hostname resolution to addresses (enabled via the NETDB API) and functions like lwip_inet_ntop() and lwip_inet_pton() for address string conversions. Dual-stack operation is achieved by specifying the appropriate domain (e.g., AF_INET or AF_INET6) in the lwip_socket() call, allowing applications to handle both IPv4 and transparently where configured. However, due to inherent limitations in the API specification for resource-constrained environments, some incompatibilities with full compliance exist, potentially requiring minor code adjustments for ported applications; advanced features like full fork() support are not provided, as the API assumes a single-process model typical of systems. Compared to the raw , the Socket API introduces higher memory overhead owing to the additional abstraction layers and thread-safety mechanisms, making it less suitable for the most memory-tight scenarios but preferable for applications prioritizing portability and ease of .

Integration and Porting

No-OS Operation

lwIP operates in no-OS mode, also referred to as bare-metal or standalone mode, for systems lacking an operating system, emphasizing minimal resource usage and single-threaded execution with the raw . This configuration sets NO_SYS=1 in lwipopts.h, eliminating the need for OS abstractions like semaphores or mailboxes, and instead using implementations in sys_arch.h for system calls. The design ensures lwIP's core—, ICMP, , and —runs deterministically without multi-threading support, making it suitable for real-time applications where predictability is essential. In no-OS mode, the application manages a single-threaded main to drive lwIP processing. This typically polls the network driver to retrieve incoming packets, passes them to the stack via ip_input(pbuf, netif), and then invokes sys_check_timeouts() to handle protocol . Key include tcp_tmr(), called approximately every 250 ms to manage connections, finite state machine advancements, and retransmissions, as well as ip_reass_tmr(), called every IP_TMR_INTERVAL (default 1000 ms) to manage reassembly timeouts (default duration 3 seconds). Earlier lwIP versions required explicit calls to individual like tcp_tmr() and etharp_tmr(); however, since version 1.4.0, sys_check_timeouts() centralizes this, reducing code complexity while relying on a monotonic sys_now() implementation, often based on a hardware like SysTick on platforms. A representative structure appears as follows:
c
while (1) {
  ethernetif_input(&netif);  // Poll for and process incoming packets
  sys_check_timeouts();      // Handle timers
}
This polling ensures all lwIP API calls occur sequentially from one context, avoiding reentrancy issues inherent in OS environments. Packet input can be interrupt-driven to respond promptly to events, with the Ethernet calling ethernetif_input(netif) directly from the to enqueue or process received frames into pbuf structures for lwIP consumption. However, since no-OS lwIP assumes a single execution context, interrupt handlers must not invoke reentrant functions like udp_send() or tcp_write() without protection, as this could lead to or deadlocks. Instead, short, non-blocking operations are permitted if the defers complex processing to the main loop via a simple queue. Thread safety in no-OS mode relies on lightweight mechanisms defined by SYS_ARCH_PROTECT(old_level) and SYS_ARCH_UNPROTECT(old_level) macros, enabled when LWIP_TCPIP_CORE_LOCKING or SYS_LIGHTWEIGHT_PROT is set to 1 in lwipopts.h. These macros are implemented by disabling global interrupts (e.g., using __disable_irq() and __enable_irq() on ) for atomic critical sections, such as pbuf allocation or , typically lasting microseconds. This interrupt-based locking provides sufficient for the non-reentrant core without OS primitives, though prolonged disables should be avoided to prevent system latency. For instance, during netif->input() calls from , ensures exclusivity against the main loop's timer processing. No-OS lwIP targets bare-metal platforms with limited resources, such as microcontrollers (e.g., , LPC series) and AVR devices, where dependencies are confined to a basic port in cc.h for types and error handling, plus a provider. These systems achieve lwIP's of under 40 KB and 60 KB for a minimal / configuration, enabling networking on 8- or 32-bit MCUs without scheduler overhead. A practical example is porting lwIP to using the Hardware Abstraction Layer () in FreeRTOS-free setups, as demonstrated in ' CubeMX-generated projects. Here, APIs like HAL_ETH_ReadPHYRegister() manage the Ethernet MAC and PHY, while the main loop polls via ethernetif_input(&gnetif) and timers through MX_LWIP_Process(). Interrupts for reception trigger HAL_ETH_IRQHandler(), which signals the main context to process packets, ensuring compatibility with STM32F4/H7 devices for applications like telemetry or servers without OS bloat. This integration highlights lwIP's portability, requiring only initialization and lwIP's raw callbacks for protocol handling.

RTOS and OS Support

lwIP provides an operating system through the sys.h header file, which enables compatibility with various operating systems (RTOS) by implementing wrappers for semaphores, mutexes, mailboxes, and threads. This layer allows lwIP to integrate seamlessly with popular RTOS such as , where it is commonly used in embedded applications for its raw API and /IP thread support. Similarly, ports exist for RTOS, enabling lwIP usage in and networked devices on platforms like NXP MCUs, often alongside Zephyr's native networking but as an alternative stack for specific requirements. For , integration is achievable by adapting the abstraction layer, though it requires custom modifications to align with ThreadX's threading model and avoid conflicts with its native NetX Duo stack. Beyond RTOS, lwIP has been ported to full operating systems, particularly microkernel-based ones, where it serves as a lightweight network stack. In ReactOS, lwIP forms the core of the network subsystem, with ongoing efforts to enhance TCP support through projects like Google Summer of Code integrations. Genode OS Framework incorporates lwIP via VFS plugins for socket-based networking, supporting HTTP servers and dynamic configurations in its component-based architecture. MINIX 3 adopted an lwIP-based TCP/IP service in 2017, replacing its prior stack to provide POSIX-compliant networking with improved efficiency in its microkernel environment. The GNU Hurd utilizes a dedicated lwIP port as a translator for network servers, enabling TCP/IP functionality atop its Mach microkernel since its integration in Debian GNU/Hurd releases. In vendor ecosystems, lwIP is deeply embedded in development tools for specific embedded processors. Intel's (formerly ) Nios II soft-core processor supports lwIP through tutorials and HAL drivers, facilitating Ethernet connectivity in FPGA-based systems with MicroC/OS-II or similar RTOS. Xilinx's processor leverages the standalone lwIP library for /IP operations on Zynq and UltraScale+ devices, configurable via the Xilinx SDK for bare-metal or RTOS environments. STMicroelectronics' STM32Cube middleware includes comprehensive lwIP support, with user manuals detailing application development for STM32 MCUs, including DHCP and socket APIs integrated with CubeMX code generation. Porting lwIP to a new OS involves implementing key functions in the sys_arch.c file, such as sys_mbox_post() for posting messages to mailboxes and sys_thread_new() for creating threads, to map lwIP's requirements onto the target's synchronization primitives. These implementations ensure and handle timeouts, allowing lwIP's core to operate in multi-threaded contexts without direct OS dependencies. Despite its versatility, lwIP exhibits scalability limitations when integrated into high-throughput full OS environments like , where its lightweight design—optimized for minimal resource use—cannot match the performance of native monolithic stacks, making it unsuitable as a replacement. In such cases, lwIP is better suited for user-space testing or drivers rather than core kernel integration.

Performance and Optimization

Resource Usage

lwIP's core implementation for TCP/IPv4 typically requires around 40 kilobytes of for code space, making it suitable for resource-constrained systems. This footprint encompasses essential handling without advanced features, while the overall design targets systems with tens of kilobytes of available . For example, on Espressif ESP32-P4 hardware, enabling support increases the ROM usage by approximately 39 kilobytes, along with additional RAM of 2 kilobytes at and up to 7 kilobytes during . RAM requirements are primarily driven by configurable pools and states. The pool, controlled by PBUF_POOL_SIZE, allocates fixed-size blocks for incoming and outgoing packets; a typical configuration with 16 of 1536 bytes each, plus structural overhead, consumes about 24 kilobytes, though minimal setups can limit this to under 10 kilobytes total for the . For , each active and associated demand additional dynamic allocation, often around 2 kilobytes per depending on window sizes and queue depths, with defaults like TCP_WND at 2048 bytes contributing to this. The of lwIP minimizes CPU overhead, as it only activates on interrupts or polled events. During packet bursts, usage peaks proportionally to traffic volume, but the non-blocking design prevents sustained high load. Benchmarks on ARM-based microcontrollers, such as the AM263P4, demonstrate throughputs below 15 megabits per second for small datagrams. Overall stack size varies with enabled features; for instance, software checksum computation increases CPU cycles without significantly altering memory, whereas options like or additional protocols directly inflate and footprints. These estimates are based on lwIP version 2.1.x; the latest stable version, 2.2.1 released in February 2025, includes bug fixes but maintains similar core resource characteristics.

Configuration and Tuning

lwIP configuration is primarily managed through the lwipopts.h header file, where users override default settings to tailor the stack's behavior, memory usage, and features to specific applications. This file allows selective enabling or disabling of modules and adjustment of parameters such as heap size and connection limits, ensuring the stack remains lightweight while meeting performance needs. All options must be defined before including core lwIP headers to take effect. Key memory and connection parameters include MEM_SIZE, which sets the heap size in bytes (default: 1600), critical for applications handling large data copies to avoid allocation failures. TCP_WND defines the receive window size (default: 4 * TCP_MSS, or 2144 bytes with default MSS), influencing throughput; values below 2 * TCP_MSS may degrade performance, while larger ones boost it at the cost of . Similarly, MEMP_NUM_TCP_PCB controls the number of active connections (default: 5), directly limiting concurrent sessions to conserve resources in constrained environments. For , increasing TCP_MSS beyond the default 536 bytes accommodates larger MTUs, reducing packet overhead in high-bandwidth scenarios, though it requires verifying network compatibility. Enabling LWIP_TCP_KEEPALIVE (set to 1) supports persistent connections by periodically probing idle ones, configurable via options like TCP_KEEPIDLE, preventing resource waste from stale links. Optimization techniques involve disabling unused modules, such as setting #define LWIP_DHCP 0 to exclude DHCP code and reduce footprint, or adjusting MEM_ALIGNMENT (default: 1) for platform-specific CPU alignments like 4 bytes on to enhance efficiency. Debugging is facilitated by LWIP_DEBUG (set to 1 to enable output) and module-specific flags like ETHARP_DEBUG (for logging), which add conditional logging without affecting release builds when undefined, allowing targeted diagnostics during development. Best practices emphasize balancing parameters against application demands; for instance, tuning MEMP_NUM_UDP_PCB (default: 4) limits UDP "connections" to manage queue latency, preventing overflows in systems while minimizing memory overhead.

References

  1. [1]
    lwIP - A Lightweight TCP/IP stack - Summary - Savannah.nongnu.org
    Oct 17, 2002 · The focus of the lwIP TCP/IP implementation is to reduce resource usage while still having a full scale TCP. This makes lwIP suitable for use ...
  2. [2]
    [PDF] Design and Implementation of the lwIP TCP/IP Stack
    Feb 20, 2001 · lwIP is a TCP/IP stack implementation designed to reduce memory usage and code size, suitable for small clients with limited resources.
  3. [3]
    lwIP: Overview - Savannah.nongnu.org
    lwIP is a small, independent TCP/IP implementation focused on reducing RAM usage, suitable for embedded systems with limited RAM.
  4. [4]
    Upgrading - lwIP - Savannah.nongnu.org
    This file lists major changes between release versions that require ports or applications to be changed. Use it to update a port or an application written ...
  5. [5]
    lwIP: Options (lwipopts.h)
    ### Summary of lwIP Options (lwipopts.h) - lwIP 2.1.0
  6. [6]
    IPv6 - lwIP - Savannah.nongnu.org
    lwIP IPv6 includes modules like ICMP6, DHCPv6, and options for enabling IPv6, address autoconfiguration, and fragmentation of large packets.
  7. [7]
    patch #10111, [RFC] Hardware checksum offloading [Savannah]
    Sep 25, 2021 · The computation depends on netif feature flags: - Without netif feature flags activated, lwip should always compute only a partial checksum.Missing: filters | Show results with:filters
  8. [8]
    Network interface (NETIF) - lwIP - Savannah.nongnu.org
    These functions use netif flags NETIF_FLAG_ETHARP and NETIF_FLAG_ETHERNET to decide whether to forward to ethernet_input() or ip_input(). In other words, the ...Missing: filters firewall
  9. [9]
  10. [10]
    [PDF] Programming Memory-Constrained Networked Embedded Systems
    The software I have developed as part of this thesis, lwIP, uIP, protothreads, and. Contiki, is currently used by hundreds of companies in embedded devices in.Missing: origins | Show results with:origins
  11. [11]
    news lwIP - A Lightweight TCP/IP stack - Savannah.nongnu.org
    lwIP 2.2.1 was released on Feb 6, 2025, mostly a bugfix release. lwIP 2.2.0 was released on Sep 25, 2023, with bug fixes and full ACD support.Missing: official | Show results with:official
  12. [12]
    lwIP 1.3.0: lwIP Documentation - Savannah.nongnu.org
    lwIP is a small, independent TCP/IP implementation designed to reduce resource usage, making it suitable for embedded systems.
  13. [13]
    lwIP: Changelog
    Summary of each segment:
  14. [14]
    A Lightweight TCP/IP stack - News: lwIP 2.1.0 released [Savannah]
    Sep 26, 2018 · lwIP 2.1.0 is now available from the lwIP download area on savannah [1] or via git (using the STABLE-2_1_0_RELEASE tags in both repositories).Missing: history | Show results with:history
  15. [15]
    lwIP: Changelog - Savannah.nongnu.org
    - Added PPP IPv6 support, glued lwIP IPv6 support to PPP. - Now using a ... 1) Changes since version 0.3 * Fix of a fatal bug in the buffer management.
  16. [16]
    TCP - lwIP - Savannah.nongnu.org
    A new TCP connection identifier (i.e., a protocol control block - PCB) is created with the tcp_new() function. This PCB can then be either set to listen for new ...Missing: components ip_input lwip_event_t opt.
  17. [17]
    lwIP: UDP
    ### Summary of UDP PCB in lwIP
  18. [18]
    lwIP: src/include/lwip/ip.h File Reference
    ### Summary of ip_input() in lwIP ip.h
  19. [19]
    tcp_input() - syntax, references, call tree, description - SourceVu
    LwIP tcp_input(). tcp_input() function. The initial input processing of TCP. It verifies the TCP header, demultiplexes the segment between the PCBs and passes ...
  20. [20]
    lwIP: "raw" APIs - Savannah.nongnu.org
    A particular application may register to be notified via a callback function for events such as incoming data available, outgoing data sent, error ...Missing: asynchronous | Show results with:asynchronous
  21. [21]
    lwIP: src/include/lwip/opt.h File Reference
    ### Summary of OS Abstraction Layer in lwip/opt.h for Portability
  22. [22]
    lwIP: Heap and memory pools
    ### Summary of Heap Management in lwIP (from https://www.nongnu.org/lwip/2_1_x/group__lwip__opts__mem.html)
  23. [23]
    Packet buffers (PBUF) - lwIP - Savannah.nongnu.org
    Packets are built from the pbuf data structure. It supports dynamic memory allocation for packet contents or can reference externally managed packet contents ...
  24. [24]
    lwIP: Internal memory pools
    ### Summary of Memory Pools (memp) in lwIP 2.1.0
  25. [25]
    IPv4 - lwIP - Savannah.nongnu.org
    Enables the ability to forward IP packets across network interfaces. If you are going to run lwIP on a device with only one network interface, define this to 0.Missing: routing ip_route
  26. [26]
    lwIP: IP - Savannah.nongnu.org
    #define, ip_output_if_src(p, src, dest, ttl, tos, proto, netif) ; #define, ip_route(src, dest) ; #define, ip_netif_get_local_ip(netif, dest) ...Missing: function | Show results with:function
  27. [27]
    TCP - lwIP - Savannah.nongnu.org
    lwIP TCP macros include `LWIP_TCP` to enable TCP, `TCP_MSS` for max segment size, `TCP_WND` for window size, and `TCP_MAXRTX` for max retransmissions.Missing: modularity | Show results with:modularity<|separator|>
  28. [28]
    lwIP - Tasks: task #14602, TCP: update/audit congestion... [Savannah]
    Aug 9, 2017 · LwIP's TCP congestion control implementation was written back with RFC 2001 (1997), which has had two replacements: RFC 2581 (1999) and RFC ...Missing: state machine SYN Reno selective
  29. [29]
    [lwip-users] Re: [lwip] newbie question
    Jan 8, 2003 · The terms "TCP Tahoe" and "TCP Reno" are used to denote two different variants of the TCP congestion control algorithms. TCP Tahoe is the ...
  30. [30]
    lwIP: UDP
    ### Summary of UDP and UDP-Lite Support in lwIP
  31. [31]
    ICMP - lwIP - Savannah.nongnu.org
    Enable ICMP module inside the IP stack. Be careful, disable that make your product non-compliant to RFC1122Missing: support | Show results with:support
  32. [32]
    IGMP - lwIP - Savannah.nongnu.org
    Overview · Upgrading · Changelog · How to contribute to lwIP · Common pitfalls · Reporting bugs · lwIP API · ▽Modules. ▽lwIP. ▻Mainloop mode ("NO_SYS"). ▻OS mode ( ...
  33. [33]
    lwIP - ESP32 - — ESP-IDF Programming Guide v5.5.1 documentation
    ESP-IDF uses the open source lwIP lightweight TCP/IP stack. The ESP-IDF version of lwIP (esp-lwip) has some modifications and additions compared to the ...<|control11|><|separator|>
  34. [34]
    lwIP: src/core/ipv6/nd6.c File Reference - Savannah.nongnu.org
    Neighbor discovery and stateless address autoconfiguration for IPv6. Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 (Address ...
  35. [35]
    Neighbor discovery - lwIP - Savannah.nongnu.org
    Allow TCP to provide Neighbor Discovery with reachability hints for connected destinations. This helps avoid sending unicast neighbor solicitation messages.Missing: Protocol | Show results with:Protocol
  36. [36]
    lwIP: Overview
    ### Summary of lwIP Architecture Core Components
  37. [37]
    PPP - lwIP - Savannah.nongnu.org
    Raw API for lwIP means the lightweight API which *MUST* only be used for NO_SYS=1 systems or called inside lwIP core thread for NO_SYS=0 systems.Missing: 2.2.1 | Show results with:2.2.1
  38. [38]
    DNS - lwIP - Savannah.nongnu.org
    LWIP_DNS_SECURE: controls the security level of the DNS implementation. Use all DNS security features by default. This is overridable but should only be needed ...<|control11|><|separator|>
  39. [39]
    SMTP client - lwIP - Savannah.nongnu.org
    This is simple SMTP client for raw API. It is a minimal implementation of SMTP as specified in RFC 5321.Missing: POP3 support
  40. [40]
    lwIP: IGMP
    ### Summary of IGMP and MLD Support in lwIP
  41. [41]
    lwIP: src/include/lwip/raw.h File Reference
    ### Summary of API Functions for Raw Protocols from raw.h (lwIP 2.1.0)
  42. [42]
    Critical sections - lwIP - Savannah.nongnu.org
    Critical sections in lwIP protect short code regions from concurrent access, using macros like SYS_ARCH_PROTECT and SYS_ARCH_UNPROTECT for fast protection.Missing: safety | Show results with:safety
  43. [43]
    Socket API - lwIP - Savannah.nongnu.org
    The lwIP socket API is a BSD-style, thread-safe compatibility API for existing applications, built on top of the sequential API.Missing: modularity selective
  44. [44]
    lwIP: NETDB API
    ### Summary: getaddrinfo() and IPv6 Support in lwIP Socket API
  45. [45]
    APIs - lwIP - Savannah.nongnu.org
    The raw TCP/IP interface allows the application program to integrate better with the TCP/IP code. Program execution is event based by having callback functions ...
  46. [46]
    lwIP: Common pitfalls - Savannah.nongnu.org
    When the application wants to call lwIP, it only needs to disable interrupts during the call. If timers are involved, even more locking code is needed to lock ...Missing: SYS_ARCH_LOCK | Show results with:SYS_ARCH_LOCK
  47. [47]
    [PDF] Developing applications on STM32Cube with LwIP TCP/IP stack
    Mar 28, 2014 · License. LwIP is licensed under the BSD license. Below is a copy of the LwIP license document that is included in the source codes ...
  48. [48]
    lwIP: Porting (system abstraction layer) - Savannah.nongnu.org
    For the full lwIP functionality, multiple threads support can be implemented in the sys_arch, but this is not required for the basic lwIP functionality.Missing: MMU | Show results with:MMU
  49. [49]
    LwIP using FreeRTOS - Kernel
    May 2, 2023 · We have been using Lwip with FreeRTOS for many years; however we use only the Raw API, partly for historical reasons but also for performance.
  50. [50]
    example lwip_dhcp_usb_bm and ZephyrRTOS - NXP Community
    Oct 14, 2025 · Solved: Hi, I would like to know if its possbile to combine the sample: ` examples/lwip_examples/lwip_dhcp_usb/lwip_dhcp_usb_bm ` with ZephyrOS 4.x.[FINISHED] TCP/IP stacks comparison on NXP MCU processorsSolved: Re: SNMP support for RT1024 - NXP CommunityMore results from community.nxp.com
  51. [51]
    Solved: LwIP with Threadx - STMicroelectronics Community
    Jan 8, 2025 · Solved: From my research, I've read that LwIP is written with FreeRTOS, but can be altered to support any OS. Since ST has made an effort ...RTOS selection for STM32H7R/S - STMicroelectronics CommunityFREERTOS OR THREADX : THIS IS THE PROBLEMMore results from community.st.comMissing: Zephyr | Show results with:Zephyr
  52. [52]
    Google SoC lwIP Conclusion - ReactOS Project
    Aug 23, 2016 · My Google Summer of Code project proposal stated that I would add TCP support to the network branch of ReactOS, which sought to integrate lwIP ...
  53. [53]
    System integration and automated testing - Genode
    A good example is the run script at repos/libports/run/lwip.run, which tests the lwIP stack by running a simple Genode-based HTTP server on the test machine.
  54. [54]
    [lwip-devel] MINIX 3 has switched to lwIP
    May 1, 2017 · All, As of today, the MINIX 3 operating system has switched over to a lwIP-based TCP/IP stack. I am posting about that here not just because ...
  55. [55]
    A port of LwIP to the Hurd - GitHub
    A port of LwIP to the Hurd. Contribute to jlledom/lwip-hurd development by creating an account on GitHub.
  56. [56]
    [PDF] Using Lightweight IP with the Nios II Processor Tutorial
    This tutorial provides step-by-step instructions for building a simple program based on the MicroC/OS-II RTOS and lwIP TCP/IP networking stack. This tutorial ...Missing: Xilinx MicroBlaze STM32Cube<|separator|>
  57. [57]
    Standalone LWIP library - Xilinx Wiki - Confluence
    Sep 24, 2025 · Introduction. LWIP220 provides a light weight TCP/IP stack to use with ethernet interfaces. It supports: GEM on Zynq, Zynq Ultrascale+ MPSoC ...
  58. [58]
    Re: [lwip-users] lwIP in mainline linux kernel - GNU mailing lists
    Feb 7, 2018 · Both are micro kernels and the integration point with LwIP is different. GNU Hurd integrated at the sockets level where as Minix 3, integrated ...
  59. [59]
    [lwip-users] recv ok.. send is super slow
    I am trying to test the performance of the lwip stack between two linux machines. If the server is lwIP, the performance is on par with the linux IP stack.Missing: scalability issues
  60. [60]
    lwIP - ESP32-P4 - — ESP-IDF Programming Guide v5.5.1 ...
    The ioctl() function provides a semi-standard way to access some internal features of the TCP/IP stack. In ESP-IDF, the Virtual Filesystem Component layer is ...Missing: ip_route | Show results with:ip_route
  61. [61]
    [PDF] Implementation of IPv6 in Embedded Device using LWIP TCP/IP Stack
    For IPv6 support in this drive, LWIP stack has been implemented and finally this Dual Stack supported device will be able to communicate with either only ...
  62. [62]
    AM263P4: CPSW latency improvements - Arm-based microcontrollers
    Jan 23, 2024 · The SDK v9.01 SDK has a benchmark showing the CPSW can handle <15Mpbs (with 64B UDP datagrams) before it begins dropping packets. Obviously ...Unable to reach gigabit throughput using iperf tool - Arm ... - TI E2Etm4c129encpdt: Experiences with lwIP and TivaWare? - TI E2EMore results from e2e.ti.com
  63. [63]
    Sockets - lwIP - Savannah.nongnu.org
    lwIP » Options (lwipopts.h) » Thread-safe APIs. Macros ... LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT options processing.
  64. [64]
    lwIP: DHCP
    ### Summary of LWIP_DHCP
  65. [65]
    lwIP: Debugging
    ### Summary of LWIP_DEBUG and ETHARP_DEBUG from https://www.nongnu.org/lwip/2_1_x/group__lwip__opts__debug.html