Port configuration
SFP speed is set per slot and is not saved in the startup config.
diff --git a/httpd/page_impl.c b/httpd/page_impl.c
index 183510d0..006d2dbe 100644
--- a/httpd/page_impl.c
+++ b/httpd/page_impl.c
@@ -1111,6 +1111,9 @@ void send_status(void)
slen += strtox(outbuf + slen, "\",\"rxB\":\"0x");
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
reg_to_html(RTL837X_STAT_V_HIGH); // 32bit RX packet errors
+
+ slen += strtox(outbuf + slen, "\",\"macs\":\"0x");
+ reg_to_html(RTL837X_L2_LRN_PORT_CONSTRT_CNT + (i << 2));
slen += strtox(outbuf + slen, "\"}");
if (i < machine.max_port)
char_to_html(',');
diff --git a/rtl837x_port.c b/rtl837x_port.c
index e3600eba..f82fc713 100644
--- a/rtl837x_port.c
+++ b/rtl837x_port.c
@@ -510,7 +510,7 @@ void port_media_show(uint8_t port) __banked
void port_stats_print(void) __banked
{
- print_string("\nPort\tState\tLink\tTxGood\t\tTxBad\t\tRxGood\t\tRxBad\n");
+ print_string("\nPort\tState\tLink\tTxGood\t\tTxBad\t\tRxGood\t\tRxBad\t\tMACs\n");
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
print_phys_port(i); write_char('\t');
@@ -584,6 +584,9 @@ void port_stats_print(void) __banked
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
print_reg(RTL837X_STAT_V_HIGH); write_char('\t');
+
+ reg_read(RTL837X_L2_LRN_PORT_CONSTRT_CNT + (i << 2));
+ itoa_short(SFR_DATA_U16 & L2_LRN_PORT_CNT_MASK);
print_string("\n");
}
}
diff --git a/rtl837x_regs.h b/rtl837x_regs.h
index c2117fb1..93eb7f44 100644
--- a/rtl837x_regs.h
+++ b/rtl837x_regs.h
@@ -214,6 +214,8 @@
#define RTL837x_L2_TBL_FLUSH_CNF 0x53dc
#define RTL837X_L2_LRN_PORT_CONSTRAINT 0x5384
#define RTL837X_L2_LRN_PORT_CONSTRT_ACT 0x4f80
+#define RTL837X_L2_LRN_PORT_CONSTRT_CNT 0x53ac
+#define L2_LRN_PORT_CNT_MASK 0x1fff
#define RTL8373_REG_MAC_L2_PORT_MAX_LEN 0x1250
/*
diff --git a/test/test_page_json.c b/test/test_page_json.c
index e650a538..a7626565 100644
--- a/test/test_page_json.c
+++ b/test/test_page_json.c
@@ -185,6 +185,23 @@ static void t_l2_page(void)
CHECK(balanced(), "every page is valid JSON");
}
+static void t_status_macs(void)
+{
+ const char *p1, *end, *mac;
+
+ printf("[test] /status.json reports the MAC addresses learned on each port\n");
+ hw_reset(); out_reset();
+ hw_reg_set(RTL837X_L2_LRN_PORT_CONSTRT_CNT + (1 << 2), 0x21);
+ send_status();
+ p1 = strstr(body(), "\"logPort\":1,");
+ end = p1 ? strchr(p1, '}') : NULL;
+ mac = p1 ? strstr(p1, "\"macs\":\"0x21\"") : NULL;
+ CHECK(mac && mac < end, "port 1 shows its learned count");
+ CHECK(has("\"macs\":\"0x0\""), "a port without learned addresses shows 0");
+ CHECK(slen <= TCP_OUTBUF_SIZE, "fits the buffer");
+ CHECK(balanced(), "valid JSON");
+}
+
static void t_status_counters(void)
{
printf("[test] /status.json prints 64-bit packet counters in full\n");
@@ -211,6 +228,7 @@ int main(void)
t_l2();
t_l2_page();
t_status_counters();
+ t_status_macs();
printf("\n%d checks, %d failed\n", tests_run, tests_failed);
return tests_failed ? 1 : 0;
}
diff --git a/tools/httpd_sim.c b/tools/httpd_sim.c
index 5fea029f..68f87232 100644
--- a/tools/httpd_sim.c
+++ b/tools/httpd_sim.c
@@ -56,6 +56,7 @@ time_t last_session_use;
uint64_t txG[PORTS], txB[PORTS], rxG[PORTS], rxB[PORTS];
char txG_buff[20], txB_buff[20], rxG_buff[20], rxB_buff[20], counter_buf[20], counter_name[20];
+char macs_buff[8];
char sfp_temp[8], sfp_vcc[8], sfp_txbias[8], sfp_txpower[8], sfp_rxpower[8], sfp_laser[8], sfp_options[6];
char num_buff[20];
char l2_idx_buff[20];
@@ -180,6 +181,12 @@ void send_status(int s)
json_object_object_add(v, "txB", json_object_new_string(txB_buff));
json_object_object_add(v, "rxG", json_object_new_string(rxG_buff));
json_object_object_add(v, "rxB", json_object_new_string(rxB_buff));
+ uint16_t macs = 0;
+ for (int e = 0; e < L2_ENTRY_NUM; e++)
+ if (l2_entries[e].port == physToLogPort[i-1] && l2_entries[e].type != 's')
+ macs++;
+ sprintf(macs_buff, "0x%04x", macs);
+ json_object_object_add(v, "macs", json_object_new_string(macs_buff));
if (i >= PORTS - NSFP) {
uint16_t temp = 0x28fb + rand() / (RAND_MAX / 100);
uint16_t vcc = 0x7eda + rand() / (RAND_MAX / 100);