< 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
宏的IP分片报文数据结构:
文章插图
- 开启
LWIP_NETIF_TX_SINGLE_PBUF
宏的分片IP报文数据结构(按简单的画):
文章插图
ip4_frag()
:- 与分片重组
ip4_reass()
这个API对应 。
- 需要注意的是:需要检查本次分片处理传入的原IP报文
struct pbuf *p
是否也是一个分片包 。如果是 , 那么它可能不是顶层原IP报文分片的最后一片,这样的话 , 在本次分片处理最后一片的分片IP报文首部标志字段的还有更多分片标志位不能置位0 。因为在顶层未分片IP报文角度看来 , 这还不是真正意义上的最后一片 。
- 下面函数分析时,按
推荐阅读
- 【第5篇】AI语音简介
- 原神3.0陵薮市朝什么时间开启
- 【Azure 环境】把OpenSSL生产的自签名证书导入到Azure Key Vault Certificate中报错
- 常用类.String类
- cf如何跳上高箱子(cf开什么箱子赚cf点)
- macos monterey描述文件下载_macos monterey描述文件下载地址
- 浏览器怎样清除缓存(浏览器历史清空了怎么恢复)
- 我的世界豹猫怎么驯服,为什么给豹猫喂鱼之后不变成猫
- 支付宝蚂蚁庄园每日答题答案
- 原神90级提纳里毕业面板数值怎么样