ESP32 双网卡时默认路由选择机制分析

由于 ESP32 可以同时使用以太网和 Wi-Fi 接入网络,此篇博客用来分析 ESP32 双网卡(Wi-Fi & 以太网同时存在)时使用 TCP 等协议通信会使用哪个 IP。此处会以 websocket 例程为例进行测试分析。

注:对应的 IDF commit 为 c9646ff0b (HEAD, tag: v4.3) versions: Update version to 4.3.0。

1 环境配置

打开终端,按照 ESP-IDF 编程指南 搭建 IDF 环境,然后在工程对应的终端下输入 idf.py menuconfig,在 menuconfig -> Example Connection Configuration 里同时使能 Wi-Fi 和 ETH,配置 Wi-Fi 的 SSID & Password 以及以太网相关配置,如下:

在这里插入图片描述

注:由于此处使用的硬件是 ESP32 以太网开发板 ESP32-Ethernet-Kit,故以太网相关 menuconfig 使用默认配置即可。

为了方便测试,在这里同时在 menuconfig -> Component config -> LWIP -> Enable LWIP Debug 里开启 LWIP IP debug 来查看实际通信时用的具体 IP,如下:
在这里插入图片描述
配置完成后,就可以烧录 websocket 例程进行测试了。

2 初步测试

按上述配置编译烧写例程后,相关 log 如下:

I (5626) esp_netif_handlers: example_connect: eth ip: 192.168.1.90, mask: 255.255.255.0, gw: 192.168.1.1
I (5626) example_connect: Got IPv4 event: Interface "example_connect: eth" address: 192.168.1.90
I (6626) example_connect: Got IPv6 event: Interface "example_connect: eth" address: fe80:0000:0000:0000:7e9e:bdff:fee1:744b, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (6626) example_connect: Connected to example_connect: eth
I (6636) example_connect: - IPv4 address: 192.168.1.90
I (6636) example_connect: - IPv6 address: fe80:0000:0000:0000:7e9e:bdff:fee1:744b, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (6656) example_connect: Connected to example_connect: sta
I (6656) example_connect: - IPv4 address: 192.168.1.87
I (6666) example_connect: - IPv6 address: fe80:0000:0000:0000:7e9e:bdff:fee1:7448, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (6676) WEBSOCKET: Connecting to ws://echo.websocket.org...
| 4 | 5 |  0x00 |        40     | (v, hl, tos, len)
+-------------------------------+
|    11691      |010|       0   | (id, flags, offset)
+-------------------------------+
|   43  |    6  |    0xd15a     | (ttl, proto, chksum)
+-------------------------------+
|  174  |  129  |  224  |   73  | (src)
+-------------------------------+
|  192  |  168  |    1  |   87  | (dest)
+-------------------------------+
ip4_input: p->len 40 p->tot_len 40
ip4_output_if: st1
IP header:
+-------------------------------+
| 4 | 5 |  0x00 |        50     | (v, hl, tos, len)
+-------------------------------+
|       10      |000|       0   | (id, flags, offset)
+-------------------------------+
|  255  |    6  |    0x6af1     | (ttl, proto, chksum)
+-------------------------------+
|  192  |  168  |    1  |   87  | (src)
+-------------------------------+
|  174  |  129  |  224  |   73  | (dest)
+-------------------------------+
ip4_output_if: call netif->output()
I (12226) WEBSOCKET: Sending hello 0001
I (12726) WEBSOCKET: Sending hello 0002

可以看到此时的 Wi-Fi sta 的 ip 为 192.168.1.87,ETH 的 ip 为 192.168.1.90。实际进行 websocket 通信时使用的 ip 为 192.168.1.87,测试了好几次发现都是优先使用 Wi-Fi ip 进行 websocket 通信。查阅资料后发现当 ESP32 双网卡时通信优先级是由 esp_netif_t 结构体里的 route_prio 决定的,哪个网卡的 route_prio 高就会优先被用于通信。

3 进阶分析

此时通过 esp_netif_get_route_prio() 查看 websocket 例程中 Wi-Fi 和 ETH 的默认 route_prio,相关代码如下:

  1. 查看 Wi-Fi 部分的 route_prio
    在这里插入图片描述
  2. 查看 ETH 部分的 route_prio
    在这里插入图片描述

注:esp_netif 结构体是内部的,不能直接打印对应的结构体成员变量的值,可以调用 esp_netif_get_route_prio() 查看该值。

加入上述代码后,继续编译烧写示例,log 如下:

W (726) example_connect: ----------------wifi route_prio = 128
I (736) example_connect: Connecting to zztest...
I (736) phy_init: phy_version 4670,719f9f6,Feb 18 2021,17:07:07
I (846) wifi:mode : sta (7c:9e:bd:e1:74:48)
I (846) wifi:enable tsf
W (846) example_connect: ----------------ETH route_prio = 64
I (6626) example_connect: Connected to example_connect: eth
I (6636) example_connect: - IPv4 address: 192.168.1.90
I (6636) example_connect: - IPv6 address: fe80:0000:0000:0000:7e9e:bdff:fee1:744b, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (6646) example_connect: Connected to example_connect: sta
I (6656) example_connect: - IPv4 address: 192.168.1.87
I (6666) example_connect: - IPv6 address: fe80:0000:0000:0000:7e9e:bdff:fee1:7448, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (6676) WEBSOCKET: Connecting to ws://echo.websocket.org...
+-------------------------------+
| 4 | 5 |  0x00 |        46     | (v, hl, tos, len)
+-------------------------------+
|        9      |000|       0   | (id, flags, offset)
+-------------------------------+
|  255  |    6  |    0x6af6     | (ttl, proto, chksum)
+-------------------------------+
|  192  |  168  |    1  |   87  | (src)
+-------------------------------+
|  174  |  129  |  224  |   73  | (dest)
+-------------------------------+
ip4_output_if: call netif->output()
ip_input: iphdr->dest 0x5701a8c0 netif->ip_addr 0x5701a8c0 (0x1a8c0, 0x1a8c0, 0x57000000)
ip4_input: packet accepted on interface st
ip4_input: 
IP header:
+-------------------------------+
| 4 | 5 |  0x00 |        40     | (v, hl, tos, len)
+-------------------------------+
|    12173      |010|       0   | (id, flags, offset)
+-------------------------------+
|   31  |    6  |    0xdb78     | (ttl, proto, chksum)
+-------------------------------+
|  174  |  129  |  224  |   73  | (src)
+-------------------------------+
|  192  |  168  |    1  |   87  | (dest)
+-------------------------------+
ip4_input: p->len 40 p->tot_len 40
I (8716) WEBSOCKET: Sending hello 0001

可以看到:

  • Wi-Fi sta 的 route_prio 为 128,ETH 的 route_prio 为 64,此时 Wi-Fi sta 的优先级更高
  • Wi-Fi sta 的 ip 为 192.168.1.87,ETH 的 ip 为 192.168.1.90。实际进行 websocket 通信时使用的 ip 为 192.168.1.87,为 Wi-Fi sta 的 ip,与上述优先级结果吻合

此时可以尝试修改 ETH esp_netif_inherent_config_t 里的 route_prio 参数来观察是否能让 ETH 被优先使用,将 ETH 的优先级设置为 200(Wi-Fi sta 的 route_prio 此时为 128),如下:
在这里插入图片描述
继续编译烧写例程,log 如下:

W (726) example_connect: ----------------wifi route_prio = 128
I (736) example_connect: Connecting to zztest...
I (736) phy_init: phy_version 4670,719f9f6,Feb 18 2021,17:07:07
I (836) wifi:mode : sta (7c:9e:bd:e1:74:48)
I (836) wifi:enable tsf
W (846) example_connect: ----------------ETH route_prio = 200
I (6626) example_connect: Connected to example_connect: eth
I (6636) example_connect: - IPv4 address: 192.168.1.90
I (6636) example_connect: - IPv6 address: fe80:0000:0000:0000:7e9e:bdff:fee1:744b, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (6656) example_connect: Connected to example_connect: sta
I (6656) example_connect: - IPv4 address: 192.168.1.87
I (6666) example_connect: - IPv6 address: fe80:0000:0000:0000:7e9e:bdff:fee1:7448, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (6676) WEBSOCKET: Connecting to ws://echo.websocket.org...
+-------------------------------+
| 4 | 5 |  0x00 |       241     | (v, hl, tos, len)
+-------------------------------+
|    17973      |010|       0   | (id, flags, offset)
+-------------------------------+
|   32  |    6  |    0xc304     | (ttl, proto, chksum)
+-------------------------------+
|  174  |  129  |  224  |   73  | (src)
+-------------------------------+
|  192  |  168  |    1  |   90  | (dest)
+-------------------------------+
ip4_input: p->len 241 p->tot_len 241
I (7586) WEBSOCKET: WEBSOCKET_EVENT_CONNECTED
I (7686) WEBSOCKET: Sending hello 0000
ip4_output_if: en2
IP header:
+-------------------------------+
| 4 | 5 |  0x00 |        46     | (v, hl, tos, len)
+-------------------------------+
|        8      |000|       0   | (id, flags, offset)
+-------------------------------+
|  255  |    6  |    0x6af4     | (ttl, proto, chksum)
+-------------------------------+
|  192  |  168  |    1  |   90  | (src)
+-------------------------------+
|  174  |  129  |  224  |   73  | (dest)
+-------------------------------+

可以看到:

  • Wi-Fi sta 的 route_prio 为 128,ETH 的 route_prio 为 200,此时 ETH 的优先级更高
  • Wi-Fi sta 的 ip 为 192.168.1.87,ETH 的 ip 为 192.168.1.90。实际进行 websocket 通信时使用的 ip 为 192.168.1.90,为 ETH 的 ip,与上述优先级结果吻合。

此时可以证明成功通过增大 ETH 优先级来让 ESP32 优先以以太网的形式通信。

4 附录

后续做了更多的相关测试,此处总结了双网卡时默认路由如何选择,以 ETH 和 STA 为例:

  1. 当 ETH 和 STA 在同一个局域网,设备访问局域网地址时,数据走最后 up 的 netif; 设备访问非局域网内地址时,数据走 route_prio 值大的 netif。
  2. 当 ETH 和 STA 不在一个局域网里面,ETH 属于 192.168.3.x 网段, sta 属于 192.168.2.x 网段,设备访问 192.168.3.5 时,就会走 ETH netif; 设备访问 192.168.2.5 时,就会走 STA netif;设备访问 10.10.10.10 时,就会走默认路由(route_prio 值大的 netif)。
    netif 起来后,会根据 route_prio 值大小设置默认路由,默认路由往往是 route_prio 值大的 netif。当设备访问的地址不在路由表里面,数据就会走默认路由。

注:上述第一点中设备访问局域网地址时判定最后 up 的 netif 的方法是查看 connect.c 示例中 start() 函数里的 wifi_start()eth_start() 的先后调用顺序,使用最后配置完成的 netif。

  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值