diff --git a/components/esp_netif/lwip/esp_netif_lwip.c b/components/esp_netif/lwip/esp_netif_lwip.c index 22f770869e..90adb76c43 100644 --- a/components/esp_netif/lwip/esp_netif_lwip.c +++ b/components/esp_netif/lwip/esp_netif_lwip.c @@ -378,11 +378,9 @@ esp_err_t esp_netif_bridge_add_port(esp_netif_t *esp_netif_br, esp_netif_t *esp_ esp_err_t esp_netif_bridge_fdb_add(esp_netif_t *esp_netif_br, uint8_t *addr, uint64_t ports_mask) { - bridgeif_portmask_t ports; - if (ports_mask == ESP_NETIF_BR_FDW_CPU) { - ports = 1 << BRIDGEIF_MAX_PORTS; - } else { - ports = (bridgeif_portmask_t)ports_mask; + bridgeif_portmask_t ports = (bridgeif_portmask_t)ports_mask; + if (ports_mask & ESP_NETIF_BR_FDW_CPU) { + ports |= 1 << BRIDGEIF_MAX_PORTS; } if (ERR_OK != bridgeif_fdb_add(esp_netif_br->lwip_netif, (const struct eth_addr *)addr, ports)) { diff --git a/examples/network/bridge/README.md b/examples/network/bridge/README.md index 680fe7c37f..78f63dfb36 100644 --- a/examples/network/bridge/README.md +++ b/examples/network/bridge/README.md @@ -72,10 +72,14 @@ idf.py -p PORT build flash monitor (Replace PORT with the name of the serial port to use.) -(To exit the serial monitor, type ``Ctrl-]``.) +(To exit the serial monitor, press ``Ctrl-]``.) See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. +### Forwarding Database Configuration + +You can configure bridge’s static Forwarding Database (FDB) via interactive console. Type ``help`` in the serial monitor to show available options. + ## Example Output **ESP32 output:** diff --git a/examples/network/bridge/main/CMakeLists.txt b/examples/network/bridge/main/CMakeLists.txt index 68d298a4ac..a86e4dbacc 100644 --- a/examples/network/bridge/main/CMakeLists.txt +++ b/examples/network/bridge/main/CMakeLists.txt @@ -1,2 +1,3 @@ idf_component_register(SRCS "bridge_example_main.c" + "bridge_console_cmd.c" INCLUDE_DIRS ".") diff --git a/examples/network/bridge/main/bridge_console_cmd.c b/examples/network/bridge/main/bridge_console_cmd.c new file mode 100644 index 0000000000..9b69f20eec --- /dev/null +++ b/examples/network/bridge/main/bridge_console_cmd.c @@ -0,0 +1,150 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include "esp_log.h" +#include "esp_check.h" +#include "esp_console.h" +#include "argtable3/argtable3.h" +#include "esp_eth_spec.h" +#include "bridge_console_cmd.h" + +typedef struct { + struct arg_str *addr; + struct arg_int *port; + struct arg_lit *drop; + struct arg_lit *flood; + struct arg_lit *cpu; + struct arg_end *end; +} br_add_fdb_args_t; + +typedef struct { + struct arg_str *addr; + struct arg_end *end; +} br_remove_fdb_args_t; + +static const char *TAG = "br_config_console"; + +static br_add_fdb_args_t s_add_args; +static br_remove_fdb_args_t s_remove_args; +static esp_netif_t *s_br_netif; +static uint8_t s_br_port_cnt; + +static esp_err_t str2mac(const char *str, uint8_t *mac_addr) +{ + unsigned int mac_tmp[ETH_ADDR_LEN]; + if (ETH_ADDR_LEN != sscanf(str, "%02x:%02x:%02x:%02x:%02x:%02x%*c", + &mac_tmp[0], &mac_tmp[1], &mac_tmp[2], + &mac_tmp[3], &mac_tmp[4], &mac_tmp[5])) { + return ESP_ERR_INVALID_MAC; + } + for (int i = 0; i < ETH_ADDR_LEN; i++) { + mac_addr[i] = (uint8_t)mac_tmp[i]; + } + return ESP_OK; +} + +static int cmd_br_fdb_add(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &s_add_args); + + if (nerrors != 0) { + arg_print_errors(stderr, s_add_args.end, argv[0]); + return 1; + } + + int exp_argc = 2; + if (s_add_args.port->count > 0) { + exp_argc += 2 * s_add_args.port->count; + if (s_add_args.cpu->count > 0) { + exp_argc++; + } + } else { + exp_argc++; + } + ESP_RETURN_ON_FALSE(argc == exp_argc, 1, TAG, "Invalid number or combination of arguments"); + + uint64_t port_mask = ESP_NETIF_BR_DROP; + for (int i = 0; i < s_add_args.port->count; i++) { + ESP_RETURN_ON_FALSE(s_add_args.port->ival[i] > 0 && s_add_args.port->ival[i] <= s_br_port_cnt, 1, TAG, "Invalid port number"); + port_mask |= 1 << ((uint64_t)(s_add_args.port->ival[i]) - 1); + } + if (s_add_args.drop->count > 0) { + port_mask = ESP_NETIF_BR_DROP; + } + if (s_add_args.flood->count > 0) { + port_mask = ESP_NETIF_BR_FLOOD; + } + if (s_add_args.cpu->count > 0) { + port_mask |= ESP_NETIF_BR_FDW_CPU; + } + uint8_t mac_addr[ETH_ADDR_LEN]; + ESP_RETURN_ON_FALSE(str2mac(s_add_args.addr->sval[0], mac_addr) == ESP_OK, + 1, TAG, "Ivalid MAC address format (expected xx:xx:xx:xx:xx:xx)"); + ESP_RETURN_ON_FALSE(esp_netif_bridge_fdb_add(s_br_netif, mac_addr, port_mask) == ESP_OK, + 1, TAG, "Adding FDB entry failed"); + + ESP_LOG_BUFFER_HEX_LEVEL(TAG, mac_addr, ETH_ADDR_LEN, ESP_LOG_DEBUG); + ESP_LOGD(TAG, "portmask 0x%" PRIu64 "\n", port_mask); + ESP_LOGI(TAG, "Bridge Config OK!"); + + return 0; +} + +static int cmd_br_fdb_remove(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &s_remove_args); + + if (nerrors != 0) { + arg_print_errors(stderr, s_remove_args.end, argv[0]); + return 1; + } + + uint8_t mac_addr[ETH_ADDR_LEN]; + ESP_RETURN_ON_FALSE(str2mac(s_remove_args.addr->sval[0], mac_addr) == ESP_OK, + 1, TAG, "Ivalid MAC address format (expected xx:xx:xx:xx:xx:xx)"); + ESP_RETURN_ON_FALSE(esp_netif_bridge_fdb_remove(s_br_netif, mac_addr) == ESP_OK, + 1, TAG, "Removing FDB entry failed"); + + ESP_LOG_BUFFER_HEX_LEVEL(TAG, mac_addr, ETH_ADDR_LEN, ESP_LOG_DEBUG); + ESP_LOGI(TAG, "Bridge Config OK!"); + return 0; +} + +void example_register_br_config_commands(esp_netif_t *br_netif, uint8_t br_port_cnt) +{ + ESP_LOGI(TAG, "Registering Bridge config commands."); + + s_add_args.addr = arg_str1(NULL, "addr", "", "MAC address to be added in expected xx:xx:xx:xx:xx:xx format"); + s_add_args.port = arg_intn("p", "port", "", 0, br_port_cnt + 1, "Forward to Port Number"); + s_add_args.drop = arg_lit0("d", "drop", "Drop"); + s_add_args.flood = arg_lit0("f", "flood", "Flood to all ports"); + s_add_args.cpu = arg_lit0("c", "cpu", "Forward to CPU"); + s_add_args.end = arg_end(2); + const esp_console_cmd_t br_add_fdb_cmd = { + .command = "add", + .help = "Add Forwarding Database entry", + .hint = NULL, + .func = &cmd_br_fdb_add, + .argtable = &s_add_args + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&br_add_fdb_cmd)); + + s_remove_args.addr = arg_str1(NULL, "addr", "", "MAC address to be removed in expected xx:xx:xx:xx:xx:xx format"); + s_remove_args.end = arg_end(1); + const esp_console_cmd_t br_remove_fdb_cmd = { + .command = "remove", + .help = "Remove Forwarding Database entry", + .hint = NULL, + .func = &cmd_br_fdb_remove, + .argtable = &s_remove_args + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&br_remove_fdb_cmd)); + + s_br_netif = br_netif; + s_br_port_cnt = br_port_cnt; +} diff --git a/examples/network/bridge/main/bridge_console_cmd.h b/examples/network/bridge/main/bridge_console_cmd.h new file mode 100644 index 0000000000..15dfc6db39 --- /dev/null +++ b/examples/network/bridge/main/bridge_console_cmd.h @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#pragma once + +#include +#include "esp_netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Register Bridge configuration commands +void example_register_br_config_commands(esp_netif_t *br_netif, uint8_t br_port_cnt); + +#ifdef __cplusplus +} +#endif diff --git a/examples/network/bridge/main/bridge_example_main.c b/examples/network/bridge/main/bridge_example_main.c index e0cd3f60c5..fe6054e419 100644 --- a/examples/network/bridge/main/bridge_example_main.c +++ b/examples/network/bridge/main/bridge_example_main.c @@ -16,6 +16,8 @@ #include "esp_mac.h" #include "ethernet_init.h" #include "sdkconfig.h" +#include "esp_console.h" +#include "bridge_console_cmd.h" static const char *TAG = "eth_bridge_example"; @@ -57,9 +59,9 @@ static void got_ip_event_handler(void *arg, esp_event_base_t event_base, ESP_LOGI(TAG, "Ethernet Got IP Address"); ESP_LOGI(TAG, "~~~~~~~~~~~"); - ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip)); - ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask)); - ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw)); + ESP_LOGI(TAG, "ETHIP:" IPSTR "\r", IP2STR(&ip_info->ip)); + ESP_LOGI(TAG, "ETHMASK:" IPSTR "\r", IP2STR(&ip_info->netmask)); + ESP_LOGI(TAG, "ETHGW:" IPSTR "\r", IP2STR(&ip_info->gw)); ESP_LOGI(TAG, "~~~~~~~~~~~"); } @@ -146,4 +148,16 @@ void app_main(void) // Start Ethernet driver state machine ESP_ERROR_CHECK(esp_eth_start(eth_handles[i])); } + + // --- Initialize Console --- + esp_console_repl_t *repl = NULL; + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + repl_config.prompt = "bridge>"; + + // install console REPL environment + esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl)); + example_register_br_config_commands(br_netif, eth_port_cnt); + // start console REPL + ESP_ERROR_CHECK(esp_console_start_repl(repl)); }