Merge pull request #43 from logicog/lags

feature LAGs support.
This commit is contained in:
René van Dorst
2025-12-07 09:12:21 +00:00
committed by GitHub
17 changed files with 595 additions and 146 deletions
+118 -78
View File
@@ -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++) { for (i = cmd_words_b[start]; i != cmd_words_b[start + 1] && cmd_buffer[i] != ' '; i++) {
i &= SBUF_SIZE - 1; 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"); // 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; return 1;
if (cmd_buffer[i] != cmd[j++]) if (cmd_buffer[i] != cmd[j++])
break; break;
} }
// write_char('.'); print_short(i); write_char(':'); print_short(i); // write_char('.'); print_byte(i); write_char(':'); print_byte(j); write_char(','); print_byte (cmd[j-1]);
if (i == cmd_words_b[start + 1] || cmd_buffer[i] == ' ') // write_char(','); print_byte(cmd[j]);
if (i == cmd_words_b[start + 1] || (cmd_buffer[i] == ' ' && !cmd[j]))
return 1; return 1;
return 0; 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 uint8_t group;
__xdata uint16_t members = 0; __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'; group = cmd_buffer[cmd_words_b[1]] - '0';
uint8_t w = 2; 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; uint8_t port;
if (isnumber(cmd_buffer[cmd_words_b[w]])) { if (isnumber(cmd_buffer[cmd_words_b[w]])) {
port = cmd_buffer[cmd_words_b[w]] - '1'; port = cmd_buffer[cmd_words_b[w]] - '1';
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) if (port > maxPort)
goto err; goto err;
members |= ((uint16_t)1) << port; 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++; w++;
} }
trunk_set(group, members); port_lag_hash_set(group, hash);
return;
err:
print_string("Error: trunk <trunk-id> [port]...");
} }
@@ -553,8 +626,7 @@ void cmd_parser(void) __banked
if (cmd_compare(0, "reset")) { if (cmd_compare(0, "reset")) {
print_string("\nRESET\n\n"); print_string("\nRESET\n\n");
reset_chip(); reset_chip();
} } else if (cmd_compare(0, "sfp")) {
if (cmd_compare(0, "sfp")) {
uint8_t rate = sfp_read_reg(0, 12); uint8_t rate = sfp_read_reg(0, 12);
print_string("\nRate: "); print_byte(rate); print_string("\nRate: "); print_byte(rate);
print_string(" Encoding: "); print_byte(sfp_read_reg(0, 11)); print_string(" Encoding: "); print_byte(sfp_read_reg(0, 11));
@@ -564,11 +636,9 @@ void cmd_parser(void) __banked
if (c) if (c)
write_char(c); write_char(c);
} }
} } else if (cmd_compare(0, "stat")) {
if (cmd_compare(0, "stat")) {
port_stats_print(); port_stats_print();
} } else if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'r') {
if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'r') {
print_string("\nPRINT SECURITY REGISTERS\n"); print_string("\nPRINT SECURITY REGISTERS\n");
// The following will only show something else than 0xff if it was programmed for a managed switch // The following will only show something else than 0xff if it was programmed for a managed switch
flash_region.addr = 0x0001000; flash_region.addr = 0x0001000;
@@ -580,44 +650,36 @@ void cmd_parser(void) __banked
flash_region.addr = 0x0003000; flash_region.addr = 0x0003000;
flash_region.len = 40; flash_region.len = 40;
flash_read_security(); flash_read_security();
} } else if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'd') {
if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'd') {
print_string("\nDUMPING FLASH\n"); print_string("\nDUMPING FLASH\n");
flash_region.addr = 0; flash_region.addr = 0;
flash_region.len = 255; flash_region.len = 255;
flash_dump(255); flash_dump(255);
} } else if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'j') {
if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'j') {
print_string("\nJEDEC ID\n"); print_string("\nJEDEC ID\n");
flash_read_jedecid(); flash_read_jedecid();
} } else if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'u') {
if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'u') {
print_string("\nUNIQUE ID\n"); print_string("\nUNIQUE ID\n");
flash_read_uid(); flash_read_uid();
} } else if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 's') {
// Switch to flash 62.5 MHz mode print_string("\nFLASH FAST MODE\n"); // 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");
flash_init(1); flash_init(1);
print_string("\nNow dumping flash\n"); print_string("\nNow dumping flash\n");
flash_region.addr = 0; flash_region.addr = 0;
flash_region.len = 255; flash_region.len = 255;
flash_dump(255); flash_dump(255);
} } else if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'e') {
if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'e') {
print_string("\nFLASH erase\n"); print_string("\nFLASH erase\n");
flash_region.addr = 0x20000; flash_region.addr = 0x20000;
flash_sector_erase(); flash_sector_erase();
} } else if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'w') {
if (cmd_compare(0, "flash") && cmd_words_b[1] > 0 && cmd_buffer[cmd_words_b[1]] == 'w') {
print_string("\nFLASH write\n"); print_string("\nFLASH write\n");
for (uint8_t i = 0; i < 20; i++) for (uint8_t i = 0; i < 20; i++)
flash_buf[i] = greeting[i]; flash_buf[i] = greeting[i];
flash_region.addr = 0x200000; flash_region.addr = 0x200000;
flash_region.len = 20; flash_region.len = 20;
flash_write_bytes(flash_buf); flash_write_bytes(flash_buf);
} } else if (cmd_compare(0, "port") && cmd_words_b[1] > 0) {
if (cmd_compare(0, "port") && cmd_words_b[1] > 0) {
print_string("\nPORT "); print_string("\nPORT ");
uint8_t p = cmd_buffer[cmd_words_b[1]] - '1'; uint8_t p = cmd_buffer[cmd_words_b[1]] - '1';
print_byte(p); print_byte(p);
@@ -637,8 +699,7 @@ void cmd_parser(void) __banked
print_string(" OFF\n"); print_string(" OFF\n");
phy_set_mode(p, PHY_OFF, 0, 0); phy_set_mode(p, PHY_OFF, 0, 0);
} }
} } else if (cmd_compare(0, "ip")) {
if (cmd_compare(0, "ip")) {
print_string("Got ip command: "); print_string("Got ip command: ");
if (!parse_ip(cmd_words_b[1])) if (!parse_ip(cmd_words_b[1]))
uip_ipaddr(&uip_hostaddr, ip[0], ip[1], ip[2], ip[3]); 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_string("Invalid IP address\n");
print_byte(ip[0]); print_byte(ip[1]); print_byte(ip[2]); print_byte(ip[3]); print_byte(ip[0]); print_byte(ip[1]); print_byte(ip[2]); print_byte(ip[3]);
write_char('\n'); write_char('\n');
} } else if (cmd_compare(0, "gw")) {
if (cmd_compare(0, "gw")) {
print_string("Got gw command: "); print_string("Got gw command: ");
if (!parse_ip(cmd_words_b[1])) if (!parse_ip(cmd_words_b[1]))
uip_ipaddr(&uip_draddr, ip[0], ip[1], ip[2], ip[3]); 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_string("Invalid IP address\n");
print_byte(ip[0]); print_byte(ip[1]); print_byte(ip[2]); print_byte(ip[3]); print_byte(ip[0]); print_byte(ip[1]); print_byte(ip[2]); print_byte(ip[3]);
write_char('\n'); write_char('\n');
} } else if (cmd_compare(0, "netmask")) {
if (cmd_compare(0, "netmask")) {
print_string("Got netmask command: "); print_string("Got netmask command: ");
if (!parse_ip(cmd_words_b[1])) if (!parse_ip(cmd_words_b[1]))
uip_ipaddr(&uip_netmask, ip[0], ip[1], ip[2], ip[3]); 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_string("Invalid IP address\n");
print_byte(ip[0]);print_byte(ip[1]);print_byte(ip[2]);print_byte(ip[3]); print_byte(ip[0]);print_byte(ip[1]);print_byte(ip[2]);print_byte(ip[3]);
write_char('\n'); write_char('\n');
} } else if (cmd_compare(0, "l2")) {
if (cmd_compare(0, "l2")) {
if (cmd_words_b[1] > 0 && cmd_compare(1, "forget")) if (cmd_words_b[1] > 0 && cmd_compare(1, "forget"))
port_l2_forget(); port_l2_forget();
else else
port_l2_learned(); port_l2_learned();
} } else if (cmd_compare(0, "stp")) {
if (cmd_compare(0, "stp")) {
if (cmd_words_b[1] > 0 && cmd_compare(1, "on")) { if (cmd_words_b[1] > 0 && cmd_compare(1, "on")) {
print_string("STP enabled\n"); print_string("STP enabled\n");
stpEnabled = 1; stpEnabled = 1;
@@ -681,8 +738,7 @@ void cmd_parser(void) __banked
stp_off(); stp_off();
stpEnabled = 0; stpEnabled = 0;
} }
} } else if (cmd_compare(0, "pvid") && cmd_words_b[1] > 0 && cmd_words_b[2] > 0) {
if (cmd_compare(0, "pvid") && cmd_words_b[1] > 0 && cmd_words_b[2] > 0) {
__xdata uint16_t pvid; __xdata uint16_t pvid;
uint8_t port; uint8_t port;
port = cmd_buffer[cmd_words_b[1]] - '1'; port = cmd_buffer[cmd_words_b[1]] - '1';
@@ -690,35 +746,27 @@ void cmd_parser(void) __banked
port = phys_to_log_port[port]; port = phys_to_log_port[port];
if (!atoi_short(&pvid, cmd_words_b[2])) if (!atoi_short(&pvid, cmd_words_b[2]))
port_pvid_set(port, pvid); port_pvid_set(port, pvid);
} } else if (cmd_compare(0, "vlan")) {
if (cmd_compare(0, "vlan")) {
parse_vlan(); parse_vlan();
} } else if (cmd_compare(0, "mirror")) {
if (cmd_compare(0, "mirror")) {
parse_mirror(); parse_mirror();
} } else if (cmd_compare(0, "lag")) {
if (cmd_compare(0, "trunk")) { parse_lag();
parse_trunk(); } else if (cmd_compare(0, "laghash")) {
} parse_lag_hash();
if (cmd_compare(0, "sds")) { } else if (cmd_compare(0, "sds")) {
print_reg(RTL837X_REG_SDS_MODES); print_reg(RTL837X_REG_SDS_MODES);
} } else if (cmd_compare(0, "gpio")) {
if (cmd_compare(0, "gpio")) {
print_gpio_status(); print_gpio_status();
} } else if (cmd_compare(0, "regget")) {
if (cmd_compare(0, "regget")) {
parse_regget(); parse_regget();
} } else if (cmd_compare(0, "regset")) {
if (cmd_compare(0, "regset")) {
parse_regset(); parse_regset();
} } else if (cmd_compare(0, "rnd")) {
if (cmd_compare(0, "rnd")) {
parse_rnd(); parse_rnd();
} } else if (cmd_compare(0, "passwd")) {
if (cmd_compare(0, "passwd")) {
parse_passwd(); parse_passwd();
} } else if (cmd_compare(0, "eee")) {
if (cmd_compare(0, "eee")) {
int8_t port = -1; int8_t port = -1;
if (cmd_words_b[3] > 0) { if (cmd_words_b[3] > 0) {
port = cmd_buffer[cmd_words_b[2]] - '1'; port = cmd_buffer[cmd_words_b[2]] - '1';
@@ -741,17 +789,15 @@ void cmd_parser(void) __banked
else else
port_eee_status_all(); port_eee_status_all();
} }
} } else if (cmd_compare(0, "version")) {
if (cmd_compare(0, "version")) {
print_sw_version(); print_sw_version();
} } else if (cmd_compare(0, "history")) {
if (cmd_compare(0, "history")) {
__xdata uint16_t p = (cmd_history_ptr + 1) & CMD_HISTORY_MASK; __xdata uint16_t p = (cmd_history_ptr + 1) & CMD_HISTORY_MASK;
__xdata uint8_t found_begin = 0; __xdata uint8_t found_begin = 0;
print_string("History ptr: "); // print_string("History ptr: ");
print_short(cmd_history_ptr); write_char('\n'); // print_short(cmd_history_ptr); write_char('\n');
while (p != cmd_history_ptr) { while (p != cmd_history_ptr) {
print_short(p); write_char(' '); // print_short(p); write_char(' ');
if (!cmd_history[p] || cmd_history[p] == '\n') if (!cmd_history[p] || cmd_history[p] == '\n')
found_begin = 1; found_begin = 1;
if (found_begin && cmd_history[p]) if (found_begin && cmd_history[p])
@@ -793,8 +839,6 @@ void execute_config(void) __banked
do { do {
flash_region.addr = pos; flash_region.addr = pos;
flash_region.len = FLASH_READ_BURST_SIZE; 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); flash_read_bulk(flash_buf);
uint8_t cfg_idx = 0; uint8_t cfg_idx = 0;
@@ -802,11 +846,8 @@ void execute_config(void) __banked
do { do {
for (uint8_t cmd_idx = 0; cmd_idx < (SBUF_SIZE - 1); cmd_idx++) { for (uint8_t cmd_idx = 0; cmd_idx < (SBUF_SIZE - 1); cmd_idx++) {
c = flash_buf[cfg_idx++]; c = flash_buf[cfg_idx++];
print_byte(c);
if (c == 0 || c == '\n') { if (c == 0 || c == '\n') {
cmd_buffer[cmd_idx] = '\0'; 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()) if (cmd_idx && !cmd_tokenize())
cmd_parser(); cmd_parser();
if (c == 0) if (c == 0)
@@ -816,7 +857,6 @@ void execute_config(void) __banked
cmd_buffer[cmd_idx] = c; cmd_buffer[cmd_idx] = c;
} }
write_char('N');
} while(cfg_idx); } while(cfg_idx);
len_left -= FLASH_READ_BURST_SIZE; len_left -= FLASH_READ_BURST_SIZE;
Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

+227
View File
@@ -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:
![Alt text](images/LAG_config.png?raw=true "Link Aggregation Web-Page")
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.
-25
View File
@@ -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
```
+28
View File
@@ -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
View File
@@ -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
View File
@@ -10,7 +10,7 @@
<div style="margin-left:16%;padding:1px 16px;height:1000px;"> <div style="margin-left:16%;padding:1px 16px;height:1000px;">
<div id="ports"></div> <div id="ports"></div>
<h1>Mirror Configuration</h1> <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"/> <label for="mp">Mirroring Port:</label> <input type="number" id="mp" name="mp" min="1" max="9"/>
<h2>Mirrored Ports (TX)</h2> <h2>Mirrored Ports (TX)</h2>
<div id="mPortsTX"></div> <div id="mPortsTX"></div>
+4 -2
View File
@@ -49,8 +49,10 @@ function fetchMirror() {
let m_tx = parseInt(s.mirror_tx, 2); let m_tx = parseInt(s.mirror_tx, 2);
let m_rx = parseInt(s.mirror_rx, 2); let m_rx = parseInt(s.mirror_rx, 2);
for (let i = 1; i <= numPorts; i++) { for (let i = 1; i <= numPorts; i++) {
setM("mPortsTX"+i, m_tx&1); setM("mPortsRX"+i, m_rx&1); let p = i - 1;
m_tx = m_tx >> 1; m_rx = m_tx >> 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
View File
@@ -3,7 +3,7 @@ document.getElementById('sidebar').innerHTML =
+ "<li><a href='stat.html'>Port Statistics</a></li>" + "<li><a href='stat.html'>Port Statistics</a></li>"
+ "<li><a href='vlan.html'>VLAN</a></li>" + "<li><a href='vlan.html'>VLAN</a></li>"
+ "<li><a href='mirror.html'>Mirroring</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='eee.html'>EEE</a></li>"
+ "<li><a href='system.html'>System Settings</a></li>" + "<li><a href='system.html'>System Settings</a></li>"
+ "<li><a href='update.html'>Firmware Update</a></li></ul>"; + "<li><a href='update.html'>Firmware Update</a></li></ul>";
+3
View File
@@ -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() { function drawPorts() {
var f = document.getElementById('ports'); var f = document.getElementById('ports');
console.log("DRAWING PORTS: ", numPorts); console.log("DRAWING PORTS: ", numPorts);
+2
View File
@@ -570,6 +570,8 @@ void httpd_appcall(void)
send_eee(); send_eee();
} else if (is_word(q, "/mirror.json")) { } else if (is_word(q, "/mirror.json")) {
send_mirror(); send_mirror();
} else if (is_word(q, "/lag.json")) {
send_lag();
} else if (is_word(q, "/config")) { } else if (is_word(q, "/config")) {
send_config(); send_config();
} else if (is_word(q, "/cmd_log")) { } else if (is_word(q, "/cmd_log")) {
+29 -4
View File
@@ -216,9 +216,8 @@ void send_counters(char port)
void send_mirror(void) void send_mirror(void)
{ {
print_string("send_eee called\n"); print_string("send_mirror called\n");
slen = strtox(outbuf, HTTP_RESPONCE_JSON); slen = strtox(outbuf, HTTP_RESPONCE_JSON);
print_string("sending EEE status\n");
reg_read_m(RTL837x_MIRROR_CTRL); reg_read_m(RTL837x_MIRROR_CTRL);
uint8_t mPort = sfr_data[3]; uint8_t mPort = sfr_data[3];
@@ -237,14 +236,14 @@ void send_mirror(void)
m = (m << 8) | sfr_data[1]; m = (m << 8) | sfr_data[1];
slen += strtox(outbuf + slen, ",\"mirror_rx\":\""); slen += strtox(outbuf + slen, ",\"mirror_rx\":\"");
for (uint8_t i = 0; i < 16; i++) { for (uint8_t i = 0; i < 16; i++) {
bool_to_html(m & 0x8000); bool_to_html(!!(m & 0x8000));
m <<= 1; m <<= 1;
} }
m = sfr_data[2]; m = sfr_data[2];
m = (m << 8) | sfr_data[3]; m = (m << 8) | sfr_data[3];
slen += strtox(outbuf + slen, "\",\"mirror_tx\":\""); slen += strtox(outbuf + slen, "\",\"mirror_tx\":\"");
for (uint8_t i = 0; i < 16; i++) { for (uint8_t i = 0; i < 16; i++) {
bool_to_html(m & 0x8000); bool_to_html(!!(m & 0x8000));
m <<= 1; m <<= 1;
} }
char_to_html('\"'); 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) void send_eee(void)
{ {
print_string("send_eee called\nsending EEE status\n"); print_string("send_eee called\nsending EEE status\n");
+1
View File
@@ -9,6 +9,7 @@ void send_eee(void);
void send_mirror(void); void send_mirror(void);
void send_config(void); void send_config(void);
void send_cmd_log(void); void send_cmd_log(void);
void send_lag(void);
/* Convert only the lower nibble to ascii HEX char. /* Convert only the lower nibble to ascii HEX char.
For convenience the upper nibble is masked out. For convenience the upper nibble is masked out.
+43 -27
View File
@@ -212,10 +212,10 @@ void vlan_setup(void) __banked
write_char(' '); write_char('A'); write_char('>'); print_sfr_data(); write_char(' '); write_char('A'); write_char('>'); print_sfr_data();
#endif #endif
// EGRESS filtering for port: removal of additional VLAN tag // EGRESS filtering for port: removal of additional VLAN tag (mode 0x3 for each port)
reg_bit_clear(0x6738, i << 1); reg_bit_clear(RTL837X_VLAN_PORT_EGR_TAG, i << 1);
reg_bit_clear(0x6738, (i << 1) + 1); reg_bit_clear(RTL837X_VLAN_PORT_EGR_TAG, (i << 1) + 1);
reg_bit_set(0x4e18, i); reg_bit_set(RTL837X_VLAN_PORT_IGR_FLTR, i);
#ifdef DEBUG #ifdef DEBUG
print_string("\n"); print_string("\n");
@@ -226,9 +226,9 @@ void vlan_setup(void) __banked
REG_SET(RTL837x_REG_INGRESS, 0); // No filtering for all ports REG_SET(RTL837x_REG_INGRESS, 0); // No filtering for all ports
// Enable 4k VLAN // Enable 4k VLAN
REG_SET(0x4e14, 4); REG_SET(RTL837X_VLAN_CTRL, VLAN_CVLAN_FILTER);
REG_SET(0x4e30, 0); REG_SET(RTL837X_VLAN_L2_LRN_DIS_0, 0);
REG_SET(0x4e34, 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 // Enable VLAN 1: Ports 0-9, i.e. including the CPU port are untagged members
if (isRTL8373) { if (isRTL8373) {
@@ -241,12 +241,6 @@ void vlan_setup(void) __banked
reg_read_m(RTL837X_TBL_CTRL); reg_read_m(RTL837X_TBL_CTRL);
} while (sfr_data[3] & TBL_EXECUTE); } 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 #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 0x4e18: "); print_reg(0x4e18); 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 * Forget all dynamic L2 learned entries
*/ */
@@ -377,7 +359,8 @@ void port_l2_setup(void) __banked
port_l2_forget(); port_l2_forget();
for (uint8_t i = minPort; i <= maxPort; i++) { 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); REG_SET(reg, 0x00001040);
// All ports may communicate with each other and CPU-Port // 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_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"); 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_RMA0_CONF, 0x00000000); // R4ecc
REG_SET(RTL837X_RMA_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
View File
@@ -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_mirror_del(void) __banked;
void port_ingress_filter(register uint8_t port, uint8_t type) __banked; void port_ingress_filter(register uint8_t port, uint8_t type) __banked;
void port_l2_setup(void) __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_enable_all(void) __banked;
void port_eee_disable_all(void) __banked; void port_eee_disable_all(void) __banked;
void port_eee_status_all(void) __banked; void port_eee_status_all(void) __banked;
+22 -3
View File
@@ -117,6 +117,17 @@
#define RTL837x_L2_TBL_FLUSH_CTRL 0x53d4 #define RTL837x_L2_TBL_FLUSH_CTRL 0x53d4
#define L2_TBL_FLUSH_EXEC 0x10000 #define L2_TBL_FLUSH_EXEC 0x10000
#define RTL837x_L2_TBL_FLUSH_CNF 0x53dc #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 * Egress / ingress filtering
@@ -134,10 +145,18 @@
#define RTL837x_MIRROR_CTRL 0x6048 #define RTL837x_MIRROR_CTRL 0x6048
/* /*
* Trunking * Link Aggregation aka Trunking
*/ */
#define RTL837x_TRUNK_CTRL_A 0x4f38 #define RTL837X_TRK_MBR_CTRL_BASE 0x4f38
#define RTL837x_TRUNK_CTRL_B 0x4f3c #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 * Port isolation
+33 -1
View File
@@ -13,7 +13,7 @@
#define SESSION_ID "1234567890ab" #define SESSION_ID "1234567890ab"
#define PASSWORD "1234" #define PASSWORD "1234"
#define SESSION_TIMEOUT 20 #define SESSION_TIMEOUT 2000
#define PORTS 6 #define PORTS 6
time_t last_called; 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) void send_cmd_log(int s)
{ {
char *header = "HTTP/1.1 200 OK\r\n" char *header = "HTTP/1.1 200 OK\r\n"
@@ -417,6 +442,13 @@ void launch(struct Server *server)
else else
send_mirror(new_socket); send_mirror(new_socket);
goto done; 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)) { } else if (!strncmp(&buffer[4], "/vlan.json?vid=", 15)) {
int vlan = atoi(&buffer[19]); int vlan = atoi(&buffer[19]);
printf("VLAN request for %d\n", vlan); printf("VLAN request for %d\n", vlan);