< IP_HLEN) { /* 长度校验 */LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output: LWIP_IP_HDRINCL but pbuf is too short\n"));IP_STATS_INC(ip.err);MIB2_STATS_INC(mib2.ipoutdiscards);return ERR_BUF;}iphdr = (struct ip_hdr *)p->payload;ip4_addr_copy(dest_addr, iphdr->dest); /* 获取目的IP地址 */dest = &dest_addr;}/* 状态记录 */IP_STATS_INC(ip.xmit);LWIP_DEBUGF(IP_DEBUG, ("ip4_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], (u16_t)netif->num));ip4_debug_print(p);#if ENABLE_LOOPBACK /* 环回功能 */if (ip4_addr_eq(dest, netif_ip4_addr(netif)) /* 目的IP为源网卡IP,则是环回 */#if !LWIP_HAVE_LOOPIF|| ip4_addr_isloopback(dest) /* 目的IP是环回IP字段,也是环回 */#endif /* !LWIP_HAVE_LOOPIF */) {/* 数据包环回,则不用通过数据链路层,直达对应网卡的环回链表即可 */LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));return netif_loop_output(netif, p);}#if LWIP_MULTICAST_TX_OPTIONSif ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { /* 该pbuf是要环回的UDP组播 */netif_loop_output(netif, p); /* 环回到本网卡 */}#endif /* LWIP_MULTICAST_TX_OPTIONS */#endif /* ENABLE_LOOPBACK */#if IP_FRAG/* 如果接口mtu设置为0,不用分片 *//* 分片检查 */if (netif->mtu && (p->tot_len > netif->mtu)) { /* IP报文超出网卡MTU,则需要分片处理 */return ip4_frag(p, netif, dest); /* 需要分片处理 */}#endif /* IP_FRAG *//* 不需要分片处理 */LWIP_DEBUGF(IP_DEBUG, ("ip4_output_if: call netif->output()\n"));return netif->output(netif, p, dest); /* IP层发送数据包 。至此,IP报文处理完毕,下一步交给ARP或者直接到数据链路处理 。*/}9.7.5 IP数据报分片注意:lwip分片偏移不支持IP首部带选项字段的 。
从IP报文首部就可知,有分片概念 。
不是每个底层网卡都能承载每个 IP 数据报长度的报文 。如:
- 以太网帧最大能承载 1500 个字节的数据 。
- 某些广域网链路的帧可承载不超过 576 字节的数据 。
IP 数据报的分片偏移量是用 8 的整数倍记录的,所以每个数据报中的分片数据大小也必须是 8 的整数倍 。
IP数据报分片主要关注IP首部的标识字段、标志字段和分片偏移量字段 。具体往前看 。
参考图:

文章插图
相关源码实现在
ip4_frag.c
。相关宏:
LWIP_NETIF_TX_SINGLE_PBUF
:分片是否支持新建一整个pbuf处理 。
- 1:分片时,直接申请各个IP分片包的pbuf即可(含IP首部+数据区) 。
- 0:分片时,申请各个分片的管理区,
MEMP_FRAG_PBUF
类型 。其数据结构为pbuf_custom_ref
。该数据结构包含本次IP分片包的原IP报文pbuf地址,释放引用的api,指向分片IP报文数据区的pbuf 。然后将这个分片IP首部的pbuf和这个IP报文数据区的pbuf拼接起来即可 。组成新的分片IP报文 。
pbuf_custom
数据结构:/** A custom pbuf that holds a reference to another pbuf, which is freed * when this custom pbuf is freed. This is used to create a custom PBUF_REF * that points into the original pbuf. */struct pbuf_custom_ref {/** 'base class' */struct pbuf_custom pc; /* 用户的控制区 。包含一个pbuf和一个释放该pbuf的api *//* 指向被引用的原始pbuf的指针 */struct pbuf *original;};
pbuf_custom_ref
数据结构:struct pbuf_custom {/* The actual pbuf */struct pbuf pbuf;/**This function is called when pbuf_free deallocates this pbuf(_custom) */pbuf_free_custom_fn custom_free_function;};
相关数据结构图:- 没开启
LWIP_NETIF_TX_SINGLE_PBUF
经验总结扩展阅读
- 生的榛子在家怎么炒熟
- 【第5篇】AI语音简介
- 青椒炒鸡蛋热量
- 洗衣服时应当使用哪种洗衣粉
- 蛋白粉用冷水冲还是热水
- 2023最火女儿生日文案简短 生日文案高级简短
- 晒干辣椒的方法
- 有机鲜牛奶和鲜牛奶区别
- 绿豆芽可以放冰箱几天
- 2023七夕节适合结婚吗 2023年七夕结婚吉利吗