9.5.4 路由网卡匹配的钩子函数通过分析前面的基函数和接口函数,可发现其实现是支持宏钩子函数,即是支持用户自己实现网卡匹配的逻辑的 。
有两个宏钩子:
LWIP_HOOK_IP4_ROUTE_SRC(src, dest)
:钩子入口参数有源IP和目的IP 。LWIP_HOOK_IP4_ROUTE(dest)
:钩子入口参数只有目的IP 。
而且IP包的输入和输出的网卡匹配是不一样的,比如普通的IP单播包,输出时,只需要找到目的IP和网卡处于同一个子网或者是该网卡的网关即可匹配 。而输入时 , 需要明确目的IP就是该网卡IP 。
收包的网卡匹配除了
ip4_input_accept()
这个主要函数外,还有很多独立的匹配条件 , 具体看IP层输入章节 。这里只分析
ip4_input_accept()
:- 在调用该API前,应该先配置全局IP数据结构成员值:
struct ip_globals ip_data;
- 需要被匹配的网卡必须在协议栈方向使能了,且IP地址为有效地址 。
- 单播包,目的地址和网卡地址一致,网卡匹配成功 。
- 广播包 , IP地址bit全1 , 必定是广播地址 。如果网卡就被广播能力,且IP地址的主机号bit全1,也是子网广播地址 。都匹配成功 。
- 环回,没有环回网卡,且目的IP地址为环回IP
IPADDR_LOOPBACK
。匹配成功 。
/** Return true if the current input packet should be accepted on this netif */static intip4_input_accept(struct netif *netif){LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",ip4_addr_get_u32(ip4_current_dest_addr()), ip4_addr_get_u32(netif_ip4_addr(netif)),ip4_addr_get_u32(ip4_current_dest_addr()) & ip4_addr_get_u32(netif_ip4_netmask(netif)),ip4_addr_get_u32(netif_ip4_addr(netif)) & ip4_addr_get_u32(netif_ip4_netmask(netif)),ip4_addr_get_u32(ip4_current_dest_addr()) & ~ip4_addr_get_u32(netif_ip4_netmask(netif))));/* 网卡是否在协议栈中使能且网卡地址有效? */if ((netif_is_up(netif)) && (!ip4_addr_isany_val(*netif_ip4_addr(netif)))) {/* 是否是单播到这个接口地址? */if (ip4_addr_eq(ip4_current_dest_addr(), netif_ip4_addr(netif)) ||/* 或者广播这个接口的网络地址? */ip4_addr_isbroadcast(ip4_current_dest_addr(), netif)#if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF /* 如果开启环回功能 , 但是没有创建环回网卡 *//* 目的IP是一个环回的IP地址,也就是给当前网卡的,能匹配成功 */|| (ip4_addr_get_u32(ip4_current_dest_addr()) == PP_HTONL(IPADDR_LOOPBACK))#endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */) {LWIP_DEBUGF(IP_DEBUG, ("ip4_input: packet accepted on interface %c%c\n",netif->name[0], netif->name[1]));/* accept on this netif */return 1;}#if LWIP_AUTOIP/* 更改netif地址后,链路本地地址的连接必须保持(RFC3927 ch. 1.9) *//* 即是netif网卡地址更新为可路由地址了,原本本地链路地址的连接必须保持 , 所以数据包能得到当前网卡 。匹配成功 */if (autoip_accept_packet(netif, ip4_current_dest_addr())) {LWIP_DEBUGF(IP_DEBUG, ("ip4_input: LLA packet accepted on interface %c%c\n",netif->name[0], netif->name[1]));/* accept on this netif */return 1;}#endif /* LWIP_AUTOIP */}return 0;}
9.6 IP层数据流图文章插图
9.7 IP层输出ipv4 。
当上层需要发送数据时,会先将自己的数据包组装在一个pbuf中 。并将payload指针指向对应协议首部 。
然后调用
ip_output()
发送数据,需要给ip_output()
函数提供源IP、目的IP、协议类型、TTL等重要信息让其组IP包 。该函数直接或者间接调用
ip4_route_src()
根据目的IP选出一个匹配的网卡作为本次IP数据包传输网卡 。选出后调用
ip4_output_if()
进行IP数据包组包,并调用netif->output()
发送出去 。或者调用netif_loop_output()
环回到本网卡 。9.7.1 发送数据报上层调用
ip_output()
把数据转交给IP层处理 , lwip支持ipv4和ipv6,这里默认分析ipv4,因为ipv6也是一大块,后面有时间再完整分析下 。/** * @ingroup ip * Output IP packet, netif is selected by source address */#define ip_output(p, src, dest, ttl, tos, proto) \(IP_IS_V6(dest) ? \ip6_output(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto) : \ip4_output(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto))
9.7.2 ip层前期处理:ip4_output()ipv4发包:- 检查pbuf的引用ref是否为1 。为1才能说明当前pbuf没有被其它地方引用,因为IP层处理可能会改变这个pbuf的部分指针值,如payload 。
推荐阅读
- 【第5篇】AI语音简介
- 原神3.0陵薮市朝什么时间开启
- 【Azure 环境】把OpenSSL生产的自签名证书导入到Azure Key Vault Certificate中报错
- 常用类.String类
- cf如何跳上高箱子(cf开什么箱子赚cf点)
- macos monterey描述文件下载_macos monterey描述文件下载地址
- 浏览器怎样清除缓存(浏览器历史清空了怎么恢复)
- 我的世界豹猫怎么驯服,为什么给豹猫喂鱼之后不变成猫
- 支付宝蚂蚁庄园每日答题答案
- 原神90级提纳里毕业面板数值怎么样