IP 协议栈架构¶
IP 协议栈顶层概述¶
Network stack overview
- IP 协议栈是分层的,由以下几部分组成:
- 网络应用程序。 这些应用程序使用连接 API 来操作网络连接,使用管理 API 来设置网络相关的参数(例如启动扫描、设置网络接口的 IP 地址等)。
- 核心 IP 协议栈。 它实现了各种各样的协议,例如 IPv6、IPv4、UDP、TCP、ICMPv4 和 ICMPv6。
- 网络接口抽象层。 它为所有网络接口提供了通用功能,例如获取 IP 地址等。
- 通用的 L2 层。 为向实际网络设备收发数据提供通用 API。
- L2 网络技术组件。 这些组件包括 Ethernet、IEEE 802.15.4、Bluetooth 等。其中,部分技术支持 IPv6 头部压缩(6LoWPAN),已在其自己的分层中实现。例如,在 Ethernet 组件中实现了 ARP。
- 网络设备驱动程序。 实际的底层设备驱动程序,用于处理网络报文的物理收发。
网络的数据流¶
网络数据流
应用程序通常由一个或多有执行应用程序逻辑的 task 或线程组成。当使用网络连接 API 时,将会发生下面的事:
数据接收(RX):
- 设备驱动程序接收到一个网络数据报文。
- 设备驱动程序分配足够的网络 buffe,用于存储所接收到的数据。之后,网络 buffer 会被传递到 RX FIFO,用于进一步处理。RX FIFO 用于分隔数据处理流水线(底半步),因为设备驱动程序运行在中断上下文,它必须快速地处理工作。
- RX 线程读取 RX FIFO,并将数据传递到正确的 L2 驱动程序。经过 L2 驱动程序检查后,报文会被传递到 L3 继续处理。L3 层检测报文是否是 IPv6 报文或 IPv4 报文。如果报文包含 UDP 或 TCP 数据,它会通过回调函数传递给相应的应用程序。这意味着,回调函数中的应用程序处理数据时是运行在线程上下文中的,即使实际的应用程序运行在 task 上下文。在应用程序回调中处理数据应尽快完成,以避免阻塞系统的时间太久。系统中只有一个 RX 线程。RX 线程的栈大小可以通过 Kconfig 选项调整,但是它的值应当保持尽量小。这也意味着在数据处回调函数中应尽量少用栈空间,以避免栈溢出。
- 然后数据会被应用程序接收到,并保存在一个 net_bufs 链中。应用程序此时就获得了数据。当应用程序完成它自己的处理工作后,它应当调用 net_nbuf_unref() 来释放 net_bufs 数据。
数据发送(TX):
- 当应用程序准备发送数据时,应当使用连接 API。待发送的数据会被相应的 L2 层模块检查,如果一切 ok,数据会被放到合适的网络接口的 TX 队列中。选择网络接口时通常会选择用于响应数据报文的同一个接口,或者根据路由算法所选择的接口。当数据被正确地放到 TX 队列中后,应用程序不需要释放数据报文;网络驱动程序会在数据发送后将其释放。如果连接 API 的发送函数给应用程序返回了一个错误,说明报文未被正确地发送出去,此时应用程序需要释放这个报文。
- 每个网络接口都有一个与之关联的 TX 线程,它会将报文发送到正确的设备驱动程序中。
- 如果设备驱动程序能将网络报文注射到网络中,它会释放报文。通常,在这一层没有重传机制,因此通常即使报文未被正确发送也有可能被释放。这依赖于所使用的技术。