mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-08-30 14:52:51 +08:00
+121
-81
@@ -95,15 +95,16 @@ uint8_t cmd_compare(uint8_t start, uint8_t * __code cmd)
|
||||
|
||||
for (i = cmd_words_b[start]; i != cmd_words_b[start + 1] && cmd_buffer[i] != ' '; i++) {
|
||||
i &= SBUF_SIZE - 1;
|
||||
// print_short(i); write_char(':'); print_short(j); write_char('#'); print_string("\n");
|
||||
// print_byte(i); write_char(':'); print_byte(j); write_char('#'); print_string("\n");
|
||||
// write_char('>'); write_char(cmd[j]); write_char('-'); write_char(cmd_buffer[i]); print_string("\n");
|
||||
if (!cmd[j])
|
||||
if (!cmd[j] && !isletter(cmd_buffer[i]))
|
||||
return 1;
|
||||
if (cmd_buffer[i] != cmd[j++])
|
||||
break;
|
||||
}
|
||||
// write_char('.'); print_short(i); write_char(':'); print_short(i);
|
||||
if (i == cmd_words_b[start + 1] || cmd_buffer[i] == ' ')
|
||||
// write_char('.'); print_byte(i); write_char(':'); print_byte(j); write_char(','); print_byte (cmd[j-1]);
|
||||
// write_char(','); print_byte(cmd[j]);
|
||||
if (i == cmd_words_b[start + 1] || (cmd_buffer[i] == ' ' && !cmd[j]))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -186,28 +187,100 @@ uint8_t parse_ip(register uint8_t idx)
|
||||
}
|
||||
|
||||
|
||||
void parse_trunk(void)
|
||||
void parse_lag(void)
|
||||
{
|
||||
__xdata uint8_t group;
|
||||
__xdata uint16_t members = 0;
|
||||
|
||||
if (cmd_words_b[1] > 0 && cmd_compare(1, "show")) {
|
||||
print_string("LAG status:\n");
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
write_char(' '); write_char('1' + i);
|
||||
reg_read_m(RTL837X_TRK_MBR_CTRL_BASE + (i << 2));
|
||||
members = ((uint16_t)sfr_data[2]) << 8 | sfr_data[3];
|
||||
if (!members) {
|
||||
print_string(" disabled\n");
|
||||
continue;
|
||||
}
|
||||
print_string(" member ports: ");
|
||||
for (uint8_t j = 0; j < 10; j++) {
|
||||
if (members & 1) {
|
||||
if (!isRTL8373)
|
||||
write_char('0' + log_to_phys_port[j]);
|
||||
else
|
||||
write_char('1' + j);
|
||||
write_char(' ');
|
||||
}
|
||||
members >>= 1;
|
||||
}
|
||||
print_string(" (hash: 0x");
|
||||
reg_read_m(RTL837X_TRK_HASH_CTRL_BASE + (i << 2));
|
||||
print_byte(sfr_data[3]);
|
||||
print_string(")\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd_words_b[2] <= 0 || !isnumber(cmd_buffer[cmd_words_b[1]]))
|
||||
goto err;
|
||||
group = cmd_buffer[cmd_words_b[1]] - '0';
|
||||
|
||||
uint8_t w = 2;
|
||||
while (cmd_words_b[w] > 0) {
|
||||
while (cmd_words_b[w + 1] > 0) {
|
||||
// write_char('|'); print_byte(w); write_char(':'); write_char(cmd_buffer[cmd_words_b[w]]); write_char('-');
|
||||
uint8_t port;
|
||||
if (isnumber(cmd_buffer[cmd_words_b[w]])) {
|
||||
port = cmd_buffer[cmd_words_b[w]] - '1';
|
||||
if (port > maxPort)
|
||||
goto err;
|
||||
members |= ((uint16_t)1) << port;
|
||||
if (isnumber(cmd_buffer[cmd_words_b[w] + 1]))
|
||||
port = (port + 1) * 10 + cmd_buffer[cmd_words_b[w] + 1] - '1';
|
||||
if (!isRTL8373)
|
||||
port = phys_to_log_port[port];
|
||||
} else {
|
||||
goto err;
|
||||
}
|
||||
if (port > maxPort)
|
||||
goto err;
|
||||
members |= ((uint16_t)1) << port;
|
||||
w++;
|
||||
}
|
||||
port_lag_members_set(group, members);
|
||||
return;
|
||||
err:
|
||||
print_string("Error: lag <lag> [port]...");
|
||||
}
|
||||
|
||||
|
||||
void parse_lag_hash(void)
|
||||
{
|
||||
__xdata uint8_t group;
|
||||
__xdata uint8_t hash = 0;
|
||||
|
||||
group = cmd_buffer[cmd_words_b[1]] - '0';
|
||||
|
||||
uint8_t w = 2;
|
||||
while (cmd_words_b[w + 1] > 0) {
|
||||
if (cmd_compare(w, "spa"))
|
||||
hash |= LAG_HASH_SOURCE_PORT_NUMBER;
|
||||
else if (cmd_compare(w, "smac"))
|
||||
hash |= LAG_HASH_L2_SMAC;
|
||||
else if (cmd_compare(w, "dmac"))
|
||||
hash |= LAG_HASH_L2_DMAC;
|
||||
else if (cmd_compare(w, "sip"))
|
||||
hash |= LAG_HASH_L3_SIP;
|
||||
else if (cmd_compare(w, "dip"))
|
||||
hash |= LAG_HASH_L3_DIP;
|
||||
else if (cmd_compare(w, "sport"))
|
||||
hash |= LAG_HASH_L4_SPORT;
|
||||
else if (cmd_compare(w, "dport"))
|
||||
hash |= LAG_HASH_L4_DPORT;
|
||||
else {
|
||||
print_string("Error: invalid hash type:");
|
||||
print_string_x(&cmd_buffer[cmd_words_b[w]]);
|
||||
write_char('\n');
|
||||
}
|
||||
w++;
|
||||
}
|
||||
trunk_set(group, members);
|
||||
return;
|
||||
err:
|
||||
print_string("Error: trunk <trunk-id> [port]...");
|
||||
port_lag_hash_set(group, hash);
|
||||
}
|
||||
|
||||
|
||||
@@ -553,8 +626,7 @@ void cmd_parser(void) __banked
|
||||
if (cmd_compare(0, "reset")) {
|
||||
print_string("\nRESET\n\n");
|
||||
reset_chip();
|
||||
}
|
||||
if (cmd_compare(0, "sfp")) {
|
||||
} else if (cmd_compare(0, "sfp")) {
|
||||
uint8_t rate = sfp_read_reg(0, 12);
|
||||
print_string("\nRate: "); print_byte(rate);
|
||||
print_string(" Encoding: "); print_byte(sfp_read_reg(0, 11));
|
||||
@@ -564,11 +636,9 @@ void cmd_parser(void) __banked
|
||||
if (c)
|
||||
write_char(c);
|
||||
}
|
||||
}
|
||||
if (cmd_compare(0, "stat")) {
|
||||
} else if (cmd_compare(0, "stat")) {
|
||||
port_stats_print();
|
||||
}
|
||||
if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'r') {
|
||||
} else if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'r') {
|
||||
print_string("\nPRINT SECURITY REGISTERS\n");
|
||||
// The following will only show something else than 0xff if it was programmed for a managed switch
|
||||
flash_region.addr = 0x0001000;
|
||||
@@ -580,44 +650,36 @@ void cmd_parser(void) __banked
|
||||
flash_region.addr = 0x0003000;
|
||||
flash_region.len = 40;
|
||||
flash_read_security();
|
||||
}
|
||||
if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'd') {
|
||||
} else if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'd') {
|
||||
print_string("\nDUMPING FLASH\n");
|
||||
flash_region.addr = 0;
|
||||
flash_region.len = 255;
|
||||
flash_dump(255);
|
||||
}
|
||||
if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'j') {
|
||||
} else if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'j') {
|
||||
print_string("\nJEDEC ID\n");
|
||||
flash_read_jedecid();
|
||||
}
|
||||
if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'u') {
|
||||
} else if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'u') {
|
||||
print_string("\nUNIQUE ID\n");
|
||||
flash_read_uid();
|
||||
}
|
||||
// Switch to flash 62.5 MHz mode
|
||||
if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 's') {
|
||||
print_string("\nFLASH FAST MODE\n");
|
||||
} else if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 's') {
|
||||
print_string("\nFLASH FAST MODE\n"); // Switch to flash 62.5 MHz mode
|
||||
flash_init(1);
|
||||
print_string("\nNow dumping flash\n");
|
||||
flash_region.addr = 0;
|
||||
flash_region.len = 255;
|
||||
flash_dump(255);
|
||||
}
|
||||
if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'e') {
|
||||
} else if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'e') {
|
||||
print_string("\nFLASH erase\n");
|
||||
flash_region.addr = 0x20000;
|
||||
flash_sector_erase();
|
||||
}
|
||||
if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'w') {
|
||||
} else if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'w') {
|
||||
print_string("\nFLASH write\n");
|
||||
for (uint8_t i = 0; i < 20; i++)
|
||||
flash_buf[i] = greeting[i];
|
||||
flash_region.addr = 0x200000;
|
||||
flash_region.len = 20;
|
||||
flash_write_bytes(flash_buf);
|
||||
}
|
||||
if (cmd_compare(0, "port") && cmd_words_b[1] > 0) {
|
||||
} else if (cmd_compare(0, "port") && cmd_words_b[1] > 0) {
|
||||
print_string("\nPORT ");
|
||||
uint8_t p = cmd_buffer[cmd_words_b[1]] - '1';
|
||||
print_byte(p);
|
||||
@@ -637,8 +699,7 @@ void cmd_parser(void) __banked
|
||||
print_string(" OFF\n");
|
||||
phy_set_mode(p, PHY_OFF, 0, 0);
|
||||
}
|
||||
}
|
||||
if (cmd_compare(0, "ip")) {
|
||||
} else if (cmd_compare(0, "ip")) {
|
||||
print_string("Got ip command: ");
|
||||
if (!parse_ip(cmd_words_b[1]))
|
||||
uip_ipaddr(&uip_hostaddr, ip[0], ip[1], ip[2], ip[3]);
|
||||
@@ -646,8 +707,7 @@ void cmd_parser(void) __banked
|
||||
print_string("Invalid IP address\n");
|
||||
print_byte(ip[0]); print_byte(ip[1]); print_byte(ip[2]); print_byte(ip[3]);
|
||||
write_char('\n');
|
||||
}
|
||||
if (cmd_compare(0, "gw")) {
|
||||
} else if (cmd_compare(0, "gw")) {
|
||||
print_string("Got gw command: ");
|
||||
if (!parse_ip(cmd_words_b[1]))
|
||||
uip_ipaddr(&uip_draddr, ip[0], ip[1], ip[2], ip[3]);
|
||||
@@ -655,8 +715,7 @@ void cmd_parser(void) __banked
|
||||
print_string("Invalid IP address\n");
|
||||
print_byte(ip[0]); print_byte(ip[1]); print_byte(ip[2]); print_byte(ip[3]);
|
||||
write_char('\n');
|
||||
}
|
||||
if (cmd_compare(0, "netmask")) {
|
||||
} else if (cmd_compare(0, "netmask")) {
|
||||
print_string("Got netmask command: ");
|
||||
if (!parse_ip(cmd_words_b[1]))
|
||||
uip_ipaddr(&uip_netmask, ip[0], ip[1], ip[2], ip[3]);
|
||||
@@ -664,14 +723,12 @@ void cmd_parser(void) __banked
|
||||
print_string("Invalid IP address\n");
|
||||
print_byte(ip[0]);print_byte(ip[1]);print_byte(ip[2]);print_byte(ip[3]);
|
||||
write_char('\n');
|
||||
}
|
||||
if (cmd_compare(0, "l2")) {
|
||||
} else if (cmd_compare(0, "l2")) {
|
||||
if (cmd_words_b[1] > 0 && cmd_compare(1, "forget"))
|
||||
port_l2_forget();
|
||||
else
|
||||
port_l2_learned();
|
||||
}
|
||||
if (cmd_compare(0, "stp")) {
|
||||
} else if (cmd_compare(0, "stp")) {
|
||||
if (cmd_words_b[1] > 0 && cmd_compare(1, "on")) {
|
||||
print_string("STP enabled\n");
|
||||
stpEnabled = 1;
|
||||
@@ -681,8 +738,7 @@ void cmd_parser(void) __banked
|
||||
stp_off();
|
||||
stpEnabled = 0;
|
||||
}
|
||||
}
|
||||
if (cmd_compare(0, "pvid") && cmd_words_b[1] > 0 && cmd_words_b[2] > 0) {
|
||||
} else if (cmd_compare(0, "pvid") && cmd_words_b[1] > 0 && cmd_words_b[2] > 0) {
|
||||
__xdata uint16_t pvid;
|
||||
uint8_t port;
|
||||
port = cmd_buffer[cmd_words_b[1]] - '1';
|
||||
@@ -690,35 +746,27 @@ void cmd_parser(void) __banked
|
||||
port = phys_to_log_port[port];
|
||||
if (!atoi_short(&pvid, cmd_words_b[2]))
|
||||
port_pvid_set(port, pvid);
|
||||
}
|
||||
if (cmd_compare(0, "vlan")) {
|
||||
} else if (cmd_compare(0, "vlan")) {
|
||||
parse_vlan();
|
||||
}
|
||||
if (cmd_compare(0, "mirror")) {
|
||||
} else if (cmd_compare(0, "mirror")) {
|
||||
parse_mirror();
|
||||
}
|
||||
if (cmd_compare(0, "trunk")) {
|
||||
parse_trunk();
|
||||
}
|
||||
if (cmd_compare(0, "sds")) {
|
||||
} else if (cmd_compare(0, "lag")) {
|
||||
parse_lag();
|
||||
} else if (cmd_compare(0, "laghash")) {
|
||||
parse_lag_hash();
|
||||
} else if (cmd_compare(0, "sds")) {
|
||||
print_reg(RTL837X_REG_SDS_MODES);
|
||||
}
|
||||
if (cmd_compare(0, "gpio")) {
|
||||
} else if (cmd_compare(0, "gpio")) {
|
||||
print_gpio_status();
|
||||
}
|
||||
if (cmd_compare(0, "regget")) {
|
||||
} else if (cmd_compare(0, "regget")) {
|
||||
parse_regget();
|
||||
}
|
||||
if (cmd_compare(0, "regset")) {
|
||||
} else if (cmd_compare(0, "regset")) {
|
||||
parse_regset();
|
||||
}
|
||||
if (cmd_compare(0, "rnd")) {
|
||||
} else if (cmd_compare(0, "rnd")) {
|
||||
parse_rnd();
|
||||
}
|
||||
if (cmd_compare(0, "passwd")) {
|
||||
} else if (cmd_compare(0, "passwd")) {
|
||||
parse_passwd();
|
||||
}
|
||||
if (cmd_compare(0, "eee")) {
|
||||
} else if (cmd_compare(0, "eee")) {
|
||||
int8_t port = -1;
|
||||
if (cmd_words_b[3] > 0) {
|
||||
port = cmd_buffer[cmd_words_b[2]] - '1';
|
||||
@@ -741,17 +789,15 @@ void cmd_parser(void) __banked
|
||||
else
|
||||
port_eee_status_all();
|
||||
}
|
||||
}
|
||||
if (cmd_compare(0, "version")) {
|
||||
} else if (cmd_compare(0, "version")) {
|
||||
print_sw_version();
|
||||
}
|
||||
if (cmd_compare(0, "history")) {
|
||||
} else if (cmd_compare(0, "history")) {
|
||||
__xdata uint16_t p = (cmd_history_ptr + 1) & CMD_HISTORY_MASK;
|
||||
__xdata uint8_t found_begin = 0;
|
||||
print_string("History ptr: ");
|
||||
print_short(cmd_history_ptr); write_char('\n');
|
||||
// print_string("History ptr: ");
|
||||
// print_short(cmd_history_ptr); write_char('\n');
|
||||
while (p != cmd_history_ptr) {
|
||||
print_short(p); write_char(' ');
|
||||
// print_short(p); write_char(' ');
|
||||
if (!cmd_history[p] || cmd_history[p] == '\n')
|
||||
found_begin = 1;
|
||||
if (found_begin && cmd_history[p])
|
||||
@@ -793,8 +839,6 @@ void execute_config(void) __banked
|
||||
do {
|
||||
flash_region.addr = pos;
|
||||
flash_region.len = FLASH_READ_BURST_SIZE;
|
||||
write_char('-'); print_long(flash_region.addr); write_char(':'); print_short(flash_region.len); write_char('\n');
|
||||
|
||||
flash_read_bulk(flash_buf);
|
||||
|
||||
uint8_t cfg_idx = 0;
|
||||
@@ -802,11 +846,8 @@ void execute_config(void) __banked
|
||||
do {
|
||||
for (uint8_t cmd_idx = 0; cmd_idx < (SBUF_SIZE - 1); cmd_idx++) {
|
||||
c = flash_buf[cfg_idx++];
|
||||
print_byte(c);
|
||||
|
||||
if (c == 0 || c == '\n') {
|
||||
cmd_buffer[cmd_idx] = '\0';
|
||||
write_char('\n'); write_char('#'); print_short(cfg_idx); write_char('-'); print_short(cmd_idx); write_char('-'); print_string_x(cmd_buffer); write_char('\n');
|
||||
if (cmd_idx && !cmd_tokenize())
|
||||
cmd_parser();
|
||||
if (c == 0)
|
||||
@@ -816,7 +857,6 @@ void execute_config(void) __banked
|
||||
|
||||
cmd_buffer[cmd_idx] = c;
|
||||
}
|
||||
write_char('N');
|
||||
} while(cfg_idx);
|
||||
|
||||
len_left -= FLASH_READ_BURST_SIZE;
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
@@ -0,0 +1,227 @@
|
||||
# Link Aggregation (aka Trunking)
|
||||
|
||||
The RTL827x allows to combine multiple ports to a single logical link
|
||||
(Link Aggregation / Trunking) according to IEEE 802.3ad. LAGs allow to
|
||||
combine the individual physical links into a single link with the combined
|
||||
throughput and automatic redundancy when one of the link fails.
|
||||
Up to 4 Link Aggregation Groups (LAGs) can be defined on the switch devices.
|
||||
|
||||
## LAG control
|
||||
Four registers `RTL837X_TRK_MBR_CTRL_BASE(lag) (0x4f38-0x4f44)` define the LAG membership
|
||||
via a port mask of the logical port numbers.
|
||||
|
||||
A hash algorithm applied to L2, L3 and L4 properties of a packet are used to decide which
|
||||
of the links (ports) is being used to transfer the packet. The possible properties used in the
|
||||
hash are:
|
||||
```
|
||||
#define LAG_HASH_SOURCE_PORT_NUMBER 0x01
|
||||
#define LAG_HASH_L2_SMAC 0x02
|
||||
#define LAG_HASH_L2_DMAC 0x04
|
||||
#define LAG_HASH_L3_SIP 0x08
|
||||
#define LAG_HASH_L3_DIP 0x10
|
||||
#define LAG_HASH_L4_SPORT 0x20
|
||||
#define LAG_HASH_L4_DPORT 0x40
|
||||
#define LAG_HASH_DEFAULT (LAG_HASH_L2_SMAC | LAG_HASH_L2_DMAC | LAG_HASH_L3_SIP | LAG_HASH_L3_DIP | LAG_HASH_L4_SPORT | LAG_HASH_L4_DPORT)
|
||||
```
|
||||
The hash algorithm used to select links (exit ports) is defined for each LAG individually in
|
||||
`RTL837X_TRK_HASH_CTRL_BASE (0x4f48-0x4f54)`.
|
||||
|
||||
## Trunking API
|
||||
The code currently provides the following functions:
|
||||
```
|
||||
/*
|
||||
* Configure LAGs
|
||||
* Sets the members via port bitmask of a given Link Aggregation Group
|
||||
* The groups have numbers 0-3
|
||||
* The bitmask represents up to 10 ports
|
||||
* If currently no LAG has algorithm used, a default is applied
|
||||
*/
|
||||
void port_lag_members_set(__xdata uint8_t lag, __xdata uint16_t members) __banked;
|
||||
|
||||
/*
|
||||
* Configures the hash algorithm used for a LAG
|
||||
* lag is the Group to configure and hash is a bitmask
|
||||
*/
|
||||
void port_lag_hash_set(__xdata uint8_t lag, __xdata uint8_t hash_bits) __banked;
|
||||
```
|
||||
|
||||
## LAG configuration on the Serial Console
|
||||
For testing the following commands are provided on the serial console:
|
||||
```
|
||||
> lag <LAG-ID> [p1] [p2]...
|
||||
Create or set a LAG. Trunk-ID is 1 or 2. Ports are physical ports
|
||||
If only the LAG-ID is given but no members, the LAG is deleted
|
||||
|
||||
> lag show
|
||||
Shows information on all 4 lags
|
||||
|
||||
> laghash 0 [hash1] [hash2]...
|
||||
Uses the given packet properties when hashing the packet to select the link
|
||||
Names for the hashes are spa, smac, dmac, sip, dip, sport, dport
|
||||
```
|
||||
When a lag is creates, by default the hash is based on smac, dmac, sip, dip, sport, dport. When you
|
||||
use your own hash settings, make sure that the hash always uses both the source and destination
|
||||
property of the packet, as otherwise pakets will not be routed symmetrically.
|
||||
|
||||
## LAG configuration via the Web Interface
|
||||
In the web-interface select Link Aggregation in the left navigation panel. The page will look like this:
|
||||

|
||||
Each of th 4 LAGs is configured separately. After the web-page has loaded, the current configuration
|
||||
can be edited by clicking on the port-images to include that port or exclude it from a LAG.
|
||||
When pressing on the Create/Update button, the LAG will be automatically created if not yet done, or
|
||||
updated. If a lage is updated to not having any members, then it is effectively deleted.
|
||||
|
||||
All LAGs are created with the default hash-function (see above). This currently cannot be changed
|
||||
from the Web.
|
||||
|
||||
## A Test using a single Linux Desktop
|
||||
The following is a simple test using 2 RTL 2.5 GBit switches with at least 1 SFP+-port each. You
|
||||
will also need 4 10GBit SFP+ modules (DAC or Fiber) and 2 SFP+ ports on your desktop.
|
||||
|
||||
The following shows the network configuration
|
||||
```
|
||||
----------------- -----------------
|
||||
Linux Comuter | | 2.5 GBit | | same Linux Computer
|
||||
---------- 10G | P1 |------------| P1 | 10G ----------
|
||||
192.168.9.1 | SFP+ |==========| Switch 1 | 2.5 GBit | Switch 2 |==========| SFP+ | 192.168.9.2
|
||||
enp1s0f0 ---------- | P2 |------------| P2 | ---------- enp1s0f1
|
||||
| | | |
|
||||
------------------ -----------------
|
||||
```
|
||||
|
||||
On _both_ switches create a LAG with ports 1 and 2 inside and the default hash algorithm which takes
|
||||
source and destination ports into account, e.g. just use the default:
|
||||
```
|
||||
> lag 0 1 2
|
||||
```
|
||||
|
||||
|
||||
The following shows the configuration on the desktop using a dual 10GBit card with 2 SFP+ modules:
|
||||
```
|
||||
[234690.755634] ixgbe: Intel(R) 10 Gigabit PCI Express Network Driver
|
||||
[234690.755637] ixgbe: Copyright (c) 1999-2016 Intel Corporation.
|
||||
[234690.921614] ixgbe 0000:01:00.0: Multiqueue Enabled: Rx Queue count = 12, Tx Queue count = 12 XDP Queue count = 0
|
||||
[234690.921914] ixgbe 0000:01:00.0: 32.000 Gb/s available PCIe bandwidth (5.0 GT/s PCIe x8 link)
|
||||
[234690.921999] ixgbe 0000:01:00.0: MAC: 2, PHY: 19, SFP+: 5, PBA No: FFFFFF-0FF
|
||||
[234690.922002] ixgbe 0000:01:00.0: 28:41:c6:xx:xx:aa
|
||||
[234690.924946] ixgbe 0000:01:00.0: Intel(R) 10 Gigabit Network Connection
|
||||
[234690.990024] ixgbe 0000:01:00.0 enp1s0f0: renamed from eth0
|
||||
[234691.056447] ixgbe 0000:01:00.0: registered PHC device on enp1s0f0
|
||||
[234691.089417] ixgbe 0000:01:00.1: Multiqueue Enabled: Rx Queue count = 12, Tx Queue count = 12 XDP Queue count = 0
|
||||
[234691.089706] ixgbe 0000:01:00.1: 32.000 Gb/s available PCIe bandwidth (5.0 GT/s PCIe x8 link)
|
||||
[234691.089788] ixgbe 0000:01:00.1: MAC: 2, PHY: 19, SFP+: 18, PBA No: FFFFFF-0FF
|
||||
[234691.089790] ixgbe 0000:01:00.1: 28:41:c6:xx:xx:ab
|
||||
[234691.160997] ixgbe 0000:01:00.1: Intel(R) 10 Gigabit Network Connection
|
||||
[234691.166102] ixgbe 0000:01:00.1 enp1s0f1: renamed from eth0
|
||||
[234691.231579] ixgbe 0000:01:00.1: registered PHC device on enp1s0f1
|
||||
[234691.236965] ixgbe 0000:01:00.0 enp1s0f0: detected SFP+: 5
|
||||
[234691.485031] ixgbe 0000:01:00.0 enp1s0f0: NIC Link is Up 10 Gbps, Flow Control: RX/TX
|
||||
[234691.557003] ixgbe 0000:01:00.1 enp1s0f1: detected SFP+: 18
|
||||
[234691.753061] ixgbe 0000:01:00.1 enp1s0f1: NIC Link is Up 10 Gbps, Flow Control: RX/TX
|
||||
```
|
||||
|
||||
Now set up 2 network namespaces and put each interface inside one:
|
||||
```
|
||||
sudo ip netns add netns_eth0
|
||||
sudo ip netns add netns_eth1
|
||||
sudo ip link set enp1s0f0 netns netns_eth0
|
||||
sudo ip link set enp1s0f1 netns netns_eth1
|
||||
```
|
||||
|
||||
Configure network interface addresses 192.168.9.2 and 192.168.9.1 in each namespace:
|
||||
```
|
||||
sudo ip netns exec netns_eth0 ifconfig enp1s0f0 192.168.9.1 netmask 255.255.255.0
|
||||
|
||||
sudo ip netns exec netns_eth0 ip a
|
||||
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
|
||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
24: enp1s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
|
||||
link/ether 28:41:c6:xx:xx:aa brd ff:ff:ff:ff:ff:ff
|
||||
altname enx2841c6xxxxaa
|
||||
inet 192.168.9.1/24 scope global enp1s0f0
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 fe80::2a41:c6ff:fexx:xxaa/64 scope link proto kernel_ll
|
||||
valid_lft forever preferred_lft forever
|
||||
|
||||
sudo ip netns exec netns_eth1 ifconfig enp1s0f1 192.168.9.2 netmask 255.255.255.0
|
||||
|
||||
sudo ip netns exec netns_eth1 ip a
|
||||
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
|
||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
25: enp1s0f1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
|
||||
link/ether 28:41:c6:xx:xx:ab brd ff:ff:ff:ff:ff:ff
|
||||
altname enx2841c6xxxxab
|
||||
inet 192.168.9.2/24 scope global enp1s0f1
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 fe80::2a41:c6ff:fexx:xxab/64 scope link proto kernel_ll
|
||||
valid_lft forever preferred_lft forever
|
||||
```
|
||||
Test is using ping. On both switches one of the 2.5Gbit links and all 10GBit links should show activity:
|
||||
```
|
||||
$ sudo ip netns exec netns_eth1 ping 192.168.9.1
|
||||
PING 192.168.9.1 (192.168.9.1) 56(84) bytes of data.
|
||||
64 bytes from 192.168.9.1: icmp_seq=1 ttl=64 time=0.082 ms
|
||||
64 bytes from 192.168.9.1: icmp_seq=2 ttl=64 time=0.130 ms
|
||||
^C
|
||||
--- 192.168.9.1 ping statistics ---
|
||||
2 packets transmitted, 2 received, 0% packet loss, time 1030ms
|
||||
rtt min/avg/max/mdev = 0.082/0.106/0.130/0.024 ms
|
||||
```
|
||||
You can also verify that the redundancy works by unplugging the active link, the ping should continue
|
||||
undisturbed with the other link now tranporting the pakets.
|
||||
|
||||
In 2 shells, start 2 instances of iperf, listening on 2 different ports. You will need to make sure that
|
||||
the hash algorithm assigns different switch ports for the different port numbers. You can check this by
|
||||
running the iperf3 client against each server instance and verify that different links show activity:
|
||||
```
|
||||
sudo ip netns exec netns_eth0 iperf3 -s
|
||||
|
||||
sudo ip netns exec netns_eth0 iperf3 -s -p 5333
|
||||
```
|
||||
|
||||
Now you can run the clients in parallel:
|
||||
```
|
||||
$ sudo ip netns exec netns_eth1 iperf3 -c 192.168.9.1 & sudo ip netns exec netns_eth1 iperf3 -p 5333 -c 192.168.9.1
|
||||
[1] 295484
|
||||
Connecting to host 192.168.9.1, port 5201
|
||||
[ 5] local 192.168.9.2 port 60996 connected to 192.168.9.1 port 5201
|
||||
Connecting to host 192.168.9.1, port 5333
|
||||
[ 5] local 192.168.9.2 port 39660 connected to 192.168.9.1 port 5333
|
||||
[ ID] Interval Transfer Bitrate Retr Cwnd
|
||||
[ 5] 0.00-1.00 sec 283 MBytes 2.37 Gbits/sec 485 272 KBytes
|
||||
[ ID] Interval Transfer Bitrate Retr Cwnd
|
||||
[ 5] 0.00-1.00 sec 283 MBytes 2.37 Gbits/sec 479 379 KBytes
|
||||
[ 5] 1.00-2.00 sec 280 MBytes 2.35 Gbits/sec 444 260 KBytes
|
||||
[ 5] 1.00-2.00 sec 280 MBytes 2.35 Gbits/sec 578 267 KBytes
|
||||
[ 5] 2.00-3.00 sec 281 MBytes 2.36 Gbits/sec 385 263 KBytes
|
||||
[ 5] 2.00-3.00 sec 280 MBytes 2.35 Gbits/sec 373 375 KBytes
|
||||
[ 5] 3.00-4.00 sec 280 MBytes 2.35 Gbits/sec 430 385 KBytes
|
||||
[ 5] 3.00-4.00 sec 280 MBytes 2.35 Gbits/sec 452 273 KBytes
|
||||
[ 5] 4.00-5.00 sec 281 MBytes 2.36 Gbits/sec 319 256 KBytes
|
||||
[ 5] 4.00-5.00 sec 281 MBytes 2.36 Gbits/sec 425 269 KBytes
|
||||
[ 5] 5.00-6.00 sec 280 MBytes 2.35 Gbits/sec 364 264 KBytes
|
||||
[ 5] 5.00-6.00 sec 281 MBytes 2.36 Gbits/sec 561 264 KBytes
|
||||
[ 5] 6.00-7.00 sec 281 MBytes 2.35 Gbits/sec 446 255 KBytes
|
||||
[ 5] 6.00-7.00 sec 280 MBytes 2.35 Gbits/sec 582 263 KBytes
|
||||
[ 5] 7.00-8.00 sec 281 MBytes 2.35 Gbits/sec 494 263 KBytes
|
||||
[ 5] 7.00-8.00 sec 280 MBytes 2.35 Gbits/sec 539 181 KBytes
|
||||
[ 5] 8.00-9.00 sec 281 MBytes 2.36 Gbits/sec 617 389 KBytes
|
||||
[ 5] 8.00-9.00 sec 280 MBytes 2.35 Gbits/sec 490 232 KBytes
|
||||
[ 5] 9.00-10.00 sec 281 MBytes 2.35 Gbits/sec 363 215 KBytes
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
[ ID] Interval Transfer Bitrate Retr
|
||||
[ 5] 0.00-10.00 sec 2.74 GBytes 2.36 Gbits/sec 4347 sender
|
||||
[ 5] 0.00-10.00 sec 2.74 GBytes 2.35 Gbits/sec receiver
|
||||
|
||||
iperf Done.
|
||||
[ 5] 9.00-10.00 sec 282 MBytes 2.36 Gbits/sec 536 380 KBytes
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
[ ID] Interval Transfer Bitrate Retr
|
||||
[ 5] 0.00-10.00 sec 2.74 GBytes 2.36 Gbits/sec 5015 sender
|
||||
[ 5] 0.00-10.00 sec 2.74 GBytes 2.35 Gbits/sec receiver
|
||||
|
||||
iperf Done.
|
||||
[1]+ Done sudo ip netns exec netns_eth1 iperf3 -c 192.168.9.1
|
||||
```
|
||||
As you can see, the total throughput was 4.71 GBit/sec which is close to the
|
||||
maximum possible with a single 5GBit link.
|
||||
@@ -1,25 +0,0 @@
|
||||
# Trunking
|
||||
|
||||
The RTL827x allows to combine multiple ports to a single logical port
|
||||
(trunking). Up to 2 trunk groups can be defined.
|
||||
|
||||
## Trunking control
|
||||
Two registers RTL837x_TRUNK_CTRL_A (0x4f38) and RTL837x_TRUNK_CTRL_B (0x4f3c)
|
||||
define the trunk groups. Each holds a bitmap of ports making up the trunk
|
||||
group.
|
||||
|
||||
## Trunking API
|
||||
The code currently provides the following functions:
|
||||
```
|
||||
void trunk_set(uint8_t group, uint16_t mask) __banked
|
||||
```
|
||||
|
||||
# VLAN configuration on the Serial Console
|
||||
For testing the following commands are provided on the serial console:
|
||||
```
|
||||
trunk <TRUNK-ID> [p1] [p2]...
|
||||
create or set a trunk group. Trunk-ID is 1 or 2. ports a physical ports
|
||||
|
||||
trunk <VLAN-ID> d
|
||||
deletes the trunk group
|
||||
```
|
||||
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/ports.js"></script>
|
||||
<script src="/main.js"></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title>Link Aggregation Configuration</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav id="sidebar"></nav>
|
||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<div id="ports"></div>
|
||||
<h1>Link Aggregation Groups Configuration</h1>
|
||||
<h2>LAG 1 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub0" onclick="lagSub(0);" type="button" value="Update / Create"></h2>
|
||||
<div id="mLAG0"></div>
|
||||
<br />
|
||||
<h2>LAG 2 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub1" onclick="lagSub(1);" type="button" value="Update / Create"></h2>
|
||||
<div id="mLAG1"></div>
|
||||
<br />
|
||||
<h2>LAG 3 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub2" onclick="lagSub(2);" type="button" value="Update / Create"></h2>
|
||||
<div id="mLAG2"></div>
|
||||
<br />
|
||||
<h2>LAG 4 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub3" onclick="lagSub(3);" type="button" value="Update / Create"></h2>
|
||||
<div id="mLAG3"></div>
|
||||
<script src="/lag.js"></script>
|
||||
</div>
|
||||
<script src="/navigation.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
var lagInterval = Number();
|
||||
|
||||
function lagForm() {
|
||||
if (!numPorts)
|
||||
return;
|
||||
clearInterval(lagInterval);
|
||||
for (let j=0; j < 4; j++) {
|
||||
var lag = "mLAG" + j
|
||||
console.log("Adding LAG " + lag)
|
||||
var m = document.getElementById(lag);
|
||||
for (let i = 1; i <= numPorts; i++) {
|
||||
const d = document.createElement("div");
|
||||
d.classList.add("cbgroup");
|
||||
const l = document.createElement("label");
|
||||
l.innerHTML = "" + i;
|
||||
l.classList.add("cbgroup");
|
||||
const inp = document.createElement("input");
|
||||
inp.type = "checkbox"; inp.setAttribute("class","psel");
|
||||
inp.id = "p_" + lag + "_" + i;
|
||||
const o = document.createElement("img");
|
||||
if (pIsSFP[i - 1]) {
|
||||
o.src = "sfp.svg"; o.width ="60"; o.height ="60";
|
||||
} else {
|
||||
o.src = "port.svg"; o.width = "40"; o.height = "40";
|
||||
}
|
||||
l.appendChild(inp); l.appendChild(o);
|
||||
d.appendChild(l)
|
||||
m.appendChild(d);
|
||||
}
|
||||
}
|
||||
fetchLag();
|
||||
}
|
||||
|
||||
function setL(p, c){
|
||||
console.log("LAG setting: ", p, " to ", c);
|
||||
document.getElementById(p).checked=c;
|
||||
}
|
||||
window.addEventListener("load", function() {
|
||||
lagInterval = setInterval(lagForm, 200);
|
||||
});
|
||||
|
||||
function fetchLag() {
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
const s = JSON.parse(xhttp.responseText);
|
||||
console.log("LAG: ", JSON.stringify(s));
|
||||
for (let l = 0; l < 4; l++) {
|
||||
let members = parseInt(s[l].members, 2);
|
||||
let hash = parseInt(s[l].hash, 16);
|
||||
for (let i = 1; i <= numPorts; i++) {
|
||||
let p = i - 1;
|
||||
if (numPorts < 9)
|
||||
p = physToLogPort[p];
|
||||
setL("p_mLAG"+l+"_"+i, members & (1<<p));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
xhttp.open("GET", `/lag.json`, true);
|
||||
xhttp.send();
|
||||
}
|
||||
async function lagSub(l) {
|
||||
var cmd = "lag " + l;
|
||||
for (let i = 1; i <= numPorts; i++) {
|
||||
if (document.getElementById("p_mLAG"+l+"_"+i).checked)
|
||||
cmd = cmd + ` ${i}`;
|
||||
}
|
||||
try {
|
||||
const response = await fetch('/cmd', {
|
||||
method: 'POST',
|
||||
body: cmd
|
||||
});
|
||||
console.log('Completed!', response);
|
||||
} catch(err) {
|
||||
console.error(`Error: ${err}`);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<div id="ports"></div>
|
||||
<h1>Mirror Configuration</h1>
|
||||
<label class="tswitch">Enabled: <input id="me" type="checkbox"><span class="slider"></span></label><br/>
|
||||
<label class="tswitch">Enabled: <input id="me" type="checkbox"></label><br/>
|
||||
<label for="mp">Mirroring Port:</label> <input type="number" id="mp" name="mp" min="1" max="9"/>
|
||||
<h2>Mirrored Ports (TX)</h2>
|
||||
<div id="mPortsTX"></div>
|
||||
|
||||
+4
-2
@@ -49,8 +49,10 @@ function fetchMirror() {
|
||||
let m_tx = parseInt(s.mirror_tx, 2);
|
||||
let m_rx = parseInt(s.mirror_rx, 2);
|
||||
for (let i = 1; i <= numPorts; i++) {
|
||||
setM("mPortsTX"+i, m_tx&1); setM("mPortsRX"+i, m_rx&1);
|
||||
m_tx = m_tx >> 1; m_rx = m_tx >> 1;
|
||||
let p = i - 1;
|
||||
if (numPorts < 9)
|
||||
p = physToLogPort[p];members & (1<<p)
|
||||
setM("mPortsTX"+i, m_tx&(1<<p)); setM("mPortsRX"+i, m_rx&(1<<p));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ document.getElementById('sidebar').innerHTML =
|
||||
+ "<li><a href='stat.html'>Port Statistics</a></li>"
|
||||
+ "<li><a href='vlan.html'>VLAN</a></li>"
|
||||
+ "<li><a href='mirror.html'>Mirroring</a></li>"
|
||||
+ "<li><a href='trunk.html'>Port Aggregation</a></li>"
|
||||
+ "<li><a href='lag.html'>Link Aggregation</a></li>"
|
||||
+ "<li><a href='eee.html'>EEE</a></li>"
|
||||
+ "<li><a href='system.html'>System Settings</a></li>"
|
||||
+ "<li><a href='update.html'>Firmware Update</a></li></ul>";
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
const logToPhysPort = [0, 0, 0, 5, 1, 2, 3, 4, 6];
|
||||
const physToLogPort = [ 4, 5, 6, 7, 3, 8];
|
||||
|
||||
function drawPorts() {
|
||||
var f = document.getElementById('ports');
|
||||
console.log("DRAWING PORTS: ", numPorts);
|
||||
|
||||
@@ -570,6 +570,8 @@ void httpd_appcall(void)
|
||||
send_eee();
|
||||
} else if (is_word(q, "/mirror.json")) {
|
||||
send_mirror();
|
||||
} else if (is_word(q, "/lag.json")) {
|
||||
send_lag();
|
||||
} else if (is_word(q, "/config")) {
|
||||
send_config();
|
||||
} else if (is_word(q, "/cmd_log")) {
|
||||
|
||||
+29
-4
@@ -216,9 +216,8 @@ void send_counters(char port)
|
||||
|
||||
void send_mirror(void)
|
||||
{
|
||||
print_string("send_eee called\n");
|
||||
print_string("send_mirror called\n");
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
print_string("sending EEE status\n");
|
||||
|
||||
reg_read_m(RTL837x_MIRROR_CTRL);
|
||||
uint8_t mPort = sfr_data[3];
|
||||
@@ -237,14 +236,14 @@ void send_mirror(void)
|
||||
m = (m << 8) | sfr_data[1];
|
||||
slen += strtox(outbuf + slen, ",\"mirror_rx\":\"");
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
bool_to_html(m & 0x8000);
|
||||
bool_to_html(!!(m & 0x8000));
|
||||
m <<= 1;
|
||||
}
|
||||
m = sfr_data[2];
|
||||
m = (m << 8) | sfr_data[3];
|
||||
slen += strtox(outbuf + slen, "\",\"mirror_tx\":\"");
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
bool_to_html(m & 0x8000);
|
||||
bool_to_html(!!(m & 0x8000));
|
||||
m <<= 1;
|
||||
}
|
||||
char_to_html('\"');
|
||||
@@ -252,6 +251,32 @@ void send_mirror(void)
|
||||
}
|
||||
|
||||
|
||||
void send_lag(void)
|
||||
{
|
||||
print_string("send_lag called\n");
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
|
||||
char_to_html('[');
|
||||
for (uint8_t l=0; l < 4; l++) {
|
||||
slen += strtox(outbuf + slen, "{\"lagNum\":");
|
||||
itoa_html(l);
|
||||
slen += strtox(outbuf + slen, ",\"members\":\"");
|
||||
reg_read_m(RTL837X_TRK_MBR_CTRL_BASE + (l << 2));
|
||||
uint16_t ports = ((uint16_t)sfr_data[2] << 8) | sfr_data[3];
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
bool_to_html(!!(ports & 0x8000));
|
||||
ports <<= 1;
|
||||
}
|
||||
slen += strtox(outbuf + slen, "\",\"hash\":\"");
|
||||
reg_read_m(RTL837X_TRK_HASH_CTRL_BASE + (l << 2));
|
||||
sfr_data_to_html();
|
||||
slen += strtox(outbuf + slen, "\"},");
|
||||
}
|
||||
slen -=1; // remove comma
|
||||
char_to_html(']');
|
||||
}
|
||||
|
||||
|
||||
void send_eee(void)
|
||||
{
|
||||
print_string("send_eee called\nsending EEE status\n");
|
||||
|
||||
@@ -9,6 +9,7 @@ void send_eee(void);
|
||||
void send_mirror(void);
|
||||
void send_config(void);
|
||||
void send_cmd_log(void);
|
||||
void send_lag(void);
|
||||
|
||||
/* Convert only the lower nibble to ascii HEX char.
|
||||
For convenience the upper nibble is masked out.
|
||||
|
||||
+43
-27
@@ -212,10 +212,10 @@ void vlan_setup(void) __banked
|
||||
write_char(' '); write_char('A'); write_char('>'); print_sfr_data();
|
||||
#endif
|
||||
|
||||
// EGRESS filtering for port: removal of additional VLAN tag
|
||||
reg_bit_clear(0x6738, i << 1);
|
||||
reg_bit_clear(0x6738, (i << 1) + 1);
|
||||
reg_bit_set(0x4e18, i);
|
||||
// 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) + 1);
|
||||
reg_bit_set(RTL837X_VLAN_PORT_IGR_FLTR, i);
|
||||
|
||||
#ifdef DEBUG
|
||||
print_string("\n");
|
||||
@@ -226,9 +226,9 @@ void vlan_setup(void) __banked
|
||||
REG_SET(RTL837x_REG_INGRESS, 0); // No filtering for all ports
|
||||
|
||||
// Enable 4k VLAN
|
||||
REG_SET(0x4e14, 4);
|
||||
REG_SET(0x4e30, 0);
|
||||
REG_SET(0x4e34, 0);
|
||||
REG_SET(RTL837X_VLAN_CTRL, VLAN_CVLAN_FILTER);
|
||||
REG_SET(RTL837X_VLAN_L2_LRN_DIS_0, 0);
|
||||
REG_SET(RTL837X_VLAN_L2_LRN_DIS_1, 0);
|
||||
|
||||
// Enable VLAN 1: Ports 0-9, i.e. including the CPU port are untagged members
|
||||
if (isRTL8373) {
|
||||
@@ -241,12 +241,6 @@ void vlan_setup(void) __banked
|
||||
reg_read_m(RTL837X_TBL_CTRL);
|
||||
} while (sfr_data[3] & TBL_EXECUTE);
|
||||
|
||||
// Configure trunking
|
||||
if (isRTL8373) {
|
||||
REG_SET(0x4f4c, 0x0000007e); // Removes RTL VLAN-Tags
|
||||
REG_SET(0x4f48, 0x0000007e); // Adds 802.1Q VLAN-Tags to tagged ports
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
print_string("\nvlan_setup, REG 0x6738: "); print_reg(0x6738);
|
||||
print_string("\nvlan_setup, REG 0x4e18: "); print_reg(0x4e18);
|
||||
@@ -261,18 +255,6 @@ void vlan_setup(void) __banked
|
||||
}
|
||||
|
||||
|
||||
void trunk_set(uint8_t group, uint16_t mask) __banked
|
||||
{
|
||||
if (group == 1) {
|
||||
REG_WRITE(RTL837x_TRUNK_CTRL_A, 0, 0, mask >> 8, mask);
|
||||
} else if (group == 2) {
|
||||
REG_WRITE(RTL837x_TRUNK_CTRL_B, 0, 0, mask >> 8, mask);
|
||||
} else {
|
||||
print_string("\nTrunk group must be 1 or 2\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Forget all dynamic L2 learned entries
|
||||
*/
|
||||
@@ -377,7 +359,8 @@ void port_l2_setup(void) __banked
|
||||
port_l2_forget();
|
||||
|
||||
for (uint8_t i = minPort; i <= maxPort; i++) {
|
||||
uint16_t reg = 0x5384 + (i << 2);
|
||||
// Limit the number of automatically learned MAC-Entries per port to 0x1040
|
||||
uint16_t reg = RTL837X_L2_LRN_PORT_CONSTRAINT + (i << 2);
|
||||
REG_SET(reg, 0x00001040);
|
||||
|
||||
// All ports may communicate with each other and CPU-Port
|
||||
@@ -388,7 +371,8 @@ void port_l2_setup(void) __banked
|
||||
REG_SET(reg, PMASK_6 | PMASK_CPU);
|
||||
}
|
||||
}
|
||||
reg_bit_set(0x4f80, 0);
|
||||
// When maximim entries learned, then simply flood the packet
|
||||
reg_bit_set(RTL837X_L2_LRN_PORT_CONSTRT_ACT, 0);
|
||||
|
||||
print_string("\nport_l2_setup done\n");
|
||||
}
|
||||
@@ -597,3 +581,35 @@ void port_rldp_on(__xdata uint16_t p_ms)
|
||||
REG_SET(RTL837X_RMA0_CONF, 0x00000000); // R4ecc
|
||||
REG_SET(RTL837X_RMA_CONF, 0x00000000); // R4ecc
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Configure LAGs
|
||||
* Sets the members via port bitmask of a given Link Aggregation Group
|
||||
* The groups have numbers 0-3
|
||||
* The bitmask represents up to 10 ports
|
||||
* If currently no LAG has algorithm used, a default is applied
|
||||
*/
|
||||
void port_lag_members_set(__xdata uint8_t lag, __xdata uint16_t members) __banked
|
||||
{
|
||||
print_string("port_lag_members_set, lag: "); print_byte(lag); print_string(", members: "); print_short(members);
|
||||
if (lag > 3)
|
||||
print_string("Link aggregation group must be 0-3!");
|
||||
reg_read_m(RTL837X_TRK_HASH_CTRL_BASE + (lag << 2));
|
||||
if (!(sfr_data[0] | sfr_data [1] | sfr_data [2] | sfr_data [3]))
|
||||
REG_SET(RTL837X_TRK_HASH_CTRL_BASE, LAG_HASH_DEFAULT);
|
||||
REG_WRITE(RTL837X_TRK_MBR_CTRL_BASE + (lag << 2), 0, 0, members >> 8, members & 0xff);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Configures the hash algorithm used for a LAG
|
||||
* lag is the Group to configure and hash is a bitmask
|
||||
*/
|
||||
void port_lag_hash_set(__xdata uint8_t lag, __xdata uint8_t hash_bits) __banked
|
||||
{
|
||||
print_string("port_lag_hash_set, lag: "); print_byte(lag); print_string(", hash: "); print_byte(hash_bits);
|
||||
if (lag > 3)
|
||||
print_string("Link aggregation group must be 0-3!");
|
||||
REG_WRITE(RTL837X_TRK_HASH_CTRL_BASE + (lag << 2), 0, 0, 0, hash_bits);
|
||||
}
|
||||
|
||||
+2
-1
@@ -26,7 +26,8 @@ void port_mirror_set(register uint8_t port, __xdata uint16_t rx_pmask, __xdata u
|
||||
void port_mirror_del(void) __banked;
|
||||
void port_ingress_filter(register uint8_t port, uint8_t type) __banked;
|
||||
void port_l2_setup(void) __banked;
|
||||
void trunk_set(uint8_t group, uint16_t mask) __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_eee_enable_all(void) __banked;
|
||||
void port_eee_disable_all(void) __banked;
|
||||
void port_eee_status_all(void) __banked;
|
||||
|
||||
+22
-3
@@ -117,6 +117,17 @@
|
||||
#define RTL837x_L2_TBL_FLUSH_CTRL 0x53d4
|
||||
#define L2_TBL_FLUSH_EXEC 0x10000
|
||||
#define RTL837x_L2_TBL_FLUSH_CNF 0x53dc
|
||||
#define RTL837X_L2_LRN_PORT_CONSTRAINT 0x5384
|
||||
#define RTL837X_L2_LRN_PORT_CONSTRT_ACT 0x4f80
|
||||
/*
|
||||
* VLAN configuration
|
||||
*/
|
||||
#define RTL837X_VLAN_CTRL 0x4e14
|
||||
#define VLAN_CVLAN_FILTER 0x4
|
||||
#define RTL837X_VLAN_PORT_EGR_TAG 0x6738
|
||||
#define RTL837X_VLAN_PORT_IGR_FLTR 0x4e18
|
||||
#define RTL837X_VLAN_L2_LRN_DIS_0 0x4e30
|
||||
#define RTL837X_VLAN_L2_LRN_DIS_1 0x4e34
|
||||
|
||||
/*
|
||||
* Egress / ingress filtering
|
||||
@@ -134,10 +145,18 @@
|
||||
#define RTL837x_MIRROR_CTRL 0x6048
|
||||
|
||||
/*
|
||||
* Trunking
|
||||
* Link Aggregation aka Trunking
|
||||
*/
|
||||
#define RTL837x_TRUNK_CTRL_A 0x4f38
|
||||
#define RTL837x_TRUNK_CTRL_B 0x4f3c
|
||||
#define RTL837X_TRK_MBR_CTRL_BASE 0x4f38
|
||||
#define RTL837X_TRK_HASH_CTRL_BASE 0x4f48
|
||||
#define LAG_HASH_SOURCE_PORT_NUMBER 0x01
|
||||
#define LAG_HASH_L2_SMAC 0x02
|
||||
#define LAG_HASH_L2_DMAC 0x04
|
||||
#define LAG_HASH_L3_SIP 0x08
|
||||
#define LAG_HASH_L3_DIP 0x10
|
||||
#define LAG_HASH_L4_SPORT 0x20
|
||||
#define LAG_HASH_L4_DPORT 0x40
|
||||
#define LAG_HASH_DEFAULT (LAG_HASH_L2_SMAC | LAG_HASH_L2_DMAC | LAG_HASH_L3_SIP | LAG_HASH_L3_DIP | LAG_HASH_L4_SPORT | LAG_HASH_L4_DPORT)
|
||||
|
||||
/*
|
||||
* Port isolation
|
||||
|
||||
+33
-1
@@ -13,7 +13,7 @@
|
||||
|
||||
#define SESSION_ID "1234567890ab"
|
||||
#define PASSWORD "1234"
|
||||
#define SESSION_TIMEOUT 20
|
||||
#define SESSION_TIMEOUT 2000
|
||||
|
||||
#define PORTS 6
|
||||
time_t last_called;
|
||||
@@ -216,6 +216,31 @@ void send_mirror(int s)
|
||||
}
|
||||
|
||||
|
||||
void send_lag(int s)
|
||||
{
|
||||
char lag_buf[20];
|
||||
struct json_object *lags = json_object_new_array_ext(4);
|
||||
struct json_object *v;
|
||||
const char *jstring;
|
||||
char *header = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
v = json_object_new_object();
|
||||
json_object_object_add(v, "lagNum", json_object_new_int(i));
|
||||
sprintf(lag_buf, "%016b", 0x30 << (i * 2) & 0x1f8);
|
||||
json_object_object_add(v, "members", json_object_new_string(lag_buf));
|
||||
json_object_object_add(v, "hash", json_object_new_string("0x7e"));
|
||||
json_object_array_add(lags, v);
|
||||
}
|
||||
write(s, header, strlen(header));
|
||||
|
||||
jstring = json_object_to_json_string_ext(lags, JSON_C_TO_STRING_PLAIN);
|
||||
write(s, jstring, strlen(jstring));
|
||||
json_object_put(lags);
|
||||
}
|
||||
|
||||
|
||||
void send_cmd_log(int s)
|
||||
{
|
||||
char *header = "HTTP/1.1 200 OK\r\n"
|
||||
@@ -417,6 +442,13 @@ void launch(struct Server *server)
|
||||
else
|
||||
send_mirror(new_socket);
|
||||
goto done;
|
||||
} else if (!strncmp(&buffer[4], "/lag.json", 9)) {
|
||||
printf("LAG request\n");
|
||||
if (!authenticated)
|
||||
send_unauthorized(new_socket);
|
||||
else
|
||||
send_lag(new_socket);
|
||||
goto done;
|
||||
} else if (!strncmp(&buffer[4], "/vlan.json?vid=", 15)) {
|
||||
int vlan = atoi(&buffer[19]);
|
||||
printf("VLAN request for %d\n", vlan);
|
||||
|
||||
Reference in New Issue
Block a user