Skip to content

Commit bfcae33

Browse files
committed
Hot path performance optimizations, remote console mem dynamic
1 parent 5527364 commit bfcae33

31 files changed

Lines changed: 190 additions & 100 deletions

components/acl/acl.c

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ static acl_stats_t acl_stats[MAX_ACL_LISTS];
5959
/* Mutex protecting acl_lists and acl_stats from concurrent access */
6060
static SemaphoreHandle_t acl_mutex = NULL;
6161

62+
/* Per-list rule count - written under acl_mutex, read lock-free in hot path */
63+
static volatile uint8_t acl_rule_count[MAX_ACL_LISTS];
64+
6265
void acl_init(void)
6366
{
6467
if (acl_mutex == NULL) {
@@ -67,6 +70,7 @@ void acl_init(void)
6770
}
6871
memset(acl_lists, 0, sizeof(acl_lists));
6972
memset(acl_stats, 0, sizeof(acl_stats));
73+
memset((void *)acl_rule_count, 0, sizeof(acl_rule_count));
7074
ESP_LOGI(TAG, "ACL subsystem initialized");
7175
}
7276

@@ -84,39 +88,20 @@ void acl_unlock(void)
8488
}
8589
}
8690

87-
bool acl_is_empty(uint8_t acl_no)
91+
IRAM_ATTR bool acl_is_empty(uint8_t acl_no)
8892
{
8993
if (acl_no >= MAX_ACL_LISTS) {
9094
return true;
9195
}
92-
93-
bool empty = true;
94-
acl_lock();
95-
for (int i = 0; i < MAX_ACL_ENTRIES; i++) {
96-
if (acl_lists[acl_no][i].valid) {
97-
empty = false;
98-
break;
99-
}
100-
}
101-
acl_unlock();
102-
return empty;
96+
return acl_rule_count[acl_no] == 0;
10397
}
10498

10599
int acl_get_count(uint8_t acl_no)
106100
{
107101
if (acl_no >= MAX_ACL_LISTS) {
108102
return 0;
109103
}
110-
111-
acl_lock();
112-
int count = 0;
113-
for (int i = 0; i < MAX_ACL_ENTRIES; i++) {
114-
if (acl_lists[acl_no][i].valid) {
115-
count++;
116-
}
117-
}
118-
acl_unlock();
119-
return count;
104+
return acl_rule_count[acl_no];
120105
}
121106

122107
void acl_clear(uint8_t acl_no)
@@ -127,6 +112,7 @@ void acl_clear(uint8_t acl_no)
127112

128113
acl_lock();
129114
memset(acl_lists[acl_no], 0, sizeof(acl_lists[acl_no]));
115+
acl_rule_count[acl_no] = 0;
130116
acl_unlock();
131117
ESP_LOGI(TAG, "Cleared ACL list %s", acl_names[acl_no]);
132118
}
@@ -185,6 +171,7 @@ bool acl_add(uint8_t acl_no, uint32_t src, uint32_t s_mask,
185171
entry->allow = allow;
186172
entry->hit_count = 0;
187173
entry->valid = 1;
174+
acl_rule_count[acl_no]++;
188175

189176
acl_unlock();
190177
ESP_LOGI(TAG, "Added rule %d to ACL %s", slot, acl_names[acl_no]);
@@ -216,6 +203,9 @@ bool acl_delete(uint8_t acl_no, uint8_t rule_idx)
216203
break;
217204
}
218205
}
206+
if (acl_rule_count[acl_no] > 0) {
207+
acl_rule_count[acl_no]--;
208+
}
219209

220210
acl_unlock();
221211
ESP_LOGI(TAG, "Deleted rule %d from ACL %s", rule_idx, acl_names[acl_no]);
@@ -228,7 +218,7 @@ bool acl_delete(uint8_t acl_no, uint8_t rule_idx)
228218
#define ETH_TYPE_ARP 0x0806
229219
#define ETH_TYPE_IPV6 0x86DD
230220

231-
uint8_t acl_check_packet(uint8_t acl_no, struct pbuf *p)
221+
IRAM_ATTR uint8_t acl_check_packet(uint8_t acl_no, struct pbuf *p)
232222
{
233223
if (acl_no >= MAX_ACL_LISTS || p == NULL) {
234224
return ACL_NO_MATCH;

components/cmd_router/cmd_router.c

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static void register_set_led_gpio(void);
8080
static void register_set_led_lowactive(void);
8181
static void register_set_led_strip(void);
8282
static void register_set_ttl(void);
83+
static void register_client_stats_cmd(void);
8384
static void register_set_tx_power(void);
8485
#if defined(CONFIG_IDF_TARGET_ESP32C6)
8586
static void register_set_rf_switch(void);
@@ -297,6 +298,7 @@ void register_router(void)
297298
register_set_led_lowactive();
298299
register_set_led_strip();
299300
register_set_ttl();
301+
register_client_stats_cmd();
300302
register_set_tx_power();
301303
register_set_ap_hidden();
302304
register_set_ap_auth();
@@ -1294,13 +1296,18 @@ static int show(int argc, char **argv)
12941296
int count = get_connected_clients(clients, 8);
12951297

12961298
if (count > 0) {
1297-
// Fetch per-client traffic stats
1299+
// Fetch per-client traffic stats only when enabled
12981300
client_stats_entry_t stats[CLIENT_STATS_MAX];
1299-
int stats_count = client_stats_get_all(stats, CLIENT_STATS_MAX);
1301+
int stats_count = client_stats_enabled ? client_stats_get_all(stats, CLIENT_STATS_MAX) : 0;
13001302

13011303
printf("\nClient Details:\n");
1302-
printf("MAC Address IP Address Device Name TX / RX\n");
1303-
printf("---------------- --------------- ------------------- ------------------\n");
1304+
if (client_stats_enabled) {
1305+
printf("MAC Address IP Address Device Name TX / RX\n");
1306+
printf("---------------- --------------- ------------------- ------------------\n");
1307+
} else {
1308+
printf("MAC Address IP Address Device Name\n");
1309+
printf("---------------- --------------- -------------------\n");
1310+
}
13041311

13051312
for (int i = 0; i < count; i++) {
13061313
char mac_str[18];
@@ -1315,19 +1322,21 @@ static int show(int argc, char **argv)
13151322
sprintf(ip_str, IPSTR, IP2STR(&addr));
13161323
}
13171324

1318-
// Find matching traffic stats by MAC
1319-
char traffic_str[32] = "-";
1320-
for (int j = 0; j < stats_count; j++) {
1321-
if (memcmp(stats[j].mac, clients[i].mac, 6) == 0) {
1322-
char tx_buf[12], rx_buf[12];
1323-
format_bytes_human(stats[j].bytes_sent, tx_buf, sizeof(tx_buf));
1324-
format_bytes_human(stats[j].bytes_received, rx_buf, sizeof(rx_buf));
1325-
snprintf(traffic_str, sizeof(traffic_str), "%s / %s", tx_buf, rx_buf);
1326-
break;
1325+
if (client_stats_enabled) {
1326+
char traffic_str[32] = "-";
1327+
for (int j = 0; j < stats_count; j++) {
1328+
if (memcmp(stats[j].mac, clients[i].mac, 6) == 0) {
1329+
char tx_buf[12], rx_buf[12];
1330+
format_bytes_human(stats[j].bytes_sent, tx_buf, sizeof(tx_buf));
1331+
format_bytes_human(stats[j].bytes_received, rx_buf, sizeof(rx_buf));
1332+
snprintf(traffic_str, sizeof(traffic_str), "%s / %s", tx_buf, rx_buf);
1333+
break;
1334+
}
13271335
}
1336+
printf("%-17s %-15s %-19s %s\n", mac_str, ip_str, clients[i].name, traffic_str);
1337+
} else {
1338+
printf("%-17s %-15s %s\n", mac_str, ip_str, clients[i].name);
13281339
}
1329-
1330-
printf("%-17s %-15s %-19s %s\n", mac_str, ip_str, clients[i].name, traffic_str);
13311340
}
13321341
}
13331342
}
@@ -2073,6 +2082,46 @@ static void register_set_ttl(void)
20732082
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
20742083
}
20752084

2085+
/* 'client_stats' command - enable/disable per-client traffic statistics */
2086+
static int client_stats_cmd(int argc, char **argv)
2087+
{
2088+
if (argc < 2) {
2089+
printf("Per-client stats: %s\n", client_stats_enabled ? "enabled" : "disabled");
2090+
printf("Usage: client_stats <enable|disable>\n");
2091+
return 0;
2092+
}
2093+
2094+
bool enable;
2095+
if (strcmp(argv[1], "enable") == 0) {
2096+
enable = true;
2097+
} else if (strcmp(argv[1], "disable") == 0) {
2098+
enable = false;
2099+
} else {
2100+
printf("Usage: client_stats <enable|disable>\n");
2101+
return 1;
2102+
}
2103+
2104+
esp_err_t err = set_config_param_int("cstats_en", enable ? 1 : 0);
2105+
if (err != ESP_OK) {
2106+
printf("Failed to save setting\n");
2107+
return 1;
2108+
}
2109+
client_stats_enabled = enable;
2110+
printf("Per-client stats %s.\n", enable ? "enabled" : "disabled");
2111+
return 0;
2112+
}
2113+
2114+
static void register_client_stats_cmd(void)
2115+
{
2116+
const esp_console_cmd_t cmd = {
2117+
.command = "client_stats",
2118+
.help = "Enable or disable per-client traffic statistics",
2119+
.hint = NULL,
2120+
.func = &client_stats_cmd,
2121+
};
2122+
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
2123+
}
2124+
20762125
/* 'set_tx_power' command - set WiFi TX power */
20772126
static int set_tx_power_cmd(int argc, char **argv)
20782127
{

components/http_server/http_server.c

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,17 +1881,19 @@ static esp_err_t mappings_get_handler(httpd_req_t *req)
18811881
}
18821882

18831883
/* Chunk 5: Connected clients table header */
1884-
httpd_resp_send_chunk(req, MAPPINGS_CHUNK_MID2, HTTPD_RESP_USE_STRLEN);
1884+
httpd_resp_send_chunk(req,
1885+
client_stats_enabled ? MAPPINGS_CHUNK_MID2 : MAPPINGS_CHUNK_MID2_NOSTATS,
1886+
HTTPD_RESP_USE_STRLEN);
18851887

18861888
/* Chunk 6: Stream connected clients rows */
18871889
#define MAX_DISPLAYED_CLIENTS 8
18881890
connected_client_t clients[MAX_DISPLAYED_CLIENTS];
18891891
int client_count = get_connected_clients(clients, MAX_DISPLAYED_CLIENTS);
18901892
connect_count = client_count;
18911893

1892-
/* Fetch per-client traffic stats */
1894+
/* Fetch per-client traffic stats only when enabled */
18931895
client_stats_entry_t stats[CLIENT_STATS_MAX];
1894-
int stats_count = client_stats_get_all(stats, CLIENT_STATS_MAX);
1896+
int stats_count = client_stats_enabled ? client_stats_get_all(stats, CLIENT_STATS_MAX) : 0;
18951897

18961898
if (client_count > 0) {
18971899
for (int i = 0; i < client_count; i++) {
@@ -1920,39 +1922,41 @@ static esp_err_t mappings_get_handler(httpd_req_t *req)
19201922
}
19211923
js_name[j] = '\0';
19221924

1923-
/* Find matching traffic stats by MAC */
1924-
char traffic_str[32] = "-";
1925-
for (int s = 0; s < stats_count; s++) {
1926-
if (memcmp(stats[s].mac, clients[i].mac, 6) == 0) {
1927-
char tx_buf[12], rx_buf[12];
1928-
format_bytes_human(stats[s].bytes_sent, tx_buf, sizeof(tx_buf));
1929-
format_bytes_human(stats[s].bytes_received, rx_buf, sizeof(rx_buf));
1930-
snprintf(traffic_str, sizeof(traffic_str), "%s / %s", tx_buf, rx_buf);
1931-
break;
1925+
if (client_stats_enabled) {
1926+
/* Find matching traffic stats by MAC */
1927+
char traffic_str[32] = "-";
1928+
for (int s = 0; s < stats_count; s++) {
1929+
if (memcmp(stats[s].mac, clients[i].mac, 6) == 0) {
1930+
char tx_buf[12], rx_buf[12];
1931+
format_bytes_human(stats[s].bytes_sent, tx_buf, sizeof(tx_buf));
1932+
format_bytes_human(stats[s].bytes_received, rx_buf, sizeof(rx_buf));
1933+
snprintf(traffic_str, sizeof(traffic_str), "%s / %s", tx_buf, rx_buf);
1934+
break;
1935+
}
19321936
}
1937+
snprintf(row, sizeof(row),
1938+
"<tr>"
1939+
"<td>%s</td><td>%s</td><td>%s</td><td>%s</td>"
1940+
"<td><button type='button' class='select-button' onclick=\"fillDhcpForm('%s','%s','%s')\">Select</button></td>"
1941+
"</tr>",
1942+
mac_str, ip_str, clients[i].name[0] ? clients[i].name : "-", traffic_str,
1943+
mac_str, clients[i].has_ip ? ip_str : "", js_name);
1944+
} else {
1945+
snprintf(row, sizeof(row),
1946+
"<tr>"
1947+
"<td>%s</td><td>%s</td><td>%s</td>"
1948+
"<td><button type='button' class='select-button' onclick=\"fillDhcpForm('%s','%s','%s')\">Select</button></td>"
1949+
"</tr>",
1950+
mac_str, ip_str, clients[i].name[0] ? clients[i].name : "-",
1951+
mac_str, clients[i].has_ip ? ip_str : "", js_name);
19331952
}
1934-
1935-
snprintf(row, sizeof(row),
1936-
"<tr>"
1937-
"<td>%s</td>"
1938-
"<td>%s</td>"
1939-
"<td>%s</td>"
1940-
"<td>%s</td>"
1941-
"<td><button type='button' class='select-button' onclick=\"fillDhcpForm('%s','%s','%s')\">Select</button></td>"
1942-
"</tr>",
1943-
mac_str,
1944-
ip_str,
1945-
clients[i].name[0] ? clients[i].name : "-",
1946-
traffic_str,
1947-
mac_str,
1948-
clients[i].has_ip ? ip_str : "",
1949-
js_name
1950-
);
19511953
httpd_resp_send_chunk(req, row, HTTPD_RESP_USE_STRLEN);
19521954
}
19531955
} else {
19541956
httpd_resp_send_chunk(req,
1955-
"<tr><td colspan='5' style='text-align:center; color:#888;'>No clients connected</td></tr>",
1957+
client_stats_enabled
1958+
? "<tr><td colspan='5' style='text-align:center; color:#888;'>No clients connected</td></tr>"
1959+
: "<tr><td colspan='4' style='text-align:center; color:#888;'>No clients connected</td></tr>",
19561960
HTTPD_RESP_USE_STRLEN);
19571961
}
19581962

components/http_server/pages/page_mappings.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,22 @@ document.getElementById('dhcp_mac').scrollIntoView({behavior: 'smooth', block: '
8585
</thead>\
8686
<tbody>"
8787

88+
/* Same header without the Traffic column (used when per-client stats are disabled) */
89+
#define MAPPINGS_CHUNK_MID2_NOSTATS "\
90+
</div>\
91+
<div class='section'>\
92+
<h2>Connected Clients</h2>\
93+
<table class='data-table'>\
94+
<thead>\
95+
<tr>\
96+
<th>MAC Address</th>\
97+
<th>IP Address</th>\
98+
<th>Device Name</th>\
99+
<th>Action</th>\
100+
</tr>\
101+
</thead>\
102+
<tbody>"
103+
88104
/* After clients tbody, before dhcp tbody */
89105
#define MAPPINGS_CHUNK_MID3 "\
90106
</tbody>\

components/mqtt_ha/mqtt_ha.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,8 +618,8 @@ esp_err_t mqtt_ha_start(void)
618618
.qos = 1,
619619
.retain = 1,
620620
},
621-
.buffer.size = CONFIG_MQTT_BUFFER_SIZE,
622-
.buffer.out_size = CONFIG_MQTT_BUFFER_SIZE,
621+
.buffer.size = CONFIG_MQTT_HA_BUFFER_SIZE,
622+
.buffer.out_size = CONFIG_MQTT_HA_BUFFER_SIZE,
623623
};
624624

625625
s_client = esp_mqtt_client_init(&cfg);

components/pcap_capture/pcap_capture.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ void pcap_init(void)
249249
ESP_LOGI(TAG, "PCAP capture available (server starts on demand)");
250250
}
251251

252-
bool pcap_should_capture(bool is_acl_monitored, bool is_ap_interface)
252+
IRAM_ATTR bool pcap_should_capture(bool is_acl_monitored, bool is_ap_interface)
253253
{
254254
// Must have a client connected to capture anything
255255
if (!client_connected) {
@@ -269,7 +269,7 @@ bool pcap_should_capture(bool is_acl_monitored, bool is_ap_interface)
269269
return false;
270270
}
271271

272-
void pcap_capture_packet(struct pbuf *p)
272+
IRAM_ATTR void pcap_capture_packet(struct pbuf *p)
273273
{
274274
if (p == NULL || !client_connected) {
275275
return;

0 commit comments

Comments
 (0)