Console: Add Ingress type & VLAN show table

Added new `vlan show` command to dump current VLAN settings.
Supports printing PVID & ingress filtering per port.

Added new `ingress [p]<mode>` command to setup ingress filtering.
Added wrappers for enabling/disabling vlan filtering. Currently
not configurable, but state in console is read via ASIC registers.

Full VLAN dump & web support of new commands will be added later.
This commit is contained in:
diijkstra
2026-03-21 12:29:26 +01:00
parent d21d269d49
commit f7fcf0eda7
5 changed files with 221 additions and 14 deletions
+73 -2
View File
@@ -342,16 +342,86 @@ void parse_vlan(void)
w++; w++;
} }
vlan_create(); vlan_create();
} else if (cmd_words_b[1] > 0 && cmd_compare(1, "show")) {
vlan_dump();
} else {
goto err;
} }
if (cmd_words_b[2] > 0 && isletter(cmd_buffer[cmd_words_b[2]])) { if (cmd_words_b[2] > 0 && isletter(cmd_buffer[cmd_words_b[2]])) {
print_string("vlan_ptr "); print_short(vlan_ptr); write_char(':'); print_string("vlan_ptr "); print_short(vlan_ptr); write_char(':');
write_char('>'); print_string_x(&vlan_names[0]); write_char('<'); write_char('\n'); write_char('>'); print_string_x(&vlan_names[0]); write_char('<'); write_char('\n');
} }
return; return;
err: err:
print_string("Error: vlan <vlan-id> [port][t/u]..."); print_string("Error: vlan (<vlan-id>|show) [port][t/u]...");
} }
bool vlan_ingress_mode_parse(char c, vlan_ingress_mode_t *mode)
{
switch (c) {
case 'u':
*mode = VLAN_UNTAGGED;
return true;
case 't':
*mode = VLAN_TAGGED;
return true;
case 'a':
*mode = VLAN_ALL;
return true;
default:
*mode = VLAN_INVALID;
return false;
}
}
void parse_ingress(void)
{
if (cmd_words_b[1] <= 0) {
goto err;
}
__xdata uint8_t log_port = 0;
__xdata vlan_ingress_mode_t mode = VLAN_INVALID;
__xdata uint8_t w = 1;
if (vlan_ingress_mode_parse(cmd_buffer[cmd_words_b[w]], &mode)) {
// Setting mode for all ports at once
for (log_port = machine.min_port; log_port <= machine.max_port; log_port++) {
if (!port_ingress_filter(log_port, mode)) {
print_string("Error setting ingress filter for port "); print_byte(machine.log_to_phys_port[log_port]); write_char('\n');
return;
}
print_string("All ports ingress filter set to: ");
print_port_ingress_filter_mode(mode); write_char('\n');
}
return;
} else {
for(w = 1; cmd_words_b[w] > 0; w++) {
if (!isnumber(cmd_buffer[cmd_words_b[w]])) {
continue;
}
if (cmd_buffer[cmd_words_b[w]] - '1' > 9) {
print_string("Invalid physical port number: "); write_char(cmd_buffer[cmd_words_b[w]]); write_char('\n');
continue;
}
log_port = machine.phys_to_log_port[cmd_buffer[cmd_words_b[w]] - '1'];
if (!vlan_ingress_mode_parse(cmd_buffer[cmd_words_b[w] + 1], &mode)) {
print_string("Invalid ingress mode for port "); write_char(cmd_buffer[cmd_words_b[w]]); print_string(" in ingress command\n");
goto err;
}
if (!port_ingress_filter(log_port, mode)) {
print_string("Error setting ingress filter for port "); write_char(cmd_buffer[cmd_words_b[w]]); write_char('\n');
return;
}
print_string("Port "); write_char(cmd_buffer[cmd_words_b[w]]);
print_string(" ingress filter set to: ");
print_port_ingress_filter_mode(mode); write_char('\n');
}
return;
}
err:
print_string("Error: ingress [p]<u/t/a>... \n");
}
void parse_mirror(void) void parse_mirror(void)
{ {
@@ -1044,6 +1114,8 @@ void cmd_parser(void) __banked
write_char(cmd_history[p]); write_char(cmd_history[p]);
p = (p + 1) & CMD_HISTORY_MASK; p = (p + 1) & CMD_HISTORY_MASK;
} }
} else if (cmd_compare(0, "ingress")) {
parse_ingress();
} }
else { else {
print_string("Unknown command\n"); print_string("Unknown command\n");
@@ -1070,7 +1142,6 @@ void cmd_parser(void) __banked
} }
} }
void clear_command_history(void) __banked void clear_command_history(void) __banked
{ {
for (cmd_history_ptr = 0; cmd_history_ptr < CMD_HISTORY_SIZE; cmd_history_ptr++) for (cmd_history_ptr = 0; cmd_history_ptr < CMD_HISTORY_SIZE; cmd_history_ptr++)
+23 -4
View File
@@ -38,10 +38,18 @@ an even port uses bits [11:0]. The base register is
RTL837x_PVID_BASE_REG (0x4e1c) and the registers go to 0x4e2c so that also RTL837x_PVID_BASE_REG (0x4e1c) and the registers go to 0x4e2c so that also
the CPU-Port may have a PVID. the CPU-Port may have a PVID.
Register RTL837x_REG_INGRESS (0x4e10) allows to define the iingress rules of Register RTL837x_REG_INGRESS (0x4e10) allows to define the ingress rules of
a port. 2 bits define a rule and bits 0-19 are being used. A value of 00 a port. 2 bits define a rule and bits 0-19 are being used. A value of 00
defines no filtering, 01 (0x01) allows only tagged packets, while 10 (0x02) defines no filtering, 01 (0x01) allows only tagged packets, while 10 (0x02)
allows only untagged packets to enter a port. The default PVID is 1. allows only untagged packets to enter a port.
Register RTL837X_VLAN_PORT_IGR_FLTR (0x4e18) enables or disables ingres VLAN
filtering, each bit corresponds to given port (port0 -> bit0, port9 -> bit9).
When enabled, incomming package's vlan tag is checked against VLAN membership
on given port. When package contains VLAN not in member list, package is dropped.
The default PVID on all port is 1, ingress VLAN filtering is enabled and all types of
frames are accepted on input on all ports.
By default, the ports transmit Ethernet frames with Realtek's proprietary By default, the ports transmit Ethernet frames with Realtek's proprietary
tag format. By setting bit 6 (0x40) of the respective port configuration tag format. By setting bit 6 (0x40) of the respective port configuration
@@ -68,9 +76,20 @@ vlan <VLAN-ID> p[t/u]...
vlan <VLAN-ID> d vlan <VLAN-ID> d
deletes the VLAN deletes the VLAN
vlan show
Dumps the current ingress vlan settings.
pvid <port> <VLAN-ID> pvid <port> <VLAN-ID>
assigns PVID to a port. ports are numbered as on the casing assigns PVID to a port. ports are numbered as on the casing
ingress <port> [tagged|untagged|all] ingress [p]<t|u|a>...
Allows ingress only for the named packages at the given port Allows ingress packages on port `p` only when `t`agged, `u`ntagged or `a`ny.
Multiple ports can be given at once as in vlan. When `p` is missing, all ports
are assigned the same mode. CPU port can not be changed.
Use `vlan show` to see current configuration.
Example:
`ingress 1t 2a` -> Set port 1 as tagged input only, set port 2 accepting any frames.
`ingress a` -> Set all ports to accept both tagged and untagged frames (default behaviour).
``` ```
+104 -6
View File
@@ -48,16 +48,38 @@ void port_mirror_del(void) __banked
} }
void port_ingress_filter(__xdata uint8_t port, __xdata uint8_t type) __banked bool port_ingress_filter(__xdata uint8_t port, __xdata vlan_ingress_mode_t type) __banked
{ {
if (type & 0x1) if (port > 9 || type >= VLAN_INVALID) {
print_string("Invalid port or ingress filter type\n");
return false;
}
if (type & 0x1) {
reg_bit_set(RTL837x_REG_INGRESS, port << 1); reg_bit_set(RTL837x_REG_INGRESS, port << 1);
else } else {
reg_bit_clear(RTL837x_REG_INGRESS, port << 1); reg_bit_clear(RTL837x_REG_INGRESS, port << 1);
if (type & 0x2) }
if (type & 0x2) {
reg_bit_set(RTL837x_REG_INGRESS, (port << 1) + 1); reg_bit_set(RTL837x_REG_INGRESS, (port << 1) + 1);
else } else {
reg_bit_clear(RTL837x_REG_INGRESS, (port << 1) + 1); reg_bit_clear(RTL837x_REG_INGRESS, (port << 1) + 1);
}
return true;
}
vlan_ingress_mode_t port_ingress_filter_get(__xdata uint8_t port) __banked
{
reg_read_m(RTL837x_REG_INGRESS);
if (port > 9) {
return VLAN_INVALID;
}
// Each port is represented by 2 bits in the ingress register, starting from bit 0 for port 0
const uint8_t sfr_index = 3 - (port / 4);
const uint8_t shift = (port % 4) << 1;
return (vlan_ingress_mode_t)((sfr_data[sfr_index] >> shift) & 0x03);
} }
@@ -210,7 +232,8 @@ void vlan_setup(void) __banked
// EGRESS filtering for port: removal of additional VLAN tag (mode 0x3 for each port) // EGRESS filtering for port: removal of additional VLAN tag (mode 0x3 for each port)
reg_bit_clear(RTL837X_VLAN_PORT_EGR_TAG, i << 1); reg_bit_clear(RTL837X_VLAN_PORT_EGR_TAG, i << 1);
reg_bit_clear(RTL837X_VLAN_PORT_EGR_TAG, (i << 1) + 1); reg_bit_clear(RTL837X_VLAN_PORT_EGR_TAG, (i << 1) + 1);
reg_bit_set(RTL837X_VLAN_PORT_IGR_FLTR, i); // Enable INGRESS filtering for port: discard packets not belonging to member VLAN on that port
port_ingress_vlan_filter_set(i, true);
#ifdef DEBUG #ifdef DEBUG
print_string("\n"); print_string("\n");
@@ -235,6 +258,7 @@ void vlan_setup(void) __banked
#ifdef DEBUG #ifdef DEBUG
print_string("\nvlan_setup, REG 0x6738: "); print_reg(0x6738); print_string("\nvlan_setup, REG 0x6738: "); print_reg(0x6738);
print_string("\nvlan_setup, REG 0x4e10: "); print_reg(0x4e10);
print_string("\nvlan_setup, REG 0x4e18: "); print_reg(0x4e18); print_string("\nvlan_setup, REG 0x4e18: "); print_reg(0x4e18);
print_string("\nvlan_setup, REG 0x4e14: "); print_reg(0x4e14); print_string("\nvlan_setup, REG 0x4e14: "); print_reg(0x4e14);
print_string("\nvlan_setup, REG 0x4e30: "); print_reg(0x4e30); print_string("\nvlan_setup, REG 0x4e30: "); print_reg(0x4e30);
@@ -636,3 +660,77 @@ void port_lag_hash_set(__xdata uint8_t lag, __xdata uint8_t hash_bits) __banked
print_string("Link aggregation group must be 0-3!"); print_string("Link aggregation group must be 0-3!");
REG_WRITE(RTL837X_TRK_HASH_CTRL_BASE + (lag << 2), 0, 0, 0, hash_bits); REG_WRITE(RTL837X_TRK_HASH_CTRL_BASE + (lag << 2), 0, 0, 0, hash_bits);
} }
void print_port_ingress_filter_mode(vlan_ingress_mode_t mode) __banked
{
switch (mode) {
case VLAN_UNTAGGED:
print_string("Untag.");
break;
case VLAN_TAGGED:
print_string("Tagged");
break;
case VLAN_ALL:
print_string("Any");
break;
default:
print_string("!!err!!");
}
}
static void print_phys_port(uint8_t port) __banked
{
if (port >= machine.min_port && port <= machine.max_port)
write_char(machine.log_to_phys_port[port] + '0');
else if (port == 9)
write_char('9');
else
write_char('?');
}
void print_vlan_ingress_port(uint8_t log_port) __banked
{
print_phys_port(log_port);write_char('\t');
print_short(port_pvid_get(log_port));write_char('\t');
print_port_ingress_filter_mode(port_ingress_filter_get(log_port));write_char('\t');
port_ingress_vlan_filter_get(log_port) ? print_string("Enabled") : print_string("Disabled");
write_char('\n');
}
/*
* Dumps the VLAN ingress configuration
*/
void vlan_dump(void) __banked
{
print_string("Ingress VLAN configuration:\n");
print_string("Port\tPVID\tType\tFiltering\n");
for (uint8_t port = machine.min_port; port <= machine.max_port; port++) {
print_vlan_ingress_port(port);
}
print_vlan_ingress_port(9);
write_char('\n');
print_string("Type - Which frame types are allowed: untagged, tagged or any\n");
print_string("Filtering - Whether packets not belonging to member VLANs on that port are dropped\n");
print_string("PVID - Assumed VLAN for untagged packets\n");
}
/** Set the ingress VLAN filtering */
bool port_ingress_vlan_filter_set(__xdata uint8_t port, __xdata bool enabled) __banked
{
if (port < machine.min_port || port > machine.max_port && port != 9) {
return false;
}
reg_bit_set(RTL837X_VLAN_PORT_IGR_FLTR, port);
return true;
}
/** Get the ingress VLAN filtering status */
bool port_ingress_vlan_filter_get(__xdata uint8_t port) __banked
{
if (port < machine.min_port || port > machine.max_port && port != 9) {
return false;
}
return reg_bit_test(RTL837X_VLAN_PORT_IGR_FLTR, port);
}
+19 -1
View File
@@ -2,6 +2,7 @@
#define _RTL837X_PORT_H_ #define _RTL837X_PORT_H_
#include <stdint.h> #include <stdint.h>
#include "rtl837x_regs.h"
#define STAT_COUNTER_TX_PKTS 46 #define STAT_COUNTER_TX_PKTS 46
#define STAT_COUNTER_RX_PKTS 47 #define STAT_COUNTER_RX_PKTS 47
@@ -13,6 +14,19 @@
reg_read_m(RTL837X_STAT_GET); \ reg_read_m(RTL837X_STAT_GET); \
} while (sfr_data[3] & 0x1); } while (sfr_data[3] & 0x1);
// Possible values for ingress filter type
typedef enum {
VLAN_ALL = INGR_ALLOW_ALL,
VLAN_TAGGED = INGR_ALLOW_TAGGED,
VLAN_UNTAGGED = INGR_ALLOW_UNTAGGED,
VLAN_INVALID = 3
} vlan_ingress_mode_e;
// Since we lack a way to force enum to be 1 byte,
// This is a typedef for the VLAN ingress filter type
// which holds vlan_ingress_mode_e values
typedef uint8_t vlan_ingress_mode_t;
struct vlan_settings { struct vlan_settings {
uint16_t vlan; uint16_t vlan;
uint16_t members; uint16_t members;
@@ -31,9 +45,10 @@ void port_pvid_set(uint8_t port, __xdata uint16_t pvid) __banked;
uint16_t port_pvid_get(uint8_t port) __banked; uint16_t port_pvid_get(uint8_t port) __banked;
void vlan_create(void) __banked; void vlan_create(void) __banked;
void vlan_delete(uint16_t vlan) __banked; void vlan_delete(uint16_t vlan) __banked;
void vlan_dump(void) __banked;
void port_mirror_set(register uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t tx_pmask) __banked; void port_mirror_set(register uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t tx_pmask) __banked;
void port_mirror_del(void) __banked; void port_mirror_del(void) __banked;
void port_ingress_filter(__xdata uint8_t port, __xdata uint8_t type) __banked; bool port_ingress_filter(__xdata uint8_t port, __xdata vlan_ingress_mode_t type) __banked;
void port_l2_setup(void) __banked; void port_l2_setup(void) __banked;
void port_lag_members_set(__xdata uint8_t lag, __xdata uint16_t members) __banked; void port_lag_members_set(__xdata uint8_t lag, __xdata uint16_t members) __banked;
void port_lag_hash_set(__xdata uint8_t lag, __xdata uint8_t hash) __banked; void port_lag_hash_set(__xdata uint8_t lag, __xdata uint8_t hash) __banked;
@@ -43,4 +58,7 @@ void port_eee_status_all(void) __banked;
void port_eee_enable(__xdata uint8_t port, __xdata uint8_t speed) __banked; void port_eee_enable(__xdata uint8_t port, __xdata uint8_t speed) __banked;
void port_eee_disable(uint8_t port) __banked; void port_eee_disable(uint8_t port) __banked;
void port_eee_status(uint8_t port) __banked; void port_eee_status(uint8_t port) __banked;
void print_port_ingress_filter_mode(vlan_ingress_mode_t mode) __banked;
bool port_ingress_vlan_filter_set(__xdata uint8_t port, __xdata bool enabled) __banked;
bool port_ingress_vlan_filter_get(__xdata uint8_t port) __banked;
#endif #endif
+2 -1
View File
@@ -95,6 +95,7 @@ extern __xdata struct dhcp_state dhcp_state;
__xdata volatile uint8_t sbuf_ptr; __xdata volatile uint8_t sbuf_ptr;
__xdata uint8_t sbuf[SBUF_SIZE]; __xdata uint8_t sbuf[SBUF_SIZE];
// Registry data in sfr is in *big endian* order, so sfr_data[0] is the MSB and sfr_data[3] the LSB
__xdata uint8_t sfr_data[4]; __xdata uint8_t sfr_data[4];
extern __xdata uint8_t gpio_last_value[8]; extern __xdata uint8_t gpio_last_value[8];
@@ -462,7 +463,7 @@ void reg_bit_clear(uint16_t reg_addr, char bit)
/* /*
* This sets a bit in the 32bit wide switch register reg_addr * This tests a bit in the 32bit wide switch register reg_addr
*/ */
uint8_t reg_bit_test(uint16_t reg_addr, char bit) uint8_t reg_bit_test(uint16_t reg_addr, char bit)
{ {