Page 1 of 1

Transparent ethernet bridge and ping to ESP32C6 module

Posted: Fri Jan 12, 2024 7:38 am
by endi83
Hello, I'm developing a project with the ESP32C6 module, which has two W5500 ethernets, with the aim that a device can send and receive data from a PC through this module via ethernet or wifi.

To do this, a transparent bridge has been made between the two ethernets (eth1/eth2) and another wifi bridge (eth1/wifi).

In addition, a static IP has been configured to the module so that I can connect to it and configure the module from a web with the selected static IP address.

Having made the eth1/eth2 bridge, the module is not able to answer the ping because everything it receives through eth1 is sent to eth2 automatically without looking if the packet it has received is really for it.

As it is not able to answer the ping I can't configure the module through the web.

Any idea how to solve this problem?

I attach an image with the schematic of the project and the code of the eth1 and eth2 configuration:
  1. static void initialize_ethernet(void)
  2. {
  3. uint8_t eth_port_cnt = 0;
  4. esp_eth_handle_t *eth_handles;
  5. eth_speed_t speed = ETH_SPEED_10M;
  6. eth_duplex_t duplex = ETH_DUPLEX_FULL;
  7. bool exp_autoneg_en = false, auto_nego_en = false;
  8.  
  9.     // Initialize Ethernet driver  
  10.     ESP_ERROR_CHECK(example_eth_init(&eth_handles, &eth_port_cnt));
  11.  
  12.     // The same MAC address will be used for all Ethernet ports since the bridge acts as one device
  13.     uint8_t common_mac_addr[ETH_ADDR_LEN] = {0x00, 0x08, 0xEF, 0x11, 0x22, 0x33}; //MAC Ethernet 1 fijo
  14.     // If internal Ethernet is not supported by ESP32x SoC, Locally Administered OUI address might be returned.
  15.     // Note that Locally Administered OUI range should be used only when testing on a LAN under your control!
  16.     for (int i = 0; i < eth_port_cnt; i++) {
  17.         ESP_ERROR_CHECK(esp_eth_ioctl(eth_handles[i], ETH_CMD_S_MAC_ADDR, common_mac_addr));
  18.     }
  19.  
  20.     // Initialize TCP/IP network interface
  21.     ESP_ERROR_CHECK(esp_netif_init());
  22.  
  23.     // Create instances of esp-netif for Ethernet ports
  24.     esp_netif_t **eth_netifs = calloc(eth_port_cnt, sizeof(esp_netif_t *));
  25.     esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH();
  26.     esp_netif_config_t netif_cfg = {
  27.         .base = &esp_netif_config,
  28.         .stack = ESP_NETIF_NETSTACK_DEFAULT_ETH,
  29.     };
  30.     char if_key_str[10];
  31.     char if_desc_str[10];
  32.     char num_str[3];
  33.     for (int i = 0; i < eth_port_cnt; i++) {
  34.         itoa(i, num_str, 10);
  35.         strcat(strcpy(if_key_str, "ETH_"), num_str);
  36.         strcat(strcpy(if_desc_str, "eth"), num_str);
  37.         esp_netif_config.if_key = if_key_str;
  38.         esp_netif_config.if_desc = if_desc_str;
  39.         esp_netif_config.route_prio = 50 - i;
  40.         esp_netif_config.flags = 0; // esp-netif flags need to be zero when port's to be bridged
  41.  
  42.         eth_netifs[i] = esp_netif_new(&netif_cfg);
  43.  
  44.         esp_netif_ip_info_t ip_info;
  45.            
  46.         esp_netif_dhcpc_stop(eth_netif);
  47.         IP4_ADDR(&ip_info.ip, 192, 168, 10, 1);
  48.         IP4_ADDR(&ip_info.netmask, 255, 255, 255, 0);
  49.         IP4_ADDR(&ip_info.gw, 192, 168, 10, 254);
  50.  
  51.         esp_netif_set_ip_info(eth_netifs[i], &ip_info);
  52.  
  53.         // Attach Ethernet driver to TCP/IP stack
  54.         ESP_ERROR_CHECK(esp_netif_attach(eth_netifs[i], esp_eth_new_netif_glue(eth_handles[i])));
  55.     }
  56.  
  57.     // Create instance of esp-netif for bridge interface
  58.     esp_netif_inherent_config_t esp_netif_br_config = ESP_NETIF_INHERENT_DEFAULT_BR();
  59.     esp_netif_config_t netif_br_cfg = {
  60.         .base = &esp_netif_br_config,
  61.         .stack = ESP_NETIF_NETSTACK_DEFAULT_BR,
  62.     };
  63.     // Bridge configuration
  64.     bridgeif_config_t bridgeif_config = {
  65.         .max_fdb_dyn_entries = 10, // maximum number of address entries in dynamic forwarding database
  66.         .max_fdb_sta_entries = 2,  // maximum number of address entries in static forwarding database
  67.         .max_ports = eth_port_cnt  // maximum number of ports the bridge can consist of
  68.     };
  69.     esp_netif_br_config.bridge_info = &bridgeif_config;
  70.     // Set MAC address of bridge interface the same as the Ethernet interface
  71.     memcpy(esp_netif_br_config.mac, common_mac_addr, ETH_ADDR_LEN);
  72.     esp_netif_t *br_netif = esp_netif_new(&netif_br_cfg);
  73.  
  74.     // Create new esp netif bridge glue instance
  75.     esp_netif_br_glue_handle_t netif_br_glue = esp_netif_br_glue_new();
  76.     // Add Ethernet port interfaces to that esp netif bridge glue instance
  77.     for (int i = 0; i < eth_port_cnt; i++) {
  78.         ESP_ERROR_CHECK(esp_netif_br_glue_add_port(netif_br_glue, eth_netifs[i]));
  79.     }
  80.     // Attach esp netif bridge glue instance with added ports to bridge netif
  81.     ESP_ERROR_CHECK(esp_netif_attach(br_netif, netif_br_glue));
  82.  
  83.     // Register user defined event handers
  84.     ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL));
  85.    
  86.     for (int i = 0; i < eth_port_cnt; i++) {
  87.         // Since the MAC forwarding is performed in lwIP bridge, we need to pass all addresses through the Ethernet MACs
  88.         bool promiscuous = true;
  89.  
  90.         //ESP_ERROR_CHECK(esp_eth_update_input_path(eth_handles[i], pkt_eth2wifi, NULL));
  91.         esp_eth_ioctl(eth_handles[i], ETH_CMD_S_PROMISCUOUS, &promiscuous);
  92.    
  93.     // Disable autonegotiation and change speed to 10 Mbps and full duplex
  94.         ESP_LOGI(TAG, "disable the autonegotiation and change the speed/duplex...");
  95.         ESP_ERROR_CHECK(esp_eth_ioctl(eth_handles[i], ETH_CMD_S_AUTONEGO, &auto_nego_en));
  96.         ESP_ERROR_CHECK(esp_eth_ioctl(eth_handles[i], ETH_CMD_G_AUTONEGO, &exp_autoneg_en));
  97.    
  98.     // set new duplex mode
  99.         ESP_ERROR_CHECK(esp_eth_ioctl(eth_handles[i], ETH_CMD_S_DUPLEX_MODE, &duplex));
  100.  
  101.     // set new speed
  102.         ESP_ERROR_CHECK(esp_eth_ioctl(eth_handles[i], ETH_CMD_S_SPEED, &speed));
  103.    
  104.         s_eth_handle[i] = eth_handles[i];
  105.         // Start Ethernet driver state machine
  106.         ESP_ERROR_CHECK(esp_eth_start(eth_handles[i]));
  107.     }
  108.    
  109.     // --- Initialize Console ---
  110.     esp_console_repl_t *repl = NULL;
  111.     esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
  112.     repl_config.prompt = "bridge>";
  113.  
  114.     // install console REPL environment
  115.     esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
  116.     ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl));
  117.     example_register_br_config_commands(br_netif, eth_port_cnt);
  118.     // start console REPL
  119.     ESP_ERROR_CHECK(esp_console_start_repl(repl));
  120. }
Thank you very much.

Re: Transparent ethernet bridge and ping to ESP32C6 module

Posted: Mon Jan 15, 2024 9:10 am
by endi83
I have separated the ethernet configuration into two instances. The first instance to get the bridge between eth1/eth2 and the second to select a static IP for eth2.

I have managed to ping the ESP32 (static IP) from the PC if I only connect eth2 to the ESP32. When I connect eth1 I see that it keeps pinging the static IP and that the eth1/eth2 bridge works correctly BUT after a few seconds I lose the ping. However, I have seen that if I continuously call the static IP of the module from a web browser, it does not lose the ping and the eth1/eth2 bridge continues to work.

It seems as if the instance that programmed the static IP went into sleep mode for some reason.

How could I manage two instances at the same time on eth2?

I would really appreciate your help and sorry for my english.

I update the eth1 and eth2 configuration code:
  1. static void initialize_ethernet(void)
  2. {
  3. uint8_t eth_port_cnt = 0;
  4. esp_eth_handle_t *eth_handles;
  5. eth_speed_t speed = ETH_SPEED_100M;
  6. eth_duplex_t duplex = ETH_DUPLEX_FULL;
  7. bool exp_autoneg_en = false, auto_nego_en = false;
  8.  
  9.     // Initialize Ethernet driver  
  10.     ESP_ERROR_CHECK(example_eth_init(&eth_handles, &eth_port_cnt));
  11.  
  12.     // The same MAC address will be used for all Ethernet ports since the bridge acts as one device
  13.     uint8_t common_mac_addr[ETH_ADDR_LEN] = {0x00, 0x08, 0xEF, 0x11, 0x22, 0x33}; //MAC Ethernet 1 fijo
  14.     // If internal Ethernet is not supported by ESP32x SoC, Locally Administered OUI address might be returned.
  15.     // Note that Locally Administered OUI range should be used only when testing on a LAN under your control!
  16.     for (int i = 0; i < eth_port_cnt; i++) {
  17.         ESP_ERROR_CHECK(esp_eth_ioctl(eth_handles[i], ETH_CMD_S_MAC_ADDR, common_mac_addr));
  18.     }
  19.  
  20.     // Initialize TCP/IP network interface
  21.     ESP_ERROR_CHECK(esp_netif_init());
  22.  
  23.     // Create instances of esp-netif for Ethernet ports
  24.     esp_netif_t **eth_netifs = calloc(eth_port_cnt, sizeof(esp_netif_t *)); //QUITAR COMENTARIO
  25.     esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH();
  26.     esp_netif_config_t netif_cfg = {
  27.         .base = &esp_netif_config,
  28.         .stack = ESP_NETIF_NETSTACK_DEFAULT_ETH,
  29.     };
  30.     char if_key_str[10];
  31.     char if_desc_str[10];
  32.     char num_str[3];
  33.     for (int i = 0; i < eth_port_cnt; i++) {
  34.         itoa(i, num_str, 10);
  35.         strcat(strcpy(if_key_str, "ETH_"), num_str);
  36.         strcat(strcpy(if_desc_str, "eth"), num_str);
  37.         esp_netif_config.if_key = if_key_str;
  38.         esp_netif_config.if_desc = if_desc_str;
  39.         esp_netif_config.route_prio = 50 - i;
  40.         esp_netif_config.flags = 0; // esp-netif flags need to be zero when port's to be bridged
  41.  
  42.         eth_netifs[i] = esp_netif_new(&netif_cfg);
  43.  
  44.         // Attach Ethernet driver to TCP/IP stack
  45.         ESP_ERROR_CHECK(esp_netif_attach(eth_netifs[i], esp_eth_new_netif_glue(eth_handles[i])));
  46.     }
  47.  
  48.     // Create instance of esp-netif for bridge interface
  49.     esp_netif_inherent_config_t esp_netif_br_config = ESP_NETIF_INHERENT_DEFAULT_BR();
  50.     esp_netif_config_t netif_br_cfg = {
  51.         .base = &esp_netif_br_config,
  52.         .stack = ESP_NETIF_NETSTACK_DEFAULT_BR,
  53.     };
  54.     // Bridge configuration
  55.     bridgeif_config_t bridgeif_config = {
  56.         .max_fdb_dyn_entries = 10, // maximum number of address entries in dynamic forwarding database
  57.         .max_fdb_sta_entries = 2,  // maximum number of address entries in static forwarding database
  58.         .max_ports = eth_port_cnt  // maximum number of ports the bridge can consist of
  59.     };
  60.     esp_netif_br_config.bridge_info = &bridgeif_config;
  61.     // Set MAC address of bridge interface the same as the Ethernet interface
  62.     memcpy(esp_netif_br_config.mac, common_mac_addr, ETH_ADDR_LEN);
  63.     esp_netif_t *br_netif = esp_netif_new(&netif_br_cfg);
  64.  
  65.     // Create new esp netif bridge glue instance
  66.     esp_netif_br_glue_handle_t netif_br_glue = esp_netif_br_glue_new();
  67.     // Add Ethernet port interfaces to that esp netif bridge glue instance
  68.     for (int i = 0; i < eth_port_cnt; i++) {
  69.         ESP_ERROR_CHECK(esp_netif_br_glue_add_port(netif_br_glue, eth_netifs[i]));
  70.     }
  71.     // Attach esp netif bridge glue instance with added ports to bridge netif
  72.     ESP_ERROR_CHECK(esp_netif_attach(br_netif, netif_br_glue));
  73.  
  74.     // Use ESP_NETIF_INHERENT_DEFAULT_ETH when multiple Ethernet interfaces are used and so you need to modify
  75.     // esp-netif configuration parameters for each interface (name, priority, etc.).
  76.     esp_netif_inherent_config_t esp_netif_ext = ESP_NETIF_INHERENT_DEFAULT_ETH();
  77.     esp_netif_config_t cfg_ext = {
  78.         .base = &esp_netif_ext,
  79.         .stack = ESP_NETIF_NETSTACK_DEFAULT_ETH
  80.     };
  81.  
  82.     esp_netif_ext.if_key = "ETH_2";
  83.     esp_netif_ext.if_desc = "eth2";
  84.     esp_netif_ext.route_prio = 50;
  85.  
  86.     esp_netif_t *eth_netif = esp_netif_new(&cfg_ext);
  87.  
  88.     esp_netif_ip_info_t ip_info;
  89.     // Attach Ethernet driver to TCP/IP stack
  90.     esp_netif_dhcpc_stop(eth_netif);
  91.     IP4_ADDR(&ip_info.ip, 192, 168, 10, 1);
  92.     IP4_ADDR(&ip_info.netmask, 255, 255, 255, 0);
  93.     IP4_ADDR(&ip_info.gw, 192, 168, 10, 254);
  94.  
  95.     esp_netif_set_ip_info(eth_netif, &ip_info);
  96.     //s_eth_handle[1] = eth_handles[1];
  97.     // Attach Ethernet driver to TCP/IP stack
  98.     ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[1])));
  99.  
  100.     // Register user defined event handers
  101.     ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL));
  102.  
  103.     for (int i = 0; i < eth_port_cnt; i++) {
  104.         // Since the MAC forwarding is performed in lwIP bridge, we need to pass all addresses through the Ethernet MACs
  105.         bool promiscuous = true;
  106.  
  107.         //ESP_ERROR_CHECK(esp_eth_update_input_path(eth_handles[i], pkt_eth2wifi, NULL));
  108.         esp_eth_ioctl(eth_handles[i], ETH_CMD_S_PROMISCUOUS, &promiscuous);
  109.    
  110.     // Disable autonegotiation and change speed to 100 Mbps and full duplex
  111.         ESP_LOGI(TAG, "disable the autonegotiation and change the speed/duplex...");
  112.         ESP_ERROR_CHECK(esp_eth_ioctl(eth_handles[i], ETH_CMD_S_AUTONEGO, &auto_nego_en));
  113.         ESP_ERROR_CHECK(esp_eth_ioctl(eth_handles[i], ETH_CMD_G_AUTONEGO, &exp_autoneg_en));
  114.    
  115.     // set new duplex mode
  116.         ESP_ERROR_CHECK(esp_eth_ioctl(eth_handles[i], ETH_CMD_S_DUPLEX_MODE, &duplex));
  117.  
  118.     // set new speed
  119.         ESP_ERROR_CHECK(esp_eth_ioctl(eth_handles[i], ETH_CMD_S_SPEED, &speed));
  120.    
  121.         s_eth_handle[i] = eth_handles[i];
  122.         // Start Ethernet driver state machine
  123.         ESP_ERROR_CHECK(esp_eth_start(eth_handles[i]));
  124.     }
  125.    
  126.     // --- Initialize Console ---
  127.     esp_console_repl_t *repl = NULL;
  128.     esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
  129.     repl_config.prompt = "bridge>";
  130.  
  131.     // install console REPL environment
  132.     esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
  133.     ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl));
  134.     example_register_br_config_commands(br_netif, eth_port_cnt);
  135.     // start console REPL
  136.     ESP_ERROR_CHECK(esp_console_start_repl(repl));
  137. }

Re: Transparent ethernet bridge and ping to ESP32C6 module

Posted: Mon Jan 15, 2024 6:24 pm
by ESP_ondrej
If I understand it correctly you want to have both Ethernet interfaces to be bridged but, at the same time, to the Ethernet interface has its own IP address. Am I right? You cannot attach multiple netifs to single network interface. The correct way is to create netif for each interface and then add (group) these interfaces netifs under "bridge" netif. Bridging is performed at L2 (MAC addresses). You can assign IP address to the bridge netif to be able to connect to ESP32 device and manage it.

Re: Transparent ethernet bridge and ping to ESP32C6 module

Posted: Mon Jan 22, 2024 8:28 am
by endi83
Thanks to your comment I managed to solve the problem. I can make a bridge between the two ethernets and I can also connect to the web browser via the IP selected in the bridge.

Thank you very much for your help!