diff --git a/cmd_parser.c b/cmd_parser.c index bd2fc544..4fc2b0cf 100644 --- a/cmd_parser.c +++ b/cmd_parser.c @@ -395,7 +395,7 @@ void parse_lag(void) return; } - if (cmd_words_len < 2) + if (cmd_words_len < 3) goto err; // Parse group, expect only one number 0-9; @@ -406,10 +406,13 @@ void parse_lag(void) if (group > 3) goto err; + if (cmd_compare(2, "d")) { + port_lag_members_set(group, 0); + return; + } + uint8_t w = 2; while (w < cmd_words_len) { -// write_char('|'); print_byte(w); write_char(':'); write_char(cmd_buffer[cmd_words_b[w]]); write_char('-'); - // Parse port. if (cmd_parse_port_separator(cmd_words_b[w++]) == 0) goto err; @@ -419,7 +422,7 @@ void parse_lag(void) port_lag_members_set(group, members); return; err: - print_string("Error: lag <1-4> [port]...\n"); + print_string("Error: lag (show | <1-4> (d | ...))\n"); } diff --git a/dhcp.c b/dhcp.c index d821f805..6cfa373a 100644 --- a/dhcp.c +++ b/dhcp.c @@ -94,7 +94,7 @@ void dhcp_prepare_request(void) DHCP_P->hw_len = 6; DHCP_P->hops = 0; - DHCP_P->tid = HTONS(dhcp_state.transaction_id); + DHCP_P->tid = dhcp_state.transaction_id; DHCP_P->delay = HTONS(0); DHCP_P->flags = 0; // Clear fields client_ip to bootp_file @@ -300,7 +300,7 @@ void parse_opts(void) void parse_dhcp(void) { - if (!DHCP_P->tid == HTONS(dhcp_state.transaction_id)) + if (DHCP_P->tid != dhcp_state.transaction_id) return; if (DHCP_P->cookie[0] != 0x63 || DHCP_P->cookie[1] != 0x82 || DHCP_P->cookie[2] != 0x53 || DHCP_P->cookie[3] != 0x63) return; diff --git a/doc/link_aggregation.md b/doc/link_aggregation.md index 6bde787e..b725e419 100644 --- a/doc/link_aggregation.md +++ b/doc/link_aggregation.md @@ -48,9 +48,11 @@ 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 [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 [p2]... + Create or set a LAG. LAG-ID is 1 to 4. Ports are physical ports. + +> lag d + Delete the LAG. > lag show Shows information on all 4 lags diff --git a/html/main.js b/html/main.js index 37bf7b26..a549a7a7 100644 --- a/html/main.js +++ b/html/main.js @@ -1359,12 +1359,11 @@ function createPortTable() { for (let i = 1; i <= numPorts; i++) { if (pIsSFP[i-1]) continue; - console.log("Table row: " + i + "pState: " + pState[i-2]); const tr = tbl.insertRow(); let td = tr.insertCell(); td.appendChild(document.createTextNode(t('common_port') + i)); let portName = portNames[physToLogPort[i-1]] || ''; td = tr.insertCell(); td.appendChild(document.createTextNode(portName)); - td = tr.insertCell(); td.innerHTML = linkText(pState[i] + 1); + td = tr.insertCell(); td.innerHTML = linkText(pState[i-1] + 1); tr.insertCell(); // filled by devRender() td = tr.insertCell(); td.innerHTML = sSelect.replaceAll("speed_sel", "speed_sel_" + i); td = tr.insertCell(); td.innerHTML = dSwitch.replaceAll("disable_port", "disable_port_" + i) @@ -1787,7 +1786,11 @@ var l2SortCol = 'port'; var l2SortDir = 1; function l2Key(e, col) { - if (col === 'port') return e.port === 'CPU' ? Number.MAX_SAFE_INTEGER : Number(e.port); + if (col === 'port') { + if (e.port === 'CPU') return Number.MAX_SAFE_INTEGER; + if (e.lag) return 100 + e.lag; + return Number(e.port); + } if (col === 'vlan') return Number(e.vlan); return String(e[col]).toLowerCase(); } @@ -1833,7 +1836,11 @@ function fillL2(s) return; s.sort(l2CMP); s = uniq(s); - l2All = s; + l2All = s.map(function(e) { + if (e.lag) + e.port = 'LAG' + e.lag; + return e; + }); renderL2(); } @@ -2200,7 +2207,7 @@ function fetchLag() { sendXHTTP(xhttp); } async function lagSub(l) { - var cmd = "lag " + l; + var cmd = "lag " + (l + 1); for (let i = 1; i <= numPorts; i++) { if (document.getElementById("p_mLAG"+l+"_"+i).checked) cmd = cmd + ` ${i}`; diff --git a/httpd/httpd.c b/httpd/httpd.c index 3fb48308..b5f437a5 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -1012,7 +1012,7 @@ void httpd_appcall(void) if (!authenticated && !(f_data[entry].start == FDATA_START_login_html || f_data[entry].start == FDATA_START_port_svg || f_data[entry].start == FDATA_START_sfp_svg - || f_data[entry].start == FDATA_START_i18n_js + || f_data[entry].start == FDATA_START_main_js || f_data[entry].start == FDATA_START_style_css)) { send_to_login(); goto do_send; diff --git a/httpd/page_impl.c b/httpd/page_impl.c index 313a652e..b99f0b9b 100644 --- a/httpd/page_impl.c +++ b/httpd/page_impl.c @@ -359,6 +359,7 @@ void send_l2(uint16_t idx) while (1) { entries_left--; uint8_t port = 0; + uint8_t lag; reg_read_m(RTL837x_TBL_DATA_0); REG_WRITE(RTL837x_TBL_DATA_0, sfr_data[0], sfr_data[1] & 0xfc, sfr_data[2] | (TBL_LUTREAD_NEXT_L2UC << 6), sfr_data[3]); @@ -402,6 +403,9 @@ void send_l2(uint16_t idx) port |= (sfr_data[3] & 0x3) << 2; itoa_html(port); + slen += strtox(outbuf + slen, ",\"lag\":"); + lag = port_lag_of(port); + itoa_html(lag == PORT_LAG_NONE ? 0 : lag + 1); } // Index diff --git a/rtl837x_port.c b/rtl837x_port.c index 1c966728..a640fb5d 100644 --- a/rtl837x_port.c +++ b/rtl837x_port.c @@ -30,6 +30,14 @@ __xdata uint32_t l2_head; __xdata struct vlan_settings vlan_settings; +// Wait for the TABLE ready +static void wait_table_ready(void) +{ + do { + reg_read(RTL837X_TBL_CTRL); + } while (SFR_DATA_0 & TBL_EXECUTE); +} + void port_mirror_set(uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t tx_pmask) __banked { print_string("\nport_mirror_set called \n"); @@ -183,9 +191,9 @@ int8_t vlan_get(uint16_t vlan) __banked return -1; REG_WRITE(RTL837X_TBL_CTRL, vlan >> 8, vlan, TBL_VLAN, TBL_EXECUTE); - do { - reg_read_m(RTL837X_TBL_CTRL); - } while (sfr_data[3] & TBL_EXECUTE); + + wait_table_ready(); + reg_read_m(RTL837x_L2_DATA_OUT_A); return 0; @@ -239,9 +247,9 @@ void vlan_create(void) __banked // Initialize VLAN table with VLAN 1 REG_WRITE(RTL837x_TBL_DATA_IN_A, 0x02, (a >> 6) & 0x0f, (a << 2) | (vlan_settings.members >> 8), vlan_settings.members); REG_WRITE(RTL837X_TBL_CTRL, vlan_settings.vlan >> 8, vlan_settings.vlan, TBL_VLAN, TBL_WRITE | TBL_EXECUTE); - do { - reg_read_m(RTL837X_TBL_CTRL); - } while (sfr_data[3] & TBL_EXECUTE); + + wait_table_ready(); + print_string("vlan_create done \n"); } @@ -265,9 +273,8 @@ void vlan_setup(void) __banked REG_SET(RTL837x_TBL_DATA_IN_A, machine_detected.isRTL8373? 0x0007ffff : 0x0007e3f8); REG_SET(RTL837X_TBL_CTRL, 0x00010303); - do { - reg_read_m(RTL837X_TBL_CTRL); - } while (sfr_data[3] & TBL_EXECUTE); + + wait_table_ready(); // Set PVID 1 for every port. TODO: Skip unused ports! for (uint8_t i = machine.min_port; i <= machine.max_port + 1; i++) { // Do this also for the CPU port (+1) @@ -310,9 +317,8 @@ void vlan_setup(void) __banked REG_SET(RTL837x_TBL_DATA_IN_A, machine_detected.isRTL8373? 0x0207ffff : 0x0207e3f8); // 02: Entry valid, 7...: membership REG_SET(RTL837X_TBL_CTRL, 0x00010303); // Write VLAN 1 - do { - reg_read_m(RTL837X_TBL_CTRL); - } while (sfr_data[3] & TBL_EXECUTE); + + wait_table_ready(); #ifdef DEBUG print_string("\nvlan_setup, REG 0x6738: "); print_reg(0x6738); @@ -372,22 +378,21 @@ uint8_t port_l2_forget(void) __banked void port_l2_learned(void) __banked { // Whait for any table action to be finished - do { - reg_read_m(RTL837X_TBL_CTRL); - } while (sfr_data[3] & 0x01); + wait_table_ready(); + print_string("\n\tMAC\t\tVLAN\ttype\tport\n"); __xdata uint16_t entry = 0x0000; __xdata uint16_t first_entry = 0xffff; // Table does not have that many entries while (1) { uint8_t port = 0; + uint8_t lag; reg_read_m(RTL837x_TBL_DATA_0); REG_WRITE(RTL837x_TBL_DATA_0, sfr_data[0], sfr_data[1],sfr_data[2] | 0xc0, sfr_data[3]); REG_WRITE(RTL837X_TBL_CTRL, (entry >> 8) & 0xf, entry, TBL_L2_UNICAST, TBL_EXECUTE); - do { - reg_read_m(RTL837X_TBL_CTRL); - } while (sfr_data[3] & TBL_EXECUTE); + + wait_table_ready(); reg_read_m(RTL837x_TBL_DATA_0); entry = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3]; @@ -416,13 +421,19 @@ void port_l2_learned(void) __banked // type reg_read_m(RTL837x_L2_DATA_OUT_C); - if (sfr_data[2] & 0x1) + if (sfr_data[1] & 0x1) print_string("\tstatic\t"); else print_string("\tlearned\t"); port |= (sfr_data[3] & 0x3) << 2; - print_phys_port(port); + lag = port_lag_of(port); + if (lag == PORT_LAG_NONE) { + print_phys_port(port); + } else { + print_string("LAG"); + itoa(lag + 1); + } } entry++; @@ -438,17 +449,14 @@ void port_l2_learned(void) __banked void port_l2mc_set(uint8_t mac_last, __xdata uint16_t vid, __xdata uint16_t pmask) __banked { - do { - reg_read(RTL837X_TBL_CTRL); - } while (SFR_DATA_0 & TBL_EXECUTE); + wait_table_ready(); REG_WRITE(RTL837x_TBL_DATA_IN_A, 0xc2, 0x00, 0x00, mac_last); REG_WRITE(RTL837x_TBL_DATA_IN_B, 0x20 | (vid >> 8) | ((pmask & 0x3) << 6), vid, 0x01, 0x80); REG_WRITE(RTL837x_TBL_DATA_IN_C, 0, 0, 0, pmask >> 2); REG_WRITE(RTL837X_TBL_CTRL, 0, 0, TBL_L2_UNICAST, TBL_WRITE | TBL_EXECUTE); - do { - reg_read(RTL837X_TBL_CTRL); - } while (SFR_DATA_0 & TBL_EXECUTE); + + wait_table_ready(); } @@ -930,13 +938,6 @@ static void l2_mgmt_tbl_prepare(void) reg_write_m(RTL837x_TBL_DATA_0); } -static void wait_table_ready(void) -{ - do { - reg_read(RTL837X_TBL_CTRL); - } while (SFR_DATA_0 & TBL_EXECUTE); -} - /** Pin the management MAC to the CPU port; remove_entry deletes it */ void port_l2_static_mgmt(__xdata uint8_t *mac, __xdata uint16_t vlan, __xdata bool remove_entry) __banked { @@ -963,5 +964,6 @@ void port_l2_static_mgmt(__xdata uint8_t *mac, __xdata uint16_t vlan, __xdata bo // method-0 write: the hardware hashes the key and places the entry REG_WRITE(RTL837X_TBL_CTRL, 0x00, 0x00, TBL_L2_UNICAST, TBL_WRITE | TBL_EXECUTE); } + wait_table_ready(); } diff --git a/rtlplayground.c b/rtlplayground.c index b3710c76..700df0b8 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -89,6 +89,7 @@ volatile __xdata uint32_t ticks; volatile __xdata uint8_t sec_counter; volatile __xdata uint16_t sleep_ticks; __xdata uint8_t stp_clock; +__xdata uint8_t arp_age_secs; extern __xdata struct dhcp_state dhcp_state; #define STP_TICK_DIVIDER 3 @@ -493,7 +494,6 @@ void print_cmd_prompt(void) void isr_ext0(void) __interrupt(0) { EX0 = 0; // Disable interrupt for the moment - write_char('X'); IT0 = 1; // Trigger on falling edge of external interrupt EX0 = 1; // Re-enable interrupt } @@ -501,14 +501,11 @@ void isr_ext0(void) __interrupt(0) /* * External IRQ 1 Service Routine, triggered by the NIC recieving a packet - * Note that all registers are being put on the STACK because of calling - * a subroutine (write_char), we shold do better... */ void isr_ext1(void) __interrupt(2) { // This flag should only be reset after all packets have been read EX1 = 0; - write_char('Y'); EX1 = 1; } @@ -519,7 +516,6 @@ void isr_ext1(void) __interrupt(2) void isr_ext2(void) __interrupt(8) { EXIF &= 0xef; // Clear IRQ flag (bit 7) in EXIF - write_char('Z'); PCON |= 1; // Enter Idle mode until interrupt occurs } @@ -530,7 +526,6 @@ void isr_ext2(void) __interrupt(8) void isr_ext3(void) __interrupt(9) { EXIF &= 0xdf; // Clear IRQ flag (bit 6) in EXIF - write_char('W'); } // Timer2: handles system tick. @@ -1565,6 +1560,11 @@ void idle(void) // Check for button presses once a second handle_button(); + // Age the ARP cache: uip_arp_timer() expects a 10 s cadence + if (++arp_age_secs >= 10) { + arp_age_secs = 0; + uip_arp_timer(); + } #ifdef DEBUG print_sfr_data();