【lwip】09-IPv4协议&超全源码实现分析( 六 )

9.5.4 路由网卡匹配的钩子函数通过分析前面的基函数和接口函数,可发现其实现是支持宏钩子函数,即是支持用户自己实现网卡匹配的逻辑的 。
有两个宏钩子:

  • LWIP_HOOK_IP4_ROUTE_SRC(src, dest):钩子入口参数有源IP和目的IP 。
  • LWIP_HOOK_IP4_ROUTE(dest):钩子入口参数只有目的IP 。
9.5.5 收包网卡匹配当IP层收到一个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层数据流图
【lwip】09-IPv4协议&超全源码实现分析

文章插图
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发包: