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

  • 遍历网卡:
    • 有效网卡先匹配子网;
    • 子网匹配失败就匹配网关,网卡不能有广播能力 。
  • 环回IP:如果开启了各个网卡的环回功能,且没有创建环回网卡:
    • 说明:因为创建了环回网卡,在遍历链表时,就会把环回IP 127.x.x.x都会匹配到环回网卡 。
    • 对于环回IP,优先匹配默认网卡netif_default
    • 再遍历网卡,第一个协议栈有效的网卡即可 。
  • 钩子匹配:(由用户实现)
    • LWIP_HOOK_IP4_ROUTE_SRC(src, dest);
    • LWIP_HOOK_IP4_ROUTE(dest);
  • 以上都没有匹配成功,则使用netif_default,必须条件:
    • 默认网卡netif_default存在;
    • 默认网卡协议栈有效;
    • 默认网卡数据链路有效;
    • 默认网卡IP有效 。
    • 匹配的目的IP不能为环回IP(因为如果是环回IP,前面已经匹配过了,除非没有开启该功能)
  • /** * Finds the appropriate network interface for a given IP address. It * searches the list of network interfaces linearly. A match is found * if the masked IP address of the network interface equals the masked * IP address given to the function. * * @param dest the destination IP address for which to find the route * @return the netif on which to send to reach dest */struct netif *ip4_route(const ip4_addr_t *dest){#if !LWIP_SINGLE_NETIFstruct netif *netif;/* 确保在tcpip内核锁内 */LWIP_ASSERT_CORE_LOCKED();#if LWIP_MULTICAST_TX_OPTIONS /* 开启了组播TX功能 *//* 如果目的IP是一个组播地址,且协议栈内创建了组播专用网卡,则选用组播专用网卡接口 */if (ip4_addr_ismulticast(dest) && ip4_default_multicast_netif) {return ip4_default_multicast_netif;}#endif /* LWIP_MULTICAST_TX_OPTIONS *//* bug #54569: in case LWIP_SINGLE_NETIF=1 and LWIP_DEBUGF() disabled, the following loop is optimized away */LWIP_UNUSED_ARG(dest);/* 遍历网卡链表 */NETIF_FOREACH(netif) {/* 网卡协议栈有效,网卡链路层也有效,网卡的IP地址不为全0 */if (netif_is_up(netif) && netif_is_link_up(netif) && !ip4_addr_isany_val(*netif_ip4_addr(netif))) {/* 匹配传入的目的IP和网卡是否处于同一个子网 */if (ip4_addr_net_eq(dest, netif_ip4_addr(netif), netif_ip4_netmask(netif))) {/* 匹配成功 。返回netif,以转发IP数据包 */return netif;}/* 当前网卡子网匹配不成功 *//* 那就匹配下网关,匹配规则:网卡没有广播功能,目的IP和网关IP一致 。也算匹配成功,因为上层的目的是到网关 。当前网卡能把数据传达到网卡 。*/if (((netif->flags & NETIF_FLAG_BROADCAST) == 0) && ip4_addr_eq(dest, netif_ip4_gw(netif))) {/* 匹配成功 。返回netif,以转发IP数据包 */return netif;}}}/* 到这,遍历网卡,匹配失败 *//* 开启了环回功能,但是没有创建环回网卡 。(因为如果创建了环回网卡,在遍历网卡链表时就已经处理过了,这里不需要再处理) */#if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF/* 如果目的IP是一个环回IP地址,则优先返回默认网卡,否则返回网卡链表中第一个协议栈使能了的网卡作为当前环回网卡 */if (ip4_addr_isloopback(dest)) { /* 目的IP是一个环回IP */if ((netif_default != NULL) && netif_is_up(netif_default)) {/* 优先考虑默认网卡 。如果有默认网卡,且默认网卡协议栈使能了,则以此网卡作为本次环回网卡 */return netif_default;}/* 默认网卡没有匹配成功,则从网卡链表中找一个协议栈已使能的网卡作为本次环回网卡 */NETIF_FOREACH(netif) {if (netif_is_up(netif)) {return netif;}}return NULL; /* 都没找到,那就匹配失败 */}#endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */#ifdef LWIP_HOOK_IP4_ROUTE_SRC /* 如果开启了匹配网卡的钩子宏函数 */netif = LWIP_HOOK_IP4_ROUTE_SRC(NULL, dest); /* 使用宏钩子匹配 */if (netif != NULL) {return netif;}#elif defined(LWIP_HOOK_IP4_ROUTE) /* 网卡匹配钩子 */netif = LWIP_HOOK_IP4_ROUTE(dest); /* 使用宏钩子匹配 */if (netif != NULL) {return netif;}#endif#endif /* !LWIP_SINGLE_NETIF *//* 上述方案都无法匹配到网卡,就检查网卡网卡是否正常,正常则就返回默认网卡 */if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default) ||ip4_addr_isany_val(*netif_ip4_addr(netif_default)) || ip4_addr_isloopback(dest)) {LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));IP_STATS_INC(ip.rterr);MIB2_STATS_INC(mib2.ipoutnoroutes);return NULL;}return netif_default; /* 返回默认网络接口 */}

    经验总结扩展阅读