diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 77b37312..31a94891 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,7 +20,7 @@ jobs: apt install make gcc sdcc xxd python-is-python3 libjson-c-dev zlib1g-dev -y - name: Run the host-side unit tests run: make -C test - - name: Check if machine.c can be compiled for all machines + - name: Check that every machine definition can be compiled run: make machine_check - name: Make project (4x2/RTL8372) run: make CI=1 MACHINE="KP_9000_6XHML_X2" diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c490505..b66c3013 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ ## Added +- Devices + - Support the hongyavision HYWS-SGT0204S (PCB marking `2G5F4_10G2_V1.01`), an + RTL8372 based 4x2.5G + 2xSFP+ unmanaged switch with a 512 KB Bright Moon + `T25S40` flash. It is a sibling of the KP-9000-6XH-X2 (2M-PCB43-V1.1) with + the two SFP+ cages wired the other way round (physical 5 is on SDS1, + physical 6 on SDS0), no reset button fitted, wrong silkscreen labels on the + serial header, `LED_GLB_IO_EN` bit 6 has to be set for the port LEDs to + work, and the fitted T25S40 cannot be read in DIO mode on this board, so the + target selects single-IO flash reads (`flash_sio`). New machine target + `MACHINE_2G5F4_10G2_V1_01`, see `doc/devices/2G5F4_10G2_V1.01.md`. + - Web UI - Compress the embedded assets (minify + gzip) and switch to a single-page layout. #315 - Replace the multi-page UI with a themed single-page app: light, dark and Selenized themes following the browser by default, diff --git a/Makefile b/Makefile index 599d2b95..c95f12af 100644 --- a/Makefile +++ b/Makefile @@ -7,17 +7,20 @@ HTML_LOCATION = 262144 ifeq ($(origin CC),default) CC = sdcc endif -CC_FLAGS = -mmcs51 -I. -Ihttpd -Iuip +CC_FLAGS = -mmcs51 -I. -Imachine -Ihttpd -Iuip ASM ?= sdas8051 AFLAGS= -plosgff SUBDIRS := tools SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS)) -ifeq ($(MACHINE),) - MACHINE:= $(shell grep "^\s*#define MACHINE_" machine.h | sed "s/^\s*#define MACHINE_//") -else +# $MACHINE selects machine/$(MACHINE).c as the board definition and is passed +# on as -DMACHINE_$(MACHINE), which the rest of the firmware tests with +# #if defined(MACHINE_...), and as -DMACHINE_NAME, which machine.h uses to +# include machine/$(MACHINE).h. Both take the same value, so they cannot drift. +ifneq ($(MACHINE),) CC_FLAGS += -DMACHINE_$(MACHINE) + CC_FLAGS += -DMACHINE_NAME=$(MACHINE) endif # Health instrumentation and the "health" console command: HEALTH=1 gmake ... ifneq ($(HEALTH),) @@ -28,6 +31,9 @@ ifeq ($(CI),1) CC_FLAGS += --Werror endif +# The board definition being built: one file per MACHINE_* symbol in machine.h. +MACHINE_SRC = machine/$(MACHINE).c + BUILDDIR = output/$(MACHINE) VERSION_HEADER := version.h @@ -51,16 +57,30 @@ BUILD_DATE := $(shell date -u -d @$(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S" 2>/d || date -u -r $(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S") endif -all: create_build_dir $(VERSION_HEADER) $(SUBDIRS) $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin +# $(MACHINE_SRC) is listed here so an unknown $MACHINE fails before anything else +# is built, including the tools/ subdirectory. +all: create_build_dir $(VERSION_HEADER) $(MACHINE_SRC) $(SUBDIRS) $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin create_build_dir: mkdir -p "$(BUILDDIR)" mkdir -p "$(BUILDDIR)/uip" mkdir -p "$(BUILDDIR)/httpd" + mkdir -p "$(BUILDDIR)/machine" -# Keep machine.c in first position to fail immediately on invalid $MACHINE value +# Every machine is a pair machine/.c + machine/.h. Selecting +# them by name means no #if/#elif chain, so an unknown or empty $MACHINE is +# caught here instead of by a #error further down the build. +$(MACHINE_SRC): + @echo "ERROR: MACHINE='$(MACHINE)' has no definition (expected $(MACHINE_SRC))." >&2 + @echo " Every machine is one file pair under machine/, named after the" >&2 + @echo " MACHINE_* symbol it defines; see machine/*.c for the full list." >&2 + @echo " Example: make MACHINE=KP_9000_6XHML_X2" >&2 + @false + +# Keep the per-machine definition in first position to fail immediately on an +# invalid $MACHINE value SRCS = \ - machine.c \ + $(MACHINE_SRC) \ machine_init.c \ cmd_editor.c \ cmd_parser.c \ @@ -79,9 +99,11 @@ SRCS = \ # RTL837x SRCS += \ rtl837x_bandwidth.c \ + rtl837x_cabletest.c \ rtl837x_flash.c \ rtl837x_igmp.c \ rtl837x_init.c \ + rtl837x_nic.c \ rtl837x_leds.c \ rtl837x_leds_dump.c \ rtl837x_phy.c \ @@ -89,7 +111,9 @@ SRCS += \ rtl837x_port.c \ rtl837x_stp.c \ rtl837x_lldp.c \ - rtl837x_storm.c + rtl837x_storm.c \ + rtl837x_lacp.c \ + rtl837x_trap.c SRCS += \ httpd/httpd.c \ httpd/page_impl.c @@ -178,15 +202,22 @@ $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.i .PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) create_build_dir +# Every machine/ definition is compiled, so a machine added to machine/ is +# covered without registering it anywhere. The machine-specific defines are +# filtered out of $(CC_FLAGS) and supplied per iteration instead, so this also +# works as "make machine_check MACHINE=...". +MACHINE_DEFS := $(sort $(patsubst machine/%.c,%,$(wildcard machine/*.c))) +MACHINE_LESS_CC_FLAGS = $(filter-out -DMACHINE_%,$(CC_FLAGS)) + .PHONY: machine_check: @mkdir -p $(BUILDDIR)/tmp @set -eo pipefail; \ - for MACHINE in `grep -E '^[[:space:]]*(//[[:space:]]*)?#define MACHINE_' machine.h | sed -E 's%^[[:space:]]*(//[[:space:]]*)?#define MACHINE_%%' | awk '{print $$1}' | sort -u`; \ + for MACHINE in $(MACHINE_DEFS); \ do \ echo "Checking $${MACHINE}"; \ - $(CC) $(CC_FLAGS) -DMACHINE_$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine.c; \ - $(CC) $(CC_FLAGS) -DMACHINE_$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine_init.c; \ + $(CC) $(MACHINE_LESS_CC_FLAGS) -DMACHINE_$${MACHINE} -DMACHINE_NAME=$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine/$${MACHINE}.c; \ + $(CC) $(MACHINE_LESS_CC_FLAGS) -DMACHINE_$${MACHINE} -DMACHINE_NAME=$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine_init.c; \ done @rm -rf $(BUILDDIR)/tmp diff --git a/README.md b/README.md index 6eaf74e8..22d9df5d 100644 --- a/README.md +++ b/README.md @@ -103,24 +103,29 @@ docker run --rm -p 8080:8080 -v $(pwd):/workspace rtlplayground-dev \ tools/output/httpd_sim /workspace/html ``` -Edit `machine.h` or `config.txt` on your host, then re-run `make` — the +Edit `config.txt` on your host, then re-run `make` — the source directory is mounted into the container, so changes take effect -immediately. To build for a different machine, pass `MACHINE=...`. +immediately. To build for a different machine, pass `MACHINE=`, which +selects `machine/.c` (see [Adding a new device](doc/adding-a-device.md)). ## (1) Compiling for direct chip flashing AND upgrading an existing RTLPlayground running device -Edit machine.h with an editor like vi or nano. Select the correct machine the firmware should build for. +Pass the machine that matches your device, for example: +``` +make MACHINE=DEFAULT_8C_1SFP +``` +The name selects the board definition `machine/.c`; `make` without a +`MACHINE` value stops with an error listing what is expected. If your board is +not in the list yet, see [Adding a new device](doc/adding-a-device.md). > [!TIP] > You can write configuration parameters in config.txt (see below) in order your switch to get > straight at the first boot, a correct IP configuration. -Now, building the firmware image should work: -``` -make -``` +Now, building the firmware image should work. + Note, that the image generated ends in .bin, not .img, in order to make IMSProg happy. image location is stored in `RTLPlayground/output/rtlplayground_version_machine.bin` @@ -186,7 +191,7 @@ Go to "Firmware update" tab, select the correct file. > [!IMPORTANT] > If your device already runs RTLPlayground, you must upload the binary file /RTLPlayground/output/rtlplayground_Version_Machine.bin -> If your device is OEM, you must upload the binary file /RTLPlayground/installer/outputrtlplayground_oem_upgrade.bin +> If your device is OEM, you must upload the binary file /RTLPlayground/installer/output/rtlplayground_oem_upgrade.bin > [!CAUTION] > Check one more time that your device matches the machine type before flashing. @@ -353,12 +358,14 @@ Enjoy playing! ## (11) Other documents The following documents give further documentation on specific features of the RTL837x SoCs: +- [Adding a new device](doc/adding-a-device.md) - [RTL8372/3 Feature support](doc/hardware.md) - [CPU Port](doc/CpuPort.md) - [L2 learning](doc/l2.md) - [IGMP (IP-MC streaming)](doc/igmp.md) - [SFP+ ports](doc/sfp.md) -- [Trunking aka. port aggregation](doc/trunking.md) +- [Trunking aka. port aggregation](doc/link_aggregation.md) +- [LACP (802.3ad link aggregation)](doc/lacp.md) - [VLAN](doc/vlan.md) - [Storm control](doc/storm_control.md) - [Modifications and Flash replacement](doc/mods.md) diff --git a/boot.c b/boot.c index 9e271660..adcb192b 100644 --- a/boot.c +++ b/boot.c @@ -257,7 +257,7 @@ void nic_setup(void) __banked // This sets the size of the RX buffer, the filling level is in 0x7874 // R7848-000004ff - REG_SET(RTL837X_REG_NIC_RXBUFF_RX, 0x4ff); + REG_SET(RTL837X_REG_NIC_RXBUFF_RX, RTL837X_NIC_RX_LAST_SLOT); // R7844-000007fe REG_SET(RTL837X_REG_NIC_BUFFSIZE_TX, 0x7fe); @@ -296,6 +296,7 @@ void nic_setup(void) __banked // Sequence number of TX packets tx_seq = 0; + REG_SET(RTL837X_NIC_INT_MSK, NIC_INT_RXIE); } diff --git a/cmd_parser.c b/cmd_parser.c index e7daa9e8..afc7831a 100644 --- a/cmd_parser.c +++ b/cmd_parser.c @@ -14,10 +14,13 @@ #include "rtl837x_regs.h" #include "rtl837x_sfr.h" #include "rtl837x_stp.h" +#include "rtl837x_lacp.h" #include "rtl837x_igmp.h" #include "rtl837x_bandwidth.h" #include "rtl837x_lldp.h" #include "rtl837x_storm.h" +#include "rtl837x_trap.h" +#include "rtl837x_cabletest.h" #include "sfp.h" #include "dhcp.h" #include "syslog.h" @@ -164,10 +167,15 @@ uint8_t atoi_hex(uint8_t idx) break; } + if (h_idx == 8) { + h_idx = 0; + break; + } + // swap hex nibbles val = (val >> 4) | (val << 4); - if (c - '0' < 10) { + if ((uint8_t)(c - '0') < 10) { val |= c - '0'; } else { c |= 0x20; @@ -533,11 +541,21 @@ void parse_lag(void) goto err; if (cmd_compare(2, "d")) { + lacp_lag_set(group, 0); port_lag_members_set(group, 0); return; } uint8_t w = 2; + __xdata uint8_t lacp_mode = 0; + if (cmd_words_len > 2 && cmd_compare(2, "lacp")) { + lacp_mode = 1; + w = 3; + if (cmd_words_len > 3 && cmd_compare(3, "off")) { + lacp_lag_set(group, 0); + return; + } + } while (w < cmd_words_len) { // Parse port. if (cmd_parse_port_separator(cmd_words_b[w++]) == 0) @@ -545,10 +563,15 @@ void parse_lag(void) members |= ((uint16_t)1) << atoi_results_u8; } - port_lag_members_set(group, members); + if (lacp_mode) { + lacp_lag_set(group, members); + } else { + lacp_lag_set(group, 0); + port_lag_members_set(group, members); + } return; err: - cmd_error("lag (show | <1-4> (d | ...))\n"); + cmd_error("lag (show | <1-4> (d | [lacp] ...))\n"); } @@ -722,7 +745,7 @@ void parse_isolate(void) if (cmd_compare(2, "off")) { for (uint8_t i = machine.min_port; i <= machine.max_port; i++) members |= ((uint16_t)1) << i; - members |= 0x200; // CPU-port + members |= PMASK_CPU; // CPU-port port_isolate(port_configured, members); return; } @@ -846,9 +869,14 @@ void parse_mirror(void) if (cmd_words_len < 2) goto err; + // The first argument is the mirroring (monitor) port + uint8_t ret = cmd_parse_port(cmd_words_b[1]); + if (ret == 0) + goto err; + mirroring_port = atoi_results_u8; + uint8_t w = 2; uint8_t port; - uint8_t ret; while (w < cmd_words_len) { uint8_t idx = cmd_words_b[w++]; ret = cmd_parse_port(idx); @@ -858,10 +886,6 @@ void parse_mirror(void) idx += ret; port = atoi_results_u8; - // Use the first port argument as mirroring_port - if (w == 2) - mirroring_port = port; - ret = cmd_buffer[idx]; uint16_t pmask = ((uint16_t)1) << port; if (ret != 't') @@ -885,6 +909,7 @@ void parse_port(void) "\nport [show|on|off]" \ "\nport [10m|100m|1g|2g5|duplex] [half|full]" \ "\nport lldp [block|permit]" \ + "\nport cabletest [show]" \ "\nport name [custom port name]\n"); return; } @@ -927,6 +952,11 @@ void parse_port(void) } } else if (machine.is_sfp[phy_settings.port]) { print_string(" is SFP no PHY information available.\n"); + } else if (cmd_compare(2, "cabletest")) { + if (cmd_words_len > 3 && cmd_compare(3, "show")) + cabletest_show(); + else + cabletest_run(); } else if (cmd_compare(2, "10m")) { print_string(" 10M\n"); phy_settings.speed = PHY_SPEED_10M; @@ -1972,6 +2002,13 @@ void cmd_parser(void) __banked } else if (cmd_compare(0, "health")) { health_show(); #endif + } else if (cmd_compare(0, "lacp")) { + if (cmd_compare(1, "show")) + lacp_show(); + else if (cmd_compare(1, "off")) + lacp_off(); + else + cmd_error("lacp (show | off); a group starts LACP with: lag <1-4> lacp ...\n"); } else if (cmd_compare(0, "pvid")) { if (cmd_words_len == 3 && cmd_parse_port_separator(cmd_words_b[1]) != 0 && atoi_short(cmd_words_b[2]) && atoi_results_short && atoi_results_short <= 4094) @@ -2043,9 +2080,11 @@ void cmd_parser(void) __banked if (cmd_compare(1, "on")) { print_string("LLDP enabled\n"); lldp_enabled = 1; + trap_rma_set(RTL837X_RMA0E_CONF, RTL837X_RMA_ACT_TRAP); } else { print_string("LLDP disabled\n"); lldp_enabled = 0; + trap_rma_set(RTL837X_RMA0E_CONF, RTL837X_RMA_ACT_FORWARD); } } else { @@ -2116,7 +2155,7 @@ void execute_config(void) __banked skipping = 1; } c = flash_buf[cfg_idx++]; - if (c == 0 || c == '\n') { + if (c == 0 || c == '\n' || c == '\r') { if (skipping) { skipping = 0; } else { diff --git a/dhcp.c b/dhcp.c index 079cd521..279ccc24 100644 --- a/dhcp.c +++ b/dhcp.c @@ -51,7 +51,7 @@ __xdata uip_ipaddr_t server; #define DHCP_END 255 #pragma codeseg BANK3 -#pragma constseg BANK2 +#pragma constseg BANK3 struct dhcp_pkt { uint8_t type; diff --git a/doc/CpuPort.md b/doc/CpuPort.md index c10d0a15..652b1cbb 100644 --- a/doc/CpuPort.md +++ b/doc/CpuPort.md @@ -34,6 +34,21 @@ Next, transfer the actual packet over by repeating the SFR function with a pointer to the frame on the ASIC directly after the frame header and a length as given by the length in the frame header + 7, again divided by 8. +The RX ring's inclusive last slot is configured as `0x4ff`, giving a byte +range of `0x0000` through `0x27ff`. If the descriptor occupies the last slot +at `0x27f8`, its payload starts at `0x0000`, not `0x2800`. The RX copy code +normalizes that starting address before DMA. It relies on the hardware to +wrap transfers that start inside the ring and cross its end, as observed +on SWTGW218AS. Programming an initial address of `0x2800` does not wrap +and can instead read zeros or stale TX data outside the RX ring. + +Frame lengths are checked against `UIP_CONF_BUFFER_SIZE` before copying. +DMA works in whole eight-byte units. `UIP_CONF_BUFFER_ALLOC_SIZE` rounds +the backing storage up to the next complete word: 1,560 bytes for the +1,556-byte logical frame limit. This padding allows a maximum-size frame +to be transferred directly without a separate tail copy. The logical +frame limit and advertised MSS are unchanged. + The received frame will have an RTL proprietary Ethernet frame type of 0x8899 (RRPC) where normally the frame type 0x0800 for IPv4 would be located. Further 6 bytes follow describing the frame, before the normal IPv4 data diff --git a/doc/adding-a-device.md b/doc/adding-a-device.md new file mode 100644 index 00000000..8d45d198 --- /dev/null +++ b/doc/adding-a-device.md @@ -0,0 +1,196 @@ +# Adding a new device + +A device is supported by adding one board definition `.h` and board configuration `.c` file +under `machine/`. +the build selects the definition by name, and CI compiles every file it finds. + +To compile for your added device, do: +``` +make MACHINE= +``` + +## What a new device consists of + +| File | Purpose | +|------|---------| +| `machine/.c` | the `struct machine machine` board definition | +| `machine/.h` | `MACHINE_MODEL`, the model string shown in the UI and the CLI | +| `doc/devices/.md` + `doc/supported_devices.md` | (only if the board is verified and you want to support it publicly) user-facing documentation | + +`` is the machine symbol without its `MACHINE_` prefix, so `MACHINE` is +passed exactly as spelled on the command line: `make MACHINE=MY_BOARD_1_0` +needs `machine/MY_BOARD_1_0.c` and `machine/MY_BOARD_1_0.h`. + +## Step 1: the model header + +`machine/.h` only carries the product string. Use the existing files as +the template: + +```c +#ifndef _MACHINE_MY_BOARD_1_0_H_ +#define _MACHINE_MY_BOARD_1_0_H_ + +#define MACHINE_MODEL "Brand Model V1.0" + +#endif +``` + +The device product string is what the CLI or the Web-Interface will print to identify the device; `machine.h` includes it by name. + +> [!NOTE] +> `machine_name` is a `char[30]` and `MACHINE_MODEL` is copied into it at +> compile time. A longer model string still builds, but SDCC emits +> `warning 147: excess elements in array of chars initializer` and the name is +> truncated in the UI. Keep it to 29 characters or less. + +## Step 2: the board definition + +`machine/.c` starts with the shared prelude and then defines the single +`machine` object. Copy the closest existing board and adjust it — do not start +from a blank file, the field meanings are easier to see in a real example. +The best choice is usually a device that has the same number and type of Ethernet +ports and the same number of SFP+ cages. + +```c +#include "machine_defs.h" + +__code const struct machine machine = { + .machine_name = MACHINE_MODEL, + .isRTL8373 = 1, + .min_port = 0, + .max_port = 8, + .n_sfp = 1, + .log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9}, + .phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8}, + .is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1}, + + .sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN, + .sfp_port[0].pin_los = GPIO37, + .sfp_port[0].pin_tx_disable = GPIO_NA, + .sfp_port[0].sds = 1, + .sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ), + .reset_pin = GPIO_NA, + + .high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 }, + .port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1 }, + .led_sets = { + { /* RJ45 ports */ + LEDS_2G5 | LEDS_LINK, + LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, + 0, + 0 + }, { /* SFP port, single green LED */ + LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, + 0, + 0, + 0 + } + }, +}; +``` + +### Fields + +| Field | Meaning | +|-------|---------| +| `machine_name` | always `MACHINE_MODEL` | +| `isRTL8373` | `1` for an RTL8373 SoC, `0` for RTL8372 | +| `min_port` / `max_port` | range of logical port numbers the device has; `min_port` is `0` for RTL8373 boards and `3` for RTL8372 boards (logical ports 1–2 are the SoC's internal ports on the 8372), `max_port` is usually 8. | +| `n_sfp` | number of SFP+ cages | +| `n_10g` | SerDes 10G capability used by the RTL837xN init: `0` none, `1` one, `2` two 10G-capable SerDes | +| `log_to_phys_port[9]` | logical port (0-based index) → physical front-panel port number | +| `phys_to_log_port[9]` | the inverse, physical port 1 is index 0, unused slots are 0 | +| `is_sfp[9]` | `0` for copper, `1` for left slot and `2` for right slot | +| `sfp_port[2]` | per-cage wiring, `sfp_port[0]` is the leftmost cage | +| `reset_pin` | GPIO of the reset button, `GPIO_NA` if unpopulated | +| `high_leds` | mux/enable for the LED pins 27–29 (`LED_27`, `LED_28_SYS`, `LED_29`) | +| `port_led_set[9]` | which LED set (0–3) each logical port uses | +| `led_sets[4][4]` | Each port can have up to 4 GPIO output pins assigned. 4 sets of LEDs with 4 LED-conditions per set; the conditions define which GPIO pins become active for a port given a port link-state. Which LEDs are then enabled depends on the wiring of the pins to up to 3 LEDs for that port, which can make a logical combination of the 4 LED output-pins. | +| `led_mux_custom` / `led_mux[28]` | `1` plus the 28 mux values when the stock LED muxing does not fit the board | +| `mac_flash_offset` | flash offset of the factory MAC address, omit or `0` if the board does not store one | + +Each `struct sfp_port` entry holds `pin_detect`, `pin_los`, `pin_tx_disable`, +`sds` (which SerDes drives the cage) and `i2c` (built with `I2CBUS(sda, scl)`, +or `GPIO_NA`-based values where a cage has no such pin). + +`I2CBUS(...)` only accepts the pin pairs listed in `machine_defs.h`. A wrong +pair is caught at compile time: SDCC reports +`error 176: sizeof applied to an incomplete type` pointing at the offending +`.i2c` line, because the macro deliberately turns an invalid bus number into an +array of size 0. + +### Reusing an existing definition + +If the new board is electrically identical to one that already exists — same +port mapping, same SFP wiring, same LEDs — do not copy the file. Make the new +`.c` a symlink and keep only a distinct `.h`, so the two boards cannot drift +apart: + +``` +ln -s KP_9000_6XHML_X2.c machine/MY_BOARD_1_0.c +``` + +The new board still needs `machine/MY_BOARD_1_0.h` (pick the version number on the PCB) with its own +`MACHINE_MODEL`, because `MACHINE_MODEL` is what distinguishes the products. +Existing examples: `machine/PCB_K0402WS_V3.c`, `machine/KP_9000_9XHML_X_V3_2.c` +and the six `KP_9000_*` revision variants. + +Two files that differ only in whitespace or comments are duplicates and should +be collapsed this way. + +## Step 3: build and verify + +``` +make MACHINE=MY_BOARD_1_0 +``` + +The generated flash image appears as `output/rtlplayground--MY_BOARD_1_0.bin`. An +unknown or empty `MACHINE` fails immediately with a message naming the expected +file, before anything is compiled. + +Then run the checks CI runs: + +``` +make machine_check # compiles machine/.c and machine_init.c for every machine +make -C test # host-side unit tests +``` + +`make machine_check` discovers the definitions with +`$(wildcard machine/*.c)`, so a new file is covered without registering it +anywhere. CI (`.github/workflows/build.yml`) runs it on every push and pull +request, alongside full builds for a 4+2 and an 8+1 board. + +A successful compile only proves the definition is syntactically valid. The +actual behaviour — port numbering, SFP detection, LEDs — has to be confirmed on +hardware, and the console commands (`port`, `stat`, `sfp`, `leds`) are the +tools for that. + +## Step 4: documentation + +Once the board has been tested on hardware: + +1. Add a row to the table in [Supported devices](supported_devices.md). +2. Add `doc/devices/.md` describing the board, the build target + (`make MACHINE=MY_BOARD_1_0`), what works and what is unverified, plus + photos and the PCB silkscreen marking. +3. If the board shares a PCB with other revisions, follow + `doc/devices/KP-9000-6XH-X2.md` and document which `MACHINE` to pick for + which silkscreen. + +### Identifying the CPU variant + +For RTL8373-based devices, use the read-only console command below to distinguish +the N and non-N CPU variants: + +```text +regget 4 +``` + +| Register 0x0004 value | CPU | +|---|---| +| `0x83730000` | RTL8373 (non-N) | +| `0x83737000` | RTL8373N | + +Record the identified CPU in the device documentation. These values identify +only the CPU variant; document PHY and flash-chip models separately when verified. + diff --git a/doc/devices/2G5F4_10G2_V1.01.md b/doc/devices/2G5F4_10G2_V1.01.md new file mode 100644 index 00000000..fc3803a2 --- /dev/null +++ b/doc/devices/2G5F4_10G2_V1.01.md @@ -0,0 +1,178 @@ +hongyavision HYWS-SGT0204S + +RTL8372-based 4×2.5G + 2×SFP+ unmanaged switch. + +Also marked on the PCB as `2G5F4_10G2_V1.01`. + +Stock firmware runs a factory test console on UART at 9600 baud 8N1 (banner +`RTL8371B start`, prompt `RTL8371B:`). There is no management CLI and no Web +interface. + +Using SPI clamp in-board is the only method for initial installation and update. +Erase the whole chip and verify the write (`flashrom -v`) before powering the +board, so an incomplete write is caught before the board is powered up. + +Stock flash chip is 512 KB (Bright Moon `T25S40`, 4 Mbit, SOP-8), which the +RTLPlayground image fills exactly. + +### Label specifications + +Case, top / front / nameplate: + + + + + +- **Manufacturer**: hongyavision (Shenzhen Hongyavision Electronic Technology + Co., Ltd.) +- **Model**: HYWS-SGT0204S — the nameplate is printed in Chinese and reads + "10/100/1000/2500M fibre switch" and "4x 2.5G copper port + 2x 10G SFP+ + optical port" +- **Ports**: + - 4 × RJ45: 10/100/1000/2500 Mbps + - 2 × SFP+: 1G / 2.5G / 10G +- **Power**: 12 V DC, 2 A +- **Serial number**: `S/N-YYYYMMDDNNNN`, e.g. `S/N-202312010028` + +The top of the case only carries generic printing ("2.5G+10G High Speed Fiber +Transceiver / 4-Port 2.5G Ethernet Switch+10G Fiber"), so the nameplate on the +bottom is what identifies the device. + +### What works + +- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps +- Both SFP+ ports supporting 1G, 2.5G and 10G modules +- Copper LEDs: white (2.5G) and blue (link/activity) +- SFP LEDs: one single LED per port (link/activity) +- SFP EEPROM and DDM readable on both cages, verified with a 10G module + (`Rate: 0x67`, module identity and DDM values via the `sfp` console command) +- Serial console at 115200 8N1 (RTLPlayground) / 9600 8N1 (stock) + +### Not verified + +- The reset button footprint is unpopulated and the case has no opening for it, + so it could not be tested. + +### PCB overview + +**Board markings** +- Top silkscreen: `2G5F4_10G2_V1.01` + +**Key components** +- Main switch: RTL8372 (RTL8371B family), reported as `RTL8372` (non-N) by + RTLPlayground. The chip sits under a heatsink and its package marking is not + readable. +- U1: SPI NOR flash, Bright Moon `T25S40`, 4 Mbit / 512 KB, SOP-8 +- A 3-hole reset button footprint is present but unpopulated, and the case has + no opening for it, so there is no usable reset button + +Top side: + + + +Bottom: + + + +The stock flash chip, Bright Moon `T25S40` (SOP-8, 4 Mbit / 512 KB): + + + +### Port layout + +| Front panel position | Logical port | Physical port | Type | +|----------------------|--------------|---------------|---------| +| SFP left | 8 | 5 | SFP+ | +| RJ45 1 | 4 | 1 | Copper | +| RJ45 2 | 5 | 2 | Copper | +| RJ45 3 | 6 | 3 | Copper | +| RJ45 4 | 7 | 4 | Copper | +| SFP right | 3 | 6 | SFP+ | + +Copper ports 1–4 match the KP-9000-6XH-X2 (2M-PCB43-V1.1) layout, which this +board is a sibling of. The two SFP+ cages are wired the other way round +compared to that board: physical port 5 is on SDS1 and physical port 6 is on +SDS0. + +### Serial console + +The board has three through-holes used as the serial console, next to the +heatsink in the middle of the board and visible in the top side photo above (the +silkscreen labels are printed rotated by 90°). **The silkscreen labels are +wrong**: they are shifted relative to the actual signals. + +| Silkscreen label | Actual signal | +|------------------|---------------| +| TX | GND | +| RX | TX | +| GND | RX | + +Wiring (following the measured signals, not the labels): + +| USB-TTL adapter | Board pad | +|-----------------|----------------------| +| GND | pad labelled `TX` | +| RX | pad labelled `RX` | +| TX | pad labelled `GND` | + +- **Settings**: 115200 baud / 8N1 / 3.3V TTL (RTLPlayground), 9600 baud for the + stock firmware +- The stock firmware only prints a few bytes and a factory test menu + (`?`, `rst`, `f`, `r`, `10`, `100`, `g1`, `sd`, `eye`, …); it is not an + interactive management console + +### LED configuration + +Case silkscreen, below the RJ45 ports: + +``` +White : 2.5G Blue : 1000M/2500M L/A +``` + +The front panel also carries a `PWR` LED and one LED per SFP cage (`SFP1`, +`SFP2`) on the right hand side. + +| Port | LED | Linked, idle | With traffic | +|------------|--------------|--------------|--------------| +| Copper | white | 2.5G only | same | +| Copper | blue | solid | blinks (L/A) | +| SFP | single LED | solid | blinks (L/A) | + +Measured LED-ID mapping (from the RTL837x LED set registers): + +| LED-ID | Function | +|--------|---------------------------------| +| LED-ID0| copper blue LED | +| LED-ID1| copper white LED | +| LED-ID2| SFP single LED | + +**Important**: `RTL837X_REG_LED_GLB_IO_EN` bit 6 must be set in +`machine_custom_init()`. Without it the RTL837x "solid" conditions (LINK/speed) +do not drive the LEDs at all and only `ACT` does, which makes the white LED +glow faintly at non-2.5G speeds. + +### SFP GPIO assignments + +| SFP | pin\_detect (ModAbs) | pin\_los | SerDes | I2C SDA | I2C SCL | +|-------------------|-------------------------------|------------------|--------|-------------------------|--------------------------| +| Left (logical 8, physical 5) | GPIO30\_ACL\_BIT3\_EN | GPIO37 | SDS1 | GPIO39\_I2C\_SDA4 | GPIO40\_I2C\_SCL3\_MDC1 | +| Right (logical 3, physical 6)| GPIO50\_I2C\_SCL2\_UART1\_TX | GPIO10\_LED10 | SDS0 | GPIO41\_I2C\_SDA3\_MDIO1 | GPIO40\_I2C\_SCL3\_MDC1 | + +`pin_tx_disable` is GPIO\_NA on both ports. Both I2C buses are confirmed +working: with the same 10G module inserted, the `sfp` console command reads its +vendor and model from the left cage (`Slot 1`) and from the right cage +(`Slot 2`), DDM values included. The insertion also shows which SerDes drives +each cage - the left cage reports `sds_config sds: 01` and the right cage +`sds: 00`, which matches the table above. + +### Machine target + +Build for this device with `make MACHINE=2G5F4_10G2_V1_01`, which selects the +`machine/2G5F4_10G2_V1_01.c` board definition. It is derived from +`machine/KP_9000_6XHML_X2.c` with the SFP cage order and the reset pin changed. +The fitted T25S40 cannot be read in DIO mode on this board: an image that leaves +DIO enabled does not come up at all, both at the default read clock divider of 4 +and at 8 (two boards tested), while the same image with single-IO boots and runs +normally. The board definition therefore sets `flash_sio`, which makes +`flash_init()` use `CMD_FREAD` at divider 8. Only the management plane is +slower, the ASIC keeps forwarding in hardware. diff --git a/doc/devices/2M-PCB23-V3_2.md b/doc/devices/2M-PCB23-V3_2.md index 9cfe3acc..f86f8db2 100644 --- a/doc/devices/2M-PCB23-V3_2.md +++ b/doc/devices/2M-PCB23-V3_2.md @@ -17,8 +17,8 @@ The original web interface reports this board as hardware version V3.2 The component placement matches [2M-PCB23-V3.1](2M-PCB23-V3_1.md): same positions for the flash (U8), the T7/T8/T9/T10 headers, the SFP cage and its LED, and the unpopulated U7/U9 footprints. Build with -`MACHINE=KP_9000_9XHML_X_V3_2`, which uses the V3.1 machine definition and -only differs in the reported name. +`make MACHINE=KP_9000_9XHML_X_V3_2`, whose board file is a symlink to the V3.1 +definition and only differs in the reported name. ## Tested diff --git a/doc/devices/2M-PCB43-V1.1.md b/doc/devices/2M-PCB43-V1.1.md index 97343f02..0a11f513 100644 --- a/doc/devices/2M-PCB43-V1.1.md +++ b/doc/devices/2M-PCB43-V1.1.md @@ -15,7 +15,7 @@ and sold by Mokerlink. The device is fully supported: - All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps - The SFP+ port supports 1G, 2.5G and 10G modules -- LEDs work with the same indiciations as the OEM firmware (use KP_9000_6XHML_X2_V1_1 in machine.h if building yourself or the corresponding pre-compiled binary) +- LEDs work with the same indiciations as the OEM firmware (build with `make MACHINE=KP_9000_6XHML_X2_V1_1` if building yourself, or use the corresponding pre-compiled binary) - untested due to missing Hardware: SFP+ ports equipped with 1G or 2.5G SFPs. ### Hardware overview diff --git a/doc/devices/Hasivo-S1100P-8GT-1SX-S.md b/doc/devices/Hasivo-S1100P-8GT-1SX-S.md new file mode 100644 index 00000000..9fc60186 --- /dev/null +++ b/doc/devices/Hasivo-S1100P-8GT-1SX-S.md @@ -0,0 +1,41 @@ +# Hasivo S1100P-8GT-1SX-S + +RTL8373N switch with 8 × 2.5G RJ45 ports and 1 × SFP port. GD25Q16 2 MiB flash. + +## Port mapping + +| Front port | ASIC MAC | Interface | +| --- | --- | --- | +| 1–8 | 0–7 | RJ45 | +| 9 | 8 | SFP (SDS1) | + +## Board signals + +| Function | GPIO | +| --- | --- | +| SFP detect | 38 | +| SFP LOS | 37 | +| SFP TX disable | Not connected (`GPIO_NA`) | +| SFP I2C SDA / SCL | 39 / 40 | +| Reset | 54 | + +PoE is managed by an RTL8238B and a separate STC8H8K64U controller, not directly by the RTL8373N. RTLPlayground does not control PoE on this board. + +## Build + +`make MACHINE=HASIVO_S1100P_8GT_1SX_S CI=1` + +## Photos + +Front panel: + +![Front panel](photos/Hasivo-S1100P-8GT-1SX-S/front.jpg) + +PCB top: + +![PCB top](photos/Hasivo-S1100P-8GT-1SX-S/pcb_top.jpg) + +PCB bottom: + +![PCB bottom](photos/Hasivo-S1100P-8GT-1SX-S/pcb_bottom.jpg) + diff --git a/doc/devices/ONT-S207CW-62TS-SE.md b/doc/devices/ONT-S207CW-62TS-SE.md index fd5558e2..660d1c30 100644 --- a/doc/devices/ONT-S207CW-62TS-SE.md +++ b/doc/devices/ONT-S207CW-62TS-SE.md @@ -90,6 +90,8 @@ Custom mapping for ONT-S207CW-62TS-SE: ## Flashing Instructions See the [README.md](../../README.md) for general flashing instructions. +For compilation, use command `make MACHINE=ONT_S207CW_62TS_SE` to specify the machine. +If you are using managed version of the switch, you can then also compile the installer and flash using GUI - run command `cd installer` and finally `make`. ## Stock Firmware Information diff --git a/doc/devices/PCB-K0402WS-V1.0.md b/doc/devices/PCB-K0402WS-V1.0.md new file mode 100644 index 00000000..e732a20f --- /dev/null +++ b/doc/devices/PCB-K0402WS-V1.0.md @@ -0,0 +1,72 @@ +# PCB-K0402WS-V1.0 + +This is the first revision of the PCB-K0402WS series of boards; it's very similar to 2.0 in terms of layout/wiring. + +The board does have footprints for a VLAN modeswitch at the front and a second flash chip on the bottom of the PCB, but these have been seen to ship unpopulated. + +### Brands + +* YuanLey YS25-0402 Note: there are [multiple revisions](PCB-K0402WS-V3.0.md) of the YS25-0402. This first revision lacks the "Vlan" switch cutout on the front of the enclosure. + +### Programming + +Use a SOIC-8 clamp to the flash chip (U1 on silkscreen) at the top of the board, leaving it otherwise unpowered. + +The board has been seen to ship with a single [BoyaMicro BY25Q16BSSIG](https://www.lcsc.com/datasheet/C382744.pdf) 16Mbit (2MiB) chip, though exact BOM may vary. + + + +### What works + +- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps +- Both SFP ports supporting 1G, 2.5G and 10G modules +- LEDs (Power LED is always on) + +### PCB overview + +#### Board markings +- Top silkscreen: PCB-K0402W-V1.0 / DIP-K0402WS-V1.0 + +#### Key components +- U1: SPI NOR flash, 2 MiB +- S1: unpopulated slide switch footprint (three through-holes used as serial console) + +Front panel + + + +PCB top + + + +PCB bottom + + + +Bottom and rear + + + +### Power supply + +Input power is delivered via a standard DC barrel jack (5.5x2.1mm) with an included 12V 1A adapter. + +There is an optional grounding screw next to the DC input. + +### Serial console + +The PCB has a slide switch footprint (unpopulated) at the front right that is connected to the UART. It is labeled as "S1" on the silkscreen. + +Facing the top front (port) side of the board, the pinout from left to right is: + +| Position | Signal | GPIO | +|----------|--------|-------------------| +| 1 | RX | GPIO32\_UART0\_RX | +| 2 | GND | N/A | +| 3 | TX | GPIO31\_UART0\_TX | + +Standard 0.1" / 2.54mm pin headers will not fit, so wires or clips may be used instead. + +The image below shows some oversized clips clumsily attached. + + diff --git a/doc/devices/PCB-K0402WS-V3.0.md b/doc/devices/PCB-K0402WS-V3.0.md index 0da0f0d5..6246a910 100644 --- a/doc/devices/PCB-K0402WS-V3.0.md +++ b/doc/devices/PCB-K0402WS-V3.0.md @@ -19,9 +19,14 @@ of the device just above the big label, might be covered by a QC sticker. -* Siscolink SL-G0402F +* SICSOLINK SL-G0402F + + + +* YuanLey YS25-0402 Note: there are [multiple revisions](PCB-K0402WS-V1.0.md) of the YS25-0402. This is the newer revision that has a "Vlan" switch on the front. + + - ### Programming Using SPI clamp in-board is the only method for initial installation. @@ -43,7 +48,7 @@ For the initial flash (at least with flashrom), the bin file produced by the bui ### PCB overview **Board markings** -- Top silkscreen: PCB-KO4022W-V3.0 / DIP-KO4022WS-V3.0 +- Top silkscreen: PCB-K0402W-V3.0 / DIP-K0402WS-V3.0 Top side diff --git a/doc/devices/SIRIVISION_S25G2206FP_V1_1.md b/doc/devices/SIRIVISION_S25G2206FP_V1_1.md new file mode 100644 index 00000000..529ac1fc --- /dev/null +++ b/doc/devices/SIRIVISION_S25G2206FP_V1_1.md @@ -0,0 +1,32 @@ +### SIRIVISION_S25G2206FP_V1_1 + +## Brands +|Brand|Type|Managed|PCB|Flash|Chip RTL| +|---|---|---|---|---|---| +| YuanLey | YS25-0402M | Yes | SIRIVISION_S25G2206FP_V1_1 | 2M | 8372 | + +### Label specifications + +- **Name**: +- **Ports**: + - 4 × RJ45: 10/100/1000/2500 Mbps + - 2 × SFP+: 1000 / 2500 / 10000 Mbps +- **Power**: 12V DC, 1A 5525 connector + +### What works +The device is fully supported: +- ALL 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps +- ALL SFP+ ports support 1G, 2.5G and 10G modules +- LEDs work with the same indiciations as the OEM firmware +### PCB overview + +**Board markings** +- Top silkscreen: SIRIVISION S25G2206FP V1.1 + +Top side + + + +## Power supply + +Input power is delivered via barell plug, `12V 1A` adapter was provided. diff --git a/doc/devices/SWTG018AS_A_V2_0.md b/doc/devices/SWTG018AS_A_V2_0.md index a6f8a895..28447b85 100644 --- a/doc/devices/SWTG018AS_A_V2_0.md +++ b/doc/devices/SWTG018AS_A_V2_0.md @@ -4,7 +4,8 @@ |---------|------------------|-------|------------------|-----------------|---------------| | Ampcom | SWTG018AS-A V2.0 | No | SWTG018AS-A V2.0 | 2MB | 8273N + 8224N | | Horaco | HC-SWTGW218AS-A | Yes | SWTG018AS-A V2.0 | 2MB(25Q16JVSIQ) | 8273N + 8224N | -| GoodTop | GT-ST018M | Yes | SWTG018AS-A V2.0 | ? | 8273N + 8224N | +| GoodTop | GT-ST018M | Yes | SWTG018AS-A V2.0 | 2MB | 8273N + 8224N | +| MokerLink | 2G08110GSN | No | SWTG018AS-A V2.0 | 512KB(25Q40) | 8273N + 8224N | The following is a documentation for the unmanaged switch marked as `SWTG018AS-A V2.0`. @@ -14,7 +15,7 @@ The original software is running UART on 9600 baud rate. Using a SOIC clamp in-board is the only method for initial installation. -The board has a single flash chips `BS` with 4M-bit size. The front switch, switches between the two flash chips. +The board has a single flash chips `BS` with 2M-byte size. The front switch, switches between the two flash chips. These can be programed independently by using said switch - so it is e.g. possible to run the original and new firmware in parallel. ### Label specifications diff --git a/doc/devices/SWTG024AS-A-V2.0.1_4C_2SFP.md b/doc/devices/SWTG024AS-A-V2.0.1_4C_2SFP.md index f1fcc535..ddb3b1fc 100644 --- a/doc/devices/SWTG024AS-A-V2.0.1_4C_2SFP.md +++ b/doc/devices/SWTG024AS-A-V2.0.1_4C_2SFP.md @@ -2,9 +2,11 @@ It is highly similar to SWTG024AS-V2.0, with the only difference being the GPIO configuration for the SFP port. ## Brands -|Brand|Type|Managed|PCB|Flash|Chip RTL| -|---|---|---|---|---|---| -| Horaco | ZX-SG4T2 | | PCB-SWTG024AS-A-V2.0.1_19650 | P25D40SH | ??? | +|Brand |Type |Managed|PCB |Flash |Chip RTL| +|---------|--------------|-------|------------------------------|----------------|--------| +| Horaco | ZX-SG4T2 | No | PCB-SWTG024AS-A-V2.0.1_19650 | 512K (P25D40SH)| 8372N | +| Horaco | HC-SWTG124AS | Yes | PCB-SWTG024AS-A-V2.0.1 | 2M (W25Q16JV)| 8372N | +| GoodTop | GT-ST024M | Yes | PCB-SWTG024AS-A-V2.0.1 | 2M | 8372N | ### Label specifications diff --git a/doc/devices/SWTG024AS-V2.0.md b/doc/devices/SWTG024AS-V2.0.md index c787428b..69724577 100644 --- a/doc/devices/SWTG024AS-V2.0.md +++ b/doc/devices/SWTG024AS-V2.0.md @@ -46,4 +46,4 @@ Note,`R52`、`R53`may not be installed.You need to bridge them using either sold ## Power supply -Input power is delivered via barell plug, `12V 1A` adapter was provided. \ No newline at end of file +Input power is delivered via barell plug, `12V 1A` adapter was provided. diff --git a/doc/devices/SWTGW215AS.md b/doc/devices/SWTGW215AS.md index 0f986986..6bfdaadc 100644 --- a/doc/devices/SWTGW215AS.md +++ b/doc/devices/SWTGW215AS.md @@ -9,7 +9,7 @@ ## RTLPlayground target -Use machine target `MACHINE_LIANGUO_ZX_SWTGW215AS` for this device. +Build for this device with `make MACHINE=LIANGUO_ZX_SWTGW215AS`, which selects the `machine/LIANGUO_ZX_SWTGW215AS.c` board definition. Physical hardware verification: 5x RJ45 ports + 1x SFP port. Port 5 RJ45 is interfaced through a RTL8221B IC. diff --git a/doc/devices/SWTGW218AS.md b/doc/devices/SWTGW218AS.md index 4797125b..485584f9 100644 --- a/doc/devices/SWTGW218AS.md +++ b/doc/devices/SWTGW218AS.md @@ -5,9 +5,15 @@ |---|---|---|---|---|---| | Mokerlink | ZX-SWTGW218AS | Yes| SWTG118AS-V2.0-16029 | 2MB (FM25Q16A)| 8273N + 8224N | | Sodola | | | | | | -| Horaco | | | | | | +| Horaco | HC-SWTGW218AS | Yes | SWTG118AS-V2.1 | 2MB | 8373 (non-N) | | XikeStor | SKS3200-8E1X | Yes | SWTG118AS-V2.1-17462 | 2MB (25Q16JVSIQ) | | +All boards in this table use `MACHINE=SWTGW218AS`. The Horaco HC-SWTGW218AS is also sold with the +[SWTG018AS-A V2.0](SWTG018AS_A_V2_0.md) board, which needs a different firmware. Check the marking +on the PCB before flashing. + +The PHY and flash-chip models for the tested Horaco units remain unverified. + ## Photos diff --git a/doc/devices/photos/2G5F4_10G2_V1.01/assembled-bottom.jpg b/doc/devices/photos/2G5F4_10G2_V1.01/assembled-bottom.jpg new file mode 100644 index 00000000..8108ce66 Binary files /dev/null and b/doc/devices/photos/2G5F4_10G2_V1.01/assembled-bottom.jpg differ diff --git a/doc/devices/photos/2G5F4_10G2_V1.01/assembled-front.jpg b/doc/devices/photos/2G5F4_10G2_V1.01/assembled-front.jpg new file mode 100644 index 00000000..2cb1782b Binary files /dev/null and b/doc/devices/photos/2G5F4_10G2_V1.01/assembled-front.jpg differ diff --git a/doc/devices/photos/2G5F4_10G2_V1.01/assembled-top.jpg b/doc/devices/photos/2G5F4_10G2_V1.01/assembled-top.jpg new file mode 100644 index 00000000..e3ea7733 Binary files /dev/null and b/doc/devices/photos/2G5F4_10G2_V1.01/assembled-top.jpg differ diff --git a/doc/devices/photos/2G5F4_10G2_V1.01/flash_t25s40.jpg b/doc/devices/photos/2G5F4_10G2_V1.01/flash_t25s40.jpg new file mode 100644 index 00000000..a1af18ac Binary files /dev/null and b/doc/devices/photos/2G5F4_10G2_V1.01/flash_t25s40.jpg differ diff --git a/doc/devices/photos/2G5F4_10G2_V1.01/pcb_bottom.jpg b/doc/devices/photos/2G5F4_10G2_V1.01/pcb_bottom.jpg new file mode 100644 index 00000000..0c8cbabb Binary files /dev/null and b/doc/devices/photos/2G5F4_10G2_V1.01/pcb_bottom.jpg differ diff --git a/doc/devices/photos/2G5F4_10G2_V1.01/pcb_top.jpg b/doc/devices/photos/2G5F4_10G2_V1.01/pcb_top.jpg new file mode 100644 index 00000000..421462a2 Binary files /dev/null and b/doc/devices/photos/2G5F4_10G2_V1.01/pcb_top.jpg differ diff --git a/doc/devices/photos/Hasivo-S1100P-8GT-1SX-S/front.jpg b/doc/devices/photos/Hasivo-S1100P-8GT-1SX-S/front.jpg new file mode 100644 index 00000000..e2836b96 Binary files /dev/null and b/doc/devices/photos/Hasivo-S1100P-8GT-1SX-S/front.jpg differ diff --git a/doc/devices/photos/Hasivo-S1100P-8GT-1SX-S/pcb_bottom.jpg b/doc/devices/photos/Hasivo-S1100P-8GT-1SX-S/pcb_bottom.jpg new file mode 100644 index 00000000..3d2a6f6c Binary files /dev/null and b/doc/devices/photos/Hasivo-S1100P-8GT-1SX-S/pcb_bottom.jpg differ diff --git a/doc/devices/photos/Hasivo-S1100P-8GT-1SX-S/pcb_top.jpg b/doc/devices/photos/Hasivo-S1100P-8GT-1SX-S/pcb_top.jpg new file mode 100644 index 00000000..06d972cd Binary files /dev/null and b/doc/devices/photos/Hasivo-S1100P-8GT-1SX-S/pcb_top.jpg differ diff --git a/doc/devices/photos/PCB-K0402WS-V1.0/bottom.jpg b/doc/devices/photos/PCB-K0402WS-V1.0/bottom.jpg new file mode 100644 index 00000000..3c5d2440 Binary files /dev/null and b/doc/devices/photos/PCB-K0402WS-V1.0/bottom.jpg differ diff --git a/doc/devices/photos/PCB-K0402WS-V1.0/flash.jpg b/doc/devices/photos/PCB-K0402WS-V1.0/flash.jpg new file mode 100644 index 00000000..7781f009 Binary files /dev/null and b/doc/devices/photos/PCB-K0402WS-V1.0/flash.jpg differ diff --git a/doc/devices/photos/PCB-K0402WS-V1.0/pcb-bottom.jpg b/doc/devices/photos/PCB-K0402WS-V1.0/pcb-bottom.jpg new file mode 100644 index 00000000..43d13a7e Binary files /dev/null and b/doc/devices/photos/PCB-K0402WS-V1.0/pcb-bottom.jpg differ diff --git a/doc/devices/photos/PCB-K0402WS-V1.0/pcb-top.jpg b/doc/devices/photos/PCB-K0402WS-V1.0/pcb-top.jpg new file mode 100644 index 00000000..0ca412d7 Binary files /dev/null and b/doc/devices/photos/PCB-K0402WS-V1.0/pcb-top.jpg differ diff --git a/doc/devices/photos/PCB-K0402WS-V1.0/ports.jpg b/doc/devices/photos/PCB-K0402WS-V1.0/ports.jpg new file mode 100644 index 00000000..c6bded40 Binary files /dev/null and b/doc/devices/photos/PCB-K0402WS-V1.0/ports.jpg differ diff --git a/doc/devices/photos/PCB-K0402WS-V1.0/uart.jpg b/doc/devices/photos/PCB-K0402WS-V1.0/uart.jpg new file mode 100644 index 00000000..b76602a5 Binary files /dev/null and b/doc/devices/photos/PCB-K0402WS-V1.0/uart.jpg differ diff --git a/doc/devices/photos/PCB-K0402WS-V3.0/Siscolink SL-G0402F.jpg b/doc/devices/photos/PCB-K0402WS-V3.0/SICSOLINK SL-G0402F.jpg similarity index 100% rename from doc/devices/photos/PCB-K0402WS-V3.0/Siscolink SL-G0402F.jpg rename to doc/devices/photos/PCB-K0402WS-V3.0/SICSOLINK SL-G0402F.jpg diff --git a/doc/devices/photos/PCB-K0402WS-V3.0/YuanLey_YS25-0402.jpg b/doc/devices/photos/PCB-K0402WS-V3.0/YuanLey_YS25-0402.jpg new file mode 100644 index 00000000..bb403cce Binary files /dev/null and b/doc/devices/photos/PCB-K0402WS-V3.0/YuanLey_YS25-0402.jpg differ diff --git a/doc/devices/photos/SIRIVISION_S25G2206FP_V1_1/dev_pcb_top.jpg b/doc/devices/photos/SIRIVISION_S25G2206FP_V1_1/dev_pcb_top.jpg new file mode 100644 index 00000000..dfa6ec8f Binary files /dev/null and b/doc/devices/photos/SIRIVISION_S25G2206FP_V1_1/dev_pcb_top.jpg differ diff --git a/doc/igmp.md b/doc/igmp.md index 1584287f..b1aeda67 100644 --- a/doc/igmp.md +++ b/doc/igmp.md @@ -73,7 +73,8 @@ uint8_t igmp_packet_handler(void) __banked; void igmp_show(void) __banked; ```c `igmp_setup()` is called at boot-time and configures flooding of all IP-MC packets by -default, as otherwise no IP-MC would be possible in the network. +default, as otherwise no IP-MC would be possible in the network. `igmp off` calls it as +well; groups learned while IGMP was on stay in the table, but are no longer looked up. `igmp_enable()`starts IGMP which cause IGMP packets to be handled by the CPU and forwarding of IP-MC packets to be limited to only subscribed ports. @@ -85,6 +86,9 @@ for frames to 01:00:5e:xx:xx:xx and returns 0 when the frame is not a trapped IG so that it is passed on to the IP stack. IGMPv1/v2 reports (0x12, 0x16) join the group given in the IGMP header, IGMPv2 leaves (0x17) leave it, IGMPv3 reports use the first group record (type 4 joins, type 3 leaves). Trapped IGMP frames arrive without a VLAN tag. +Reports for groups in 224.0.0.0/24 are ignored: the switch floods that block +even with IGMP on, and an entry for a group such as 224.0.0.251 (mDNS) would +otherwise limit it to the ports that reported it, as RFC 4541 warns against. `igmp_show()` prints out the IGMP configuration on the CLI. diff --git a/doc/l2.md b/doc/l2.md index 0a785a8f..ccf891cf 100644 --- a/doc/l2.md +++ b/doc/l2.md @@ -73,13 +73,14 @@ without being flooded to the other ports. No bridge relays these frames: their addresses are in the set that 802.1D-2004 clause 7.12.6 forbids a bridge to forward, and what travels the network is the information, with every bridge regenerating BPDUs of its own on its designated ports. The reserved-multicast *trap* action -cannot do that on this hardware, because its destination is an external CPU -attached to a physical port, which these boards do not populate. The protocol -modules therefore leave the reserved-multicast action at *forward* and constrain -the egress with a static L2 multicast entry instead: the lookup hits the entry's -own port mask rather than the VLAN flood mask. Verified on a SWTGW218AS both -ways, with the CPU bit cleared, where delivery stops, and with the CPU bit alone, -where nothing egresses. +does that: it delivers to the port named in `EXT_CPU_CTRL` (0x6724), which +`trap_init()` sets to 9, the CPU port, at startup; with the reset value 0xf it +names no port and the trapped frame is dropped. STP traps its address while it +runs (see stp.md). Where the action is left at *forward*, the egress can be +constrained with a static L2 multicast entry instead: the lookup hits the +entry's own port mask rather than the VLAN flood mask. Verified on a SWTGW218AS +both ways, with the CPU bit cleared, where delivery stops, and with the CPU bit +alone, where nothing egresses. `port_l2mc_set()` writes one such entry. The SMI layout is the L2 multicast variant of the table entry: diff --git a/doc/lacp.md b/doc/lacp.md new file mode 100644 index 00000000..b116ef9a --- /dev/null +++ b/doc/lacp.md @@ -0,0 +1,155 @@ +# LACP (Link Aggregation Control Protocol, IEEE 802.3ad) + +A static link aggregation group works only if both ends are configured for the +same links, and nothing checks that they are. LACP lets the two ends agree on +which links reach the same partner, aggregates only those, and takes a link out +of the group when the partner stops answering. + +The switch runs LACP in software on the 8051. LACP frames belong to the Slow +Protocols, with destination `01:80:C2:00:00:02` and ethertype `0x8809`; the +subtype of LACP frames is 1. The implementation has the Receive, Selection and +Mux machines of 802.3ad clause 43 and does not aggregate links whose partners +differ. Up to `LACP_NUM_LAGS` (4) groups can run LACP; the others stay static. + +## Getting the frames to the CPU + +While LACP runs, the reserved multicast action for `01:80:C2:00:00:02` is +*trap*, the same mechanism STP uses for its BPDUs, see [stp.md](stp.md). A +trapped LACPDU has no VLAN tag after the RTL tag, and `TRAP_RX_BODY()` gives the +offset of the LACPDU in the received frame. When the last group leaves LACP, +the action goes back to *drop*. + +## What has to match across the members + +802.3ad requires that every link in an aggregate be full duplex and run at the +same speed. Beyond the standard, anything that changes how a frame is treated +has to be identical across members, because the hash picks the member per frame +and a difference would make the behaviour depend on that choice: + +* must match: speed and duplex, VLAN membership and pvid, ingress filtering, + port isolation +* may differ: EEE, LED configuration, counters, cable diagnostics + +None of this is enforced yet — `port_lag_members_set()` writes a member mask and +a hash setting and validates nothing. See #377 for the discussion of whether a +mismatch should be rejected or applied to the whole group. + +## Protocol timing + +The timer values are in units of the LACP timer, which steps every four ticks +of the system clock, 50 times per second: + +| Constant | Value | Time | +|----------------------|-------|------| +| `LACP_FAST_PERIODIC` | 50 | 1 s | +| `LACP_SLOW_PERIODIC` | 1500 | 30 s | +| `LACP_SHORT_TIMEOUT` | 200 | 4 s | + +802.3ad specifies a fast periodic time of 1 s with a short timeout of 3 s, and a +slow periodic time of 30 s with a long timeout of 90 s. The switch transmits at +the rate the partner asks for with its TIMEOUT bit. Its own timeout is always +the short one, one second above the standard, so a partner that stops sending +while its link stays up leaves the trunk after 4 s. + +The Partner block of a transmitted LACPDU repeats the partner's actor +information as it was last received: system priority, system, key, port +priority, port and state. A Linux partner sets our SYNC only when this block +matches what it sent. + +## LACP API + +``` +void lacp_init(void) __banked; +void lacp_off(void) __banked; +void lacp_lag_set(uint8_t lag, __xdata uint16_t ports) __banked; +void lacp_in(void) __banked; +void lacp_timers(void) __banked; +void lacp_show(void) __banked; +``` + +`lacp_init()` has to run before the startup configuration replays, because xdata +is not zeroed and the port-to-LAG map uses `0xff` as "no LAG"; a stray zero would +make a port look like it belongs to LAG 0. + +## LACP configuration on the serial console + +A group is put under LACP by adding `lacp` to the `lag` command: + +``` +lag 1 lacp 7 8 # ports 7 and 8 become LACP candidates of group 1 +lag 1 lacp off # group 1 leaves LACP, its trunk is cleared (so does "lag 1 lacp") +lag 1 d # group 1 disabled, whether it ran LACP or not +lag 1 7 8 # plain static aggregation, no protocol +``` + +A group put under LACP gives up the static trunk it had: the hardware trunk is +cleared and rebuilt from the ports that converge. The other way round, `lag 1 d` +and a static member list take the group out of LACP before they touch the +trunk. A port named in another LACP group moves to the new one. The protocol +starts with the first group put under LACP and stops when the last one is taken +out; there is no separate switch for it. Two commands act on the whole engine: + +``` +lacp off # every group leaves LACP, protocol stopped +lacp show +``` + +`lacp show` prints the engine state, then one line per group with its candidate +ports, the elected aggregator and the trunk members actually programmed into the +hardware, then one line per port with the actor and partner state bytes and the +receive-machine state. + +## LACP configuration via the Web Interface + +Each group on the LAG page has a Static/LACP mode next to its member ports; +for an LACP group it shows the elected aggregator and the active members. Below +the groups a table has one row per LACP port with its group, actor and partner +state, receive state, LACPDU count and partner system. The page reads +`/lacp.json` every three seconds while it is open. The member checkboxes of a +static group come from the hardware registers in `/lag.json`. + +## A test with a Linux 802.3ad bond + +Two ports of the switch to two interfaces of one host: + +``` +ip link add bond0 type bond mode 802.3ad +ip link set enp1s0 down && ip link set enp1s0 master bond0 +ip link set enp2s0 down && ip link set enp2s0 master bond0 +ip link set bond0 up +``` + +On the switch, with those two ports as the group: + +``` +lag 1 lacp 7 8 +``` + +`lacp show` should then give both ports an actor state of `0x3f` (ACTIVITY, +TIMEOUT, AGGREGATION, SYNC, COLLECTING and DISTRIBUTING), a partner state with +SYNC set, and the partner's system MAC. `lag show` lists the trunk members as +programmed in the hardware and should show both ports. + +On the host, `/proc/net/bonding/bond0` should show the same `Aggregator ID` for +both slaves; different IDs mean that each link is in a group of its own. Both +churn states should read `none`. + +Further checks: + +* `tcpdump -i enp1s0 ether proto 0x8809` on each slave shows the LACPDUs of the + switch and of that slave, never those of the other slave. +* The host log has no `illegal loopback`. +* The three reserved bytes after the actor state in a LACPDU from the switch + are zero. + +When one slave goes down, the group narrows to the remaining member, and the +slave rejoins after it comes back. + +## Known limits + +* No Churn Detection machines and no Marker protocol. +* Coupled Mux: collecting and distributing are enabled together. +* One aggregator per group. +* Selection compares the partner's system only, not its key: two aggregates + that one partner system offers on the same group land in one trunk here. +* Member compatibility is not validated; see #377. diff --git a/doc/link_aggregation.md b/doc/link_aggregation.md index b725e419..90fc7637 100644 --- a/doc/link_aggregation.md +++ b/doc/link_aggregation.md @@ -227,3 +227,7 @@ iperf Done. ``` As you can see, the total throughput was 4.71 GBit/sec which is close to the maximum possible with a single 5GBit link. + +## LACP + +Dynamic aggregation with LACP is described in [lacp.md](lacp.md). diff --git a/doc/stp.md b/doc/stp.md index 8b6780c5..96368535 100644 --- a/doc/stp.md +++ b/doc/stp.md @@ -35,28 +35,34 @@ BPDUs are addressed to `01:80:C2:00:00:00`, a reserved link-local group. The ASIC's Reserved-Multicast action for that address decides what happens to the frame. -Forwarding to the CPU port works normally: the 8051 sits behind an ordinary -port of the internal switch and is an ordinary member of a forwarding mask. -The *trap* action does not deliver to it. Its destination is an external CPU -attached to a physical port (`cpuTag_externalCpuPort_set`, `EXT_CPU_CTRL` in -the vendor SDK), which these boards do not populate. The ACL trap and -redirect actions do not deliver to the 8051 either. +While STP runs, the action is *trap*. A trap delivers to the port named in +`EXT_CPU_CTRL` (0x6724), whose reset value 0xf names no port, and with that +value the trapped frame is dropped at ingress. `trap_init()` sets it to 9, the +port the 8051 sits behind, once at startup. The trap needs no per-VLAN L2 +entries, so it does not depend on which VLANs exist or on the PVIDs, and turning +STP on no longer walks the whole VLAN table. BPDUs reach the CPU on a port that +STP holds in blocking with either action: measured on a SWTGW218AS by sending +BPDUs into a blocked port with forward and with trap, both ports stopped being +edge and waited out the forward delay. The chip exempts this address from the +ingress state check; the slow-protocols address used by LACP is not exempt. -Delivery therefore uses the *forward* action, constrained to the CPU port -by a static L2 multicast entry (`port_l2mc_set()`), one per VLAN in use: +A trapped frame reaches the CPU in the format it came in with: unlike a +forwarded one it has no VLAN tag inserted after the RTL tag, and the RTL tag +carries the trap reason. `stp_in()` reads the BPDU from the offset +`TRAP_RX_BODY()` returns, which works for both. -* while STP runs, the entry's member mask is the CPU port only — BPDUs reach - the CPU and are not flooded to other ports, as a participating bridge - requires; -* with STP off, the same entries are retargeted to all ports, restoring the - transparency an unmanaged switch is expected to have, so a surrounding - spanning tree can span *through* this device. +With STP off, the action goes back to *forward* and a static L2 multicast +entry per VLAN in use (`port_l2mc_set()`) targets all ports, restoring the +transparency an unmanaged switch is expected to have, so a surrounding +spanning tree can span *through* this device. -A BPDU delivered this way is an ordinary frame to the port's ingress logic -and passes through its acceptable-frame-type filter. BPDUs are untagged, so a -port set to admit tagged frames only (`ingress t`) never delivers one -to the CPU. `stp_setup()` prints a warning for every STP-enabled port in that -state. +The port's acceptable-frame-type filter treats the two actions differently. +BPDUs are untagged, so a port set to admit tagged frames only +(`ingress t`) drops a forwarded BPDU before it reaches the CPU, while a +trapped one passes. Both were measured on a SWTGW218AS with `ingress 3t`: +LACPDUs, delivered by forward, stopped arriving on port 3, and BPDUs sent into +the same port, delivered by trap, kept arriving. A port that admits tagged +frames only therefore takes part in STP. ## Link aggregation diff --git a/doc/supported_devices.md b/doc/supported_devices.md index 52e62bcd..3d3d5ba2 100644 --- a/doc/supported_devices.md +++ b/doc/supported_devices.md @@ -4,44 +4,52 @@ The following devices have been tested and are fully working: | Brand | Type | Managed | PCB | Flash | Ports | |----------|-----------------|---------|---------------------------------------------------------------------------|-------|-------| | Ampcom | WAM902-SWTG018AS| No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 | +| Binardat | 2G06-04210GSM | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 | | Davuaz | Da-K6501W | No | [PCB-K0501W-V2.0](devices/K0501W_V2_0.md) | | 5 + 1 | | FOXNEO | FNS-1200P | No | [PCB-K0402W-U13-V2.0](devices/FNS-1200P.md) | 2M | 4 + 2 | | Goalake | IG108 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 | -| GoodTop | GT-ST018M | Yes | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | ? | 8 + 1 | +| GoodTop | GT-ST018M | Yes | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | 2M | 8 + 1 | +| GoodTop | GT-ST024M | Yes | [SWTG024AS-A V2.0.1](devices/SWTG024AS-A-V2.0.1_4C_2SFP.md) | 2M | 4 + 2 | +| Guangnianwei | 7018-2.5G | No | [F7008-2.5GPOE-V1.2](devices/F7008-2.5.md) | 8M | 8 + 1 | | Hasivo | S1100WP_8GT_1SX_SE | Yes | [S1100WP_8GT_1SX_SE-V1.05](devices/HASIVO_S1100WP_8GT_1SX_SE.md) | 2M | 8 + 1 | -| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 | | Hisource | Hi-K0402WS | No | [PCB-K0402WS-V2.0](devices/PCB-K0402WS-V2.0.md) | 2M | 4 + 2 | +| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 | | Hisource | Hi-K0801WS | No | [PCB-KO801W-V2.0](devices/HI-K0801WS.md) | | 8 + 1 | +| hongyavision | HYWS-SGT0204S | No | [2G5F4_10G2_V1.01](devices/2G5F4_10G2_V1.01.md) | 0.5M | 4 + 2 | | hongyavision | LG-SG5T1 | No | [PCB-SWTG024AS-V2.0_16895](devices/SWTG024AS-V2.0.md) | 0.5M | 5 + 1 | +| Horaco | HC-SWTG124AS | Yes | [SWTG024AS-A-V2.0.1](devices/SWTG024AS-A-V2.0.1_4C_2SFP.md) | 2M | 4 + 2 | | Horaco | HC-SWTGW215AS | Yes | [SWTG024AS-A-V2.0.1_19650 5C 1SFP](devices/SWTG024AS-A-V2.0.1_5C_1SFP.md) | ? | 5 + 1 | | Horaco | HC-SWTGW218AS | Yes | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 | +| Horaco | HC-SWTGW218AS | Yes | [SWTG118AS-V2.1](devices/SWTGW218AS.md) | 2M | 8 + 1 | | Horaco | ZX310S-4T2XH | Yes | [PCB-SL310S-4T1T1X-V1.0.1-24107](devices/ZX310S-4T2XH.md) | 2M | 5 + 1 | | Horaco | ZX310S-4T2XT | Yes | [PCB-SL310S-4T2XT-V1.0.0-22273](devices/ZX310S-4T2XT.md) | 2M | 6 | | Horaco | ZX-SG4T2 | No | [SWTG024AS-A-V2.0.1_19650_4C_2SFP](devices/SWTG024AS-A-V2.0.1_4C_2SFP.md) | 0.5M | 4 + 2 | | Horaco | ZX-SWTG124AS | Yes | [SWTG024AS-v2.0](devices/SWTG024AS.md) | | 4 + 2 | -| Keeplink | KP-9000-6XH-X2 / KP-9000-6XHML-X2 | No/Yes | [2M-PCB43-V1.2 / V2.1](devices/KP-9000-6XH-X2.md) | | 4 + 2 | +| keepLINK | KP-9000-6XH-X2 / KP-9000-6XHML-X2 | No/Yes | [2M-PCB43-V1.2 / V2.1](devices/KP-9000-6XH-X2.md) | | 4 + 2 | | keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V2.2](devices/2M-PCB23-V2_2.md) | 2M | 8 + 1 | | keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.1](devices/2M-PCB23-V3_1.md) | 2M | 8 + 1 | | keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.2](devices/2M-PCB23-V3_2.md) | 2M | 8 + 1 | +| LIANGUO | HYWS-SGT0108S | No | [2G5F_20G_V1.01](devices/HYWS-SGT0108S.md) | 0.5M | 8 + 1 | | LIANGUO | SWTG024AS | No | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 0.5M | 4 + 2 | -| Lianguo | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 | -| Lianguo | HYWS-SGT0108S | No | [2G5F_20G_V1.01](devices/HYWS-SGT0108S.md) | 0.5M | 8 + 1 | -| Mokerlink| 2G040210GSM | Yes | [2M-PCB43-V1.1](devices/2M-PCB43-V1.1.md) | | 4 + 2 | -| Mokerlink| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 | +| LIANGUO | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 | +| MokerLink| 2G040210GSM | Yes | [2M-PCB43-V1.1](devices/2M-PCB43-V1.1.md) | | 4 + 2 | | MokerLink| POE-2G080110GS | No | [2M-PCB51-ML-V1.1](devices/2M-PCB51-ML-V1_1.md) | 4M | 8 + 1 | -| Binardat | 2G06-04210GSM | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 | -| ONT | ONT-S207CW-62TS-SE | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 | +| MokerLink| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 | +| MokerLink| 2G08110GSN | No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | 0.5M | 8 + 1 | | Netcore | GS9 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 | +| ONT | ONT-S207CW-62TS-SE | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 | | Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 | | Ruiying | RY-8GT-1SX | No | [FG-8GT-1SX](devices/FG-8GT-1SX.md) | 1M | 8 + 1 | -| SiscoLink | SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 | +| SICSOLINK| SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 | | Sodola | SL-SWTG124AS-D | Yes | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 2M | 4 + 2 | | Steamemo | IG204-V1 | No | [PB-2131](devices/STEAMEMO_IG204_V1.md) | | 4 + 2 | -| TrendNet | TEG-S562 | No | [TEG-S563/EU H/W: V1.0R](devices/TEG-S562.md) | 2M | 4 + 2 | -| Xikestore| SKS3200M-4GPY2XF| Yes | [SWTG024AS-v1.0](devices/SWTG024AS.md) | | 4 + 2 | +| TRENDnet | TEG-S562 | No | [TEG-S563/EU H/W: V1.0R](devices/TEG-S562.md) | 2M | 4 + 2 | +| XikeStor | SKS3200M-4GPY2XF| Yes | [SWTG024AS-v1.0](devices/SWTG024AS.md) | | 4 + 2 | | XikeStor | SKS3200-8E1X | Yes | [SWTG118AS-V2.1-17462](devices/SWTGW218AS.md) | 2M | 8 + 1 | +| YuanLey | YS25-0402 | No | [PCB-K0402WS-V1.0](devices/PCB-K0402WS-V1.0.md) | 2M | 4 + 2 | +| YuanLey | YS25-0402 | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | 2M | 4 + 2 | +| YuanLey | YS25-0402M | Yes | [SIRIVISION_S25G2206FP_V1_1](devices/SIRIVISION_S25G2206FP_V1_1.md) | 2M | 4 + 2 | | Ztyuav | Z-QWYT0402 | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 | -| Guangnianwei | 7018-2.5G | No | [F7008-2.5GPOE-V1.2](devices/F7008-2.5.md) | 8M | 8 + 1 | For KP-9000-6XH-X2 / KP-9000-6XHML-X2 / Mokerlink 2G040210GSM devices, select the machine target by PCB revision. The ML/non-ML or managed/unmanaged label diff --git a/html/app.js b/html/app.js index d737810b..1599e3f0 100644 --- a/html/app.js +++ b/html/app.js @@ -11,15 +11,15 @@ th_sel_light:"Selenized Light",th_sel_dark:"Selenized Dark", c_port:"Port",c_name:"Name",c_link:"Link",c_apply:"Apply",c_cancel:"Cancel",c_confirm:"Confirm", c_close:"Close",c_refresh:"Refresh",c_off:"off",c_offc:"Off",c_down:"down",c_on:"On",c_auto:"Auto",c_delete:"Delete", c_type:"Type",c_state:"State",c_enabled:"Enabled",c_load:"Load",c_disable:"Disable",c_sfp:"SFP", -c_full:"full",c_half:"half",c_devices:"devices",c_yes:"yes",c_no:"no", -d_ports:"Ports",d_ports_h:"click a port for details",d_system:"System",d_traffic:"Traffic", +c_full:"full",c_half:"half",c_yes:"yes",c_no:"no", +d_system:"System",d_traffic:"Traffic", d_traffic_h:"packets/s, live",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX bad",d_rxbad:"RX bad", i_host:"Hostname",i_ip:"IP address",i_mask:"Netmask",i_gw:"Gateway",i_mac:"MAC",i_fw:"Firmware", i_built:"Built",i_hw:"Hardware",i_temp:"Temperature",i_flash:"Flash",i_syslog:"Syslog", p_state:"State",p_disabled:"disabled",p_up:"up",p_txgb:"TX good / bad",p_rxgb:"RX good / bad", p_pkts:"pkts",p_module:"Module",p_temp:"Temperature",p_vcc:"Vcc",p_txbias:"TX bias",p_txpower:"TX power", p_rxpower:"RX power",p_txfault:"TX fault",p_txdis:"TX disabled",p_rxlos:"RX LOS",p_adv:"Advertising", -pt_title:"Port configuration",pt_conn:"Connected",pt_speed:"Speed",pt_mtu:"MTU", +pt_title:"Port configuration",pt_conn:"Devices learned",pt_speed:"Speed",pt_mtu:"MTU", pt_sfp_note:"SFP speed is set per slot and is not saved in the startup config.", pt_name_err:"Port name: 1-15 characters, no spaces",pt_mtu_err:"MTU must be 64-16383", stp_title:"Spanning tree",stp_h:"RSTP, 802.1w",stp_version:"Version",stp_v_stp:"STP compatible", @@ -67,6 +67,9 @@ iso_title:"Port isolation",iso_from:"From port",iso_to:"To port",iso_all:"Allow iso_intro:"A frame entering a port may only leave through the ports ticked in its row. Isolation is decided before forwarding, so a port that is not ticked is unreachable directly, whatever the address table says.", iso_legend:"The cell of the port itself is always allowed. A port number in red marks a port that is not fully open.", lag_hash:"Hash:",lag_note:"A LAG needs at least one member to be saved in the startup config; applying an empty group clears it.", +lacp_heading:"LACP (802.3ad)",lag_mode:"Mode",lag_static:"Static",lacp_neg:"negotiating",lacp_agg:"aggregator", +lacp_members:"active members",lacp_hint:"LACP: select candidate ports and press Apply to start negotiation", +lacp_actor:"Actor",lacp_partner:"Partner",lacp_rxstate:"RX state",lacp_rx:"LACPDUs received",lacp_psys:"Partner system", lag_clear_q:"Clear LAG {n}?",lag_clear_d:"All member ports return to normal operation.", e_title:"Energy Efficient Ethernet",e_adv:"Advertised",e_lp:"Link partner",e_active:"Active",e_enable:"Enable", e_note:"Advertised and link-partner flags per speed: 100M, 1G, 2.5G. SFP ports do not support EEE.", @@ -139,15 +142,15 @@ th_sel_light:"Selenized ライト",th_sel_dark:"Selenized ダーク", c_port:"ポート",c_name:"名前",c_link:"リンク",c_apply:"適用",c_cancel:"キャンセル",c_confirm:"確認", c_close:"閉じる",c_refresh:"更新",c_off:"オフ",c_offc:"オフ",c_down:"リンクダウン",c_on:"オン",c_auto:"自動",c_delete:"削除", c_type:"タイプ",c_state:"状態",c_enabled:"有効",c_load:"読み込み",c_disable:"無効化",c_sfp:"SFP", -c_full:"全二重",c_half:"半二重",c_devices:"デバイス",c_yes:"はい",c_no:"いいえ", -d_ports:"ポート",d_ports_h:"ポートをクリックすると詳細を表示",d_system:"システム",d_traffic:"トラフィック", +c_full:"全二重",c_half:"半二重",c_yes:"はい",c_no:"いいえ", +d_system:"システム",d_traffic:"トラフィック", d_traffic_h:"パケット/秒、リアルタイム",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX 異常",d_rxbad:"RX 異常", i_host:"ホスト名",i_ip:"IP アドレス",i_mask:"ネットマスク",i_gw:"ゲートウェイ",i_mac:"MAC",i_fw:"ファームウェア", i_built:"ビルド日",i_hw:"ハードウェア",i_temp:"温度",i_flash:"フラッシュ",i_syslog:"Syslog", p_state:"状態",p_disabled:"無効",p_up:"アップ",p_txgb:"TX 正常 / 異常",p_rxgb:"RX 正常 / 異常", p_pkts:"pkts",p_module:"モジュール",p_temp:"温度",p_vcc:"電圧",p_txbias:"TX バイアス",p_txpower:"TX 電力", p_rxpower:"RX 電力",p_txfault:"TX 障害",p_txdis:"TX 無効",p_rxlos:"RX 信号ロス",p_adv:"アドバタイズ", -pt_title:"ポート設定",pt_conn:"接続デバイス",pt_speed:"速度",pt_mtu:"MTU", +pt_title:"ポート設定",pt_conn:"学習済みデバイス",pt_speed:"速度",pt_mtu:"MTU", pt_sfp_note:"SFP の速度はスロット単位で設定され、起動設定には保存されません。", pt_name_err:"ポート名: 1〜15 文字、空白不可",pt_mtu_err:"MTU は 64〜16383 の範囲で指定してください", stp_title:"スパニングツリー",stp_h:"RSTP, 802.1w",stp_version:"バージョン",stp_v_stp:"STP 互換", @@ -252,15 +255,15 @@ th_sel_light:"Selenized 浅色",th_sel_dark:"Selenized 深色", c_port:"端口",c_name:"名称",c_link:"链路",c_apply:"应用",c_cancel:"取消",c_confirm:"确认", c_close:"关闭",c_refresh:"刷新",c_off:"关",c_offc:"关",c_down:"未连接",c_on:"开",c_auto:"自动",c_delete:"删除", c_type:"类型",c_state:"状态",c_enabled:"启用",c_load:"读取",c_disable:"禁用",c_sfp:"SFP", -c_full:"全双工",c_half:"半双工",c_devices:"台设备",c_yes:"是",c_no:"否", -d_ports:"端口",d_ports_h:"点击端口查看详情",d_system:"系统",d_traffic:"流量", +c_full:"全双工",c_half:"半双工",c_yes:"是",c_no:"否", +d_system:"系统",d_traffic:"流量", d_traffic_h:"包/秒,实时",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX 错误",d_rxbad:"RX 错误", i_host:"主机名",i_ip:"IP 地址",i_mask:"子网掩码",i_gw:"网关",i_mac:"MAC",i_fw:"固件", i_built:"构建日期",i_hw:"硬件",i_temp:"温度",i_flash:"Flash",i_syslog:"Syslog", p_state:"状态",p_disabled:"已禁用",p_up:"已连接",p_txgb:"TX 正常 / 错误",p_rxgb:"RX 正常 / 错误", p_pkts:"个包",p_module:"模块",p_temp:"温度",p_vcc:"供电电压",p_txbias:"TX 偏置电流",p_txpower:"TX 光功率", p_rxpower:"RX 光功率",p_txfault:"TX 故障",p_txdis:"TX 禁用",p_rxlos:"RX 信号丢失",p_adv:"通告能力", -pt_title:"端口配置",pt_conn:"已连接设备",pt_speed:"速率",pt_mtu:"MTU", +pt_title:"端口配置",pt_conn:"已学习设备",pt_speed:"速率",pt_mtu:"MTU", pt_sfp_note:"SFP 速率按插槽设置,不会保存到启动配置。", pt_name_err:"端口名称: 1-15 个字符,不能包含空格",pt_mtu_err:"MTU 范围为 64-16383", stp_title:"生成树",stp_h:"RSTP, 802.1w",stp_version:"版本",stp_v_stp:"STP 兼容", @@ -365,15 +368,15 @@ th_sel_light:"Selenized claro",th_sel_dark:"Selenized oscuro", c_port:"Puerto",c_name:"Nombre",c_link:"Enlace",c_apply:"Aplicar",c_cancel:"Cancelar",c_confirm:"Confirmar", c_close:"Cerrar",c_refresh:"Actualizar",c_off:"apagado",c_offc:"Apagado",c_down:"caído",c_on:"Encendido",c_auto:"Auto",c_delete:"Eliminar", c_type:"Tipo",c_state:"Estado",c_enabled:"Habilitado",c_load:"Cargar",c_disable:"Deshabilitar",c_sfp:"SFP", -c_full:"dúplex completo",c_half:"semidúplex",c_devices:"dispositivos",c_yes:"sí",c_no:"no", -d_ports:"Puertos",d_ports_h:"pulsa un puerto para ver detalles",d_system:"Sistema",d_traffic:"Tráfico", +c_full:"dúplex completo",c_half:"semidúplex",c_yes:"sí",c_no:"no", +d_system:"Sistema",d_traffic:"Tráfico", d_traffic_h:"paquetes/s, en vivo",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX erróneos",d_rxbad:"RX erróneos", i_host:"Nombre de host",i_ip:"Dirección IP",i_mask:"Máscara de red",i_gw:"Puerta de enlace",i_mac:"MAC",i_fw:"Firmware", i_built:"Compilado",i_hw:"Hardware",i_flash:"Flash",i_syslog:"Syslog", p_state:"Estado",p_disabled:"deshabilitado",p_up:"activo",p_txgb:"TX correctos / erróneos",p_rxgb:"RX correctos / erróneos", p_pkts:"paquetes",p_module:"Módulo",p_temp:"Temperatura",p_vcc:"Vcc",p_txbias:"Polarización TX",p_txpower:"Potencia TX", p_rxpower:"Potencia RX",p_txfault:"Fallo TX",p_txdis:"TX deshabilitado",p_rxlos:"Pérdida RX (LOS)",p_adv:"Anunciado", -pt_title:"Configuración de puerto",pt_conn:"Conectado",pt_speed:"Velocidad",pt_mtu:"MTU", +pt_title:"Configuración de puerto",pt_conn:"Dispositivos aprendidos",pt_speed:"Velocidad",pt_mtu:"MTU", pt_sfp_note:"La velocidad del SFP se ajusta por ranura y no se guarda en la configuración de inicio.", pt_name_err:"Nombre de puerto: 1-15 caracteres, sin espacios",pt_mtu_err:"El MTU debe estar entre 64 y 16383", stp_title:"Árbol de expansión",stp_h:"RSTP, 802.1w",stp_version:"Versión",stp_v_stp:"STP compatible", @@ -477,15 +480,15 @@ th_sel_light:"Clair (sélénisé)",th_sel_dark:"Sombre (sélénisé)", c_port:"Port",c_name:"Nom",c_link:"Lien",c_apply:"Appliquer",c_cancel:"Annuler",c_confirm:"Confirmer", c_close:"Fermer",c_refresh:"Raffraichir",c_off:"arrêt",c_offc:"Arrêt",c_down:"arrêt",c_on:"Marche",c_auto:"Auto",c_delete:"Supprimer", c_type:"Type",c_state:"Etat",c_enabled:"Activé",c_load:"Charger",c_disable:"Désactivé",c_sfp:"SFP", -c_full:"full",c_half:"half",c_devices:"Equipements",c_yes:"oui",c_no:"non", -d_ports:"Ports",d_ports_h:"Cliquez ou survollez pour plus de détails",d_system:"Système",d_traffic:"Trafic", +c_full:"full",c_half:"half",c_yes:"oui",c_no:"non", +d_system:"Système",d_traffic:"Trafic", d_traffic_h:"paquets/s (en direct)",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX KO",d_rxbad:"RX KO", i_host:"Nom d'hote",i_ip:"Adresse IP",i_mask:"Masque réseau",i_gw:"Passerelle",i_mac:"Adresse MAC",i_fw:"Micro logiciel", i_built:"Compilé le",i_hw:"Matériel",i_temp:"Température",i_flash:"Taille Flash",i_syslog:"Journal système", p_state:"Etat",p_disabled:"Inactif",p_up:"Actif",p_txgb:"TX bon / mauvais",p_rxgb:"RX bon / mauvais", p_pkts:"paquets",p_module:"Module",p_temp:"Température",p_vcc:"Vcc",p_txbias:"TX biais",p_txpower:"TX puissance", p_rxpower:"RX puissance",p_txfault:"TX erreur",p_txdis:"TX désactivé",p_rxlos:"RX pertes de signaux",p_adv:"Capacités", -pt_title:"Configuration du port",pt_conn:"Connecté à",pt_speed:"Vitesse",pt_mtu:"MTU", +pt_title:"Configuration du port",pt_conn:"Appareils appris",pt_speed:"Vitesse",pt_mtu:"MTU", pt_sfp_note:"La vitesse SFP est paramétrée pour le port et n'est pas enregistrée dans la configuration de démarrage.", pt_name_err:"Nom du port: 1 à 15 caractères, sans espaces",pt_mtu_err:"MTU doit être comrpis entre 64 et 16383", stp_title:"Arborescence",stp_h:"RSTP, 802.1w",stp_version:"Protocole",stp_v_stp:"Compatible STP", @@ -585,7 +588,7 @@ fw_timeout:"Le commutateur n'est plus joignable depuis 150 s: verifiez l'aliment }, de:{ nav_dash:"Übersicht",nav_ports:"Ports",nav_stp:"Spanning Tree",nav_stats:"Statistik", -nav_vlan:"VLANs",nav_l2:"MAC-Tabelle",nav_mirror:"Spiegelung",nav_lag:"LAG",nav_eee:"EEE", +nav_vlan:"VLANs",nav_l2:"MAC-Tabelle",nav_mirror:"Spiegelung",nav_isolate:"Isolation",nav_lag:"LAG",nav_eee:"EEE", nav_bw:"Bandbreite",nav_system:"System",nav_fw:"Firmware", hdr_dirty:"ungespeicherte Änderungen",hdr_dirty_t:"Laufende Konfiguration weicht von der Startkonfiguration ab", hdr_save:"Im Flash speichern",hdr_save_t:"Laufende Konfiguration dauerhaft im Flash speichern", @@ -594,15 +597,15 @@ th_sel_light:"Selenized Hell",th_sel_dark:"Selenized Dunkel", c_port:"Port",c_name:"Name",c_link:"Link",c_apply:"Übernehmen",c_cancel:"Abbrechen",c_confirm:"Bestätigen", c_close:"Schliessen",c_refresh:"Aktualisieren",c_off:"aus",c_offc:"Aus",c_down:"getrennt",c_on:"Ein",c_auto:"Auto",c_delete:"Löschen", c_type:"Typ",c_state:"Zustand",c_enabled:"Aktiviert",c_load:"Laden",c_disable:"Deaktivieren",c_sfp:"SFP", -c_full:"voll",c_half:"halb",c_devices:"Geräte",c_yes:"ja",c_no:"nein", -d_ports:"Ports",d_ports_h:"Port anklicken für Details",d_system:"System",d_traffic:"Datenverkehr", +c_full:"voll",c_half:"halb",c_yes:"ja",c_no:"nein", +d_system:"System",d_traffic:"Datenverkehr", d_traffic_h:"Pakete/s, live",d_txpps:"TX Pakete/s",d_rxpps:"RX Pakete/s",d_txbad:"TX fehlerhaft",d_rxbad:"RX fehlerhaft", i_host:"Hostname",i_ip:"IP-Adresse",i_mask:"Netzmaske",i_gw:"Gateway",i_mac:"MAC",i_fw:"Firmware", i_built:"Erstellt",i_hw:"Hardware",i_temp:"Temperatur",i_flash:"Flash",i_syslog:"Syslog", p_state:"Zustand",p_disabled:"deaktiviert",p_up:"verbunden",p_txgb:"TX gut / fehlerhaft",p_rxgb:"RX gut / fehlerhaft", p_pkts:"Pakete",p_module:"Modul",p_temp:"Temperatur",p_vcc:"Vcc",p_txbias:"TX-Bias",p_txpower:"Sendeleistung", p_rxpower:"Empfangsleistung",p_txfault:"TX-Fehler",p_txdis:"TX deaktiviert",p_rxlos:"RX LOS",p_adv:"Angeboten", -pt_title:"Port-Konfiguration",pt_conn:"Verbunden",pt_speed:"Geschwindigkeit",pt_mtu:"MTU", +pt_title:"Port-Konfiguration",pt_conn:"Gelernte Geräte",pt_speed:"Geschwindigkeit",pt_mtu:"MTU", pt_sfp_note:"Die SFP-Geschwindigkeit wird pro Steckplatz gesetzt und nicht in der Startkonfiguration gespeichert.", pt_name_err:"Port-Name: 1-15 Zeichen, keine Leerzeichen",pt_mtu_err:"MTU muss zwischen 64 und 16383 liegen", stp_title:"Spanning Tree",stp_h:"RSTP, 802.1w",stp_version:"Version",stp_v_stp:"STP-kompatibel", @@ -623,6 +626,7 @@ stp_en_q:"Spanning Tree aktivieren?", stp_en_d:"Die Ports starten blockiert und brauchen bis zum doppelten Forward Delay, bis sie weiterleiten; Edge-Ports sind sofort wieder aktiv.", stp_dis_q:"Spanning Tree deaktivieren?",stp_dis_d:"Alle Ports leiten sofort weiter; der Schutz vor Netzwerkschleifen entfällt.", stp_cost_err:"Pfadkosten müssen zwischen 0 und 200000000 liegen", +nav_lldp:"LLDP",lldp_enabled:"LLDP aktiv",lldp_title:"Dienststatus",lldp_portname:"Name",lldp_enable:"Pakete senden", st_title:"Port-Statistik",st_h:"Summen seit dem Start",st_txg:"TX gut",st_txb:"TX fehlerhaft",st_rxg:"RX gut", st_rxb:"RX fehlerhaft",st_details:"Details",st_counters:"MIB-Zähler",st_nonzero:"nur ungleich null", st_autoref:"automatisch aktualisieren",st_counter:"Zähler",st_value:"Wert",st_fail:"Zähler konnten nicht geladen werden", @@ -645,8 +649,12 @@ l2_learned:"gelernt",l2_loading:"lädt...",l2_failed:"Laden fehlgeschlagen",l2_e l2_del_t:"Eintrag löschen",l2_flush_q:"Alle gelernten MAC-Einträge löschen?", m_title:"Port-Spiegelung",m_active:"aktiv",m_monitor:"Monitor-Port",m_mirror:"Spiegeln",m_both:"Beide", m_note:"Beide = RX und TX des Ports auf den Monitor-Port spiegeln.",m_none:"Mindestens einen zu spiegelnden Port wählen", +iso_title:"Port-Isolation",iso_from:"Von Port",iso_to:"Zu Port",iso_all:"Alle erlauben", +iso_intro:"Ein Paket, das über einen Port hereinkommt, darf den Switch nur über die Ports verlassen, die in seiner Zeile angehakt sind. Die Isolation wirkt vor der Weiterleitung: Ein nicht angehakter Port ist direkt nicht erreichbar, egal was in der MAC-Tabelle steht.", +iso_legend:"Das Feld des Ports selbst ist immer erlaubt. Eine rote Portnummer markiert einen Port, der nicht ganz offen ist.", lag_hash:"Hash:",lag_note:"Eine LAG braucht mindestens ein Mitglied, um in der Startkonfiguration gespeichert zu werden; eine leere Gruppe zu übernehmen löscht sie.", lag_clear_q:"LAG {n} auflösen?",lag_clear_d:"Alle Mitglieds-Ports kehren in den Normalbetrieb zurück.", +lacp_heading:"LACP (802.3ad)",lag_mode:"Modus",lag_static:"Statisch",lacp_neg:"wird ausgehandelt",lacp_agg:"Aggregator",lacp_members:"aktive Mitglieder",lacp_hint:"LACP: Ports auswählen und Übernehmen drücken, um die Aushandlung zu starten",lacp_actor:"Lokal",lacp_partner:"Partner",lacp_rxstate:"Empfangsstatus",lacp_rx:"Empfangene LACPDUs",lacp_psys:"Partner-System", e_title:"Energy Efficient Ethernet",e_adv:"Angeboten",e_lp:"Gegenstelle",e_active:"Aktiv",e_enable:"Aktivieren", e_note:"Angebotene und von der Gegenstelle unterstützte Stufen je Geschwindigkeit: 100M, 1G, 2.5G. SFP-Ports unterstützen kein EEE.", e_idle:"inaktiv",e_na:"k. A.", @@ -669,7 +677,8 @@ sy_ip_err:"Ungültige IP / Netzmaske / Gateway",sy_host_err:"Hostname: 1-23 druc sy_net_q:"Netzwerkeinstellungen übernehmen?",sy_net_d:"Die Management-IP ändert sich auf {ip}: Diese Seite muss dort neu geöffnet werden.", sy_ip_changed:"IP geändert, neu verbinden unter http://{ip}/",sy_dhcp_q:"Auf DHCP umstellen?", sy_dhcp_d:"Der Switch bezieht seine Adresse per DHCP. Du musst seine neue IP herausfinden, um dich wieder zu verbinden.", -sy_sysip_err:"Ungültige IP des Syslog-Servers",sy_sysport_err:"Syslog-Port muss zwischen 1 und 65535 liegen", +sy_sysip_err:"Ungültige IP des Syslog-Servers",sy_dns1:"DNS-Server",sy_dns2:"Zweiter DNS-Server",sy_dns_err:"Ungültige IP des DNS-Servers",sy_dns_dhcp:"von DHCP: {ip}",sy_sysport_err:"Syslog-Port muss zwischen 1 und 65535 liegen", +sy_time:"Uhrzeit",sy_ntp:"NTP",sy_ntpsrv:"NTP-Server",sy_ntpsrv_p:"Hostname oder IPv4-Adresse",sy_ntpint:"Abfrageintervall [min]",sy_tz:"Zeitzone",sy_dst:"Sommerzeit",sy_dst_eu:"Europa",sy_dst_us:"USA",sy_now:"Lokale Zeit",sy_sync:"Letzte Synchronisation",sy_ntpaddr:"Server-Adresse",sy_nosync:"nicht synchronisiert",sy_waiting:"warte auf den Server",sy_ago:"vor {n} min",sy_ntp_err:"Hostname oder IPv4-Adresse des NTP-Servers eingeben",sy_ntpint_err:"Abfrageintervall muss zwischen 1 und 1440 liegen",sy_time_note:"Der Switch hat keine batteriegepufferte Uhr: Die Zeit geht bei jedem Neustart verloren und wird neu vom NTP-Server bezogen, sobald das Netzwerk bereit ist. Im Flash speichern, damit die Einstellungen erhalten bleiben.", sy_pw_len:"Passwort: 1-20 Zeichen",sy_pw_space:"Das Passwort darf keine Leerzeichen enthalten",sy_pw_match:"Die Passwörter stimmen nicht überein", sy_pw_q:"Admin-Passwort ändern?",sy_pw_d:"Gilt sofort für neue Anmeldungen. Im Flash speichern, damit es erhalten bleibt.", sy_reboot_q:"Switch neu starten?",sy_reboot_d:"Es gibt UNGESPEICHERTE Änderungen, sie gehen verloren. Zuerst im Flash speichern, wenn du sie behalten willst.", @@ -808,7 +817,7 @@ var CONF_CMDS=[ /^port\s+\d{1,2}\s+lldp\s+(permit|block)+$/, /^eee\s+(on|off)(\s+\d{1,2})?(\s+(100m|1g|2g5))?$/, /^mirror(\s+\d{1,2})(\s+\d{1,2}[tr]?)+$/,/^mirror\s+off$/, - /^lag\s+[1-4](\s+\d{1,2})+$/,/^lag\s+[1-4]\s+d$/,/^laghash\s+[1-4](\s+\w+)+$/, + /^lag\s+[1-4](\s+\d{1,2})+$/,/^lag\s+[1-4]\s+d$/,/^lag\s+[1-4]\s+lacp(\s+\d{1,2})+$/,/^lag\s+[1-4]\s+lacp\s+off$/,/^laghash\s+[1-4](\s+\w+)+$/, /^isolate\s+\d{1,2}(\s+(off|\d{1,2}))+$/, /^stp\s+(on|off)$/,/^stp\s+(prio|hello|maxage|fwd|txhold)\s+\d{1,2}$/, /^stp\s+version\s+(rstp|stp)$/, @@ -955,6 +964,7 @@ function pollStatus(){ }); } var statusPoller=new Poller(pollStatus,2500); +statusPoller.start(); function needPorts(fn){ if(S.n)return fn(); pollStatus().then(fn).catch(function(){}); @@ -1099,8 +1109,7 @@ function dashStatus(){ }); } tabHooks.dash={ - enter:function(){statusPoller.start();pollInfo().catch(function(){})}, - leave:function(){statusPoller.stop()}, + enter:function(){pollInfo().catch(function(){})}, status:dashStatus, }; @@ -1144,31 +1153,12 @@ function loadMtu(){ }); }); } -/* One learned MAC is the attached device; several means a switch or AP - * sits behind the port, so only the count is shown. */ -function portsMacs(){ - l2Load().then(function(all){ - var by={}; - all.forEach(function(e){ - if(e.pport==="CPU")return; - var l=by[e.pport]=by[e.pport]||[]; - if(l.indexOf(e.mac)<0)l.push(e.mac); - }); - S.ports.forEach(function(p){ - var el=$("pmac"+(p.portNum-1)); - if(!el)return; - var m=by[p.portNum]||[]; - el.textContent=!m.length?"-":(m.length===1?m[0]:m.length+" "+t("c_devices")); - el.title=m.join("\n"); - }); - }).catch(function(){}); -} -var _macTick=0; function portsStatus(){ buildPorts(); - if(++_macTick%10===0)portsMacs(); S.ports.forEach(function(p){ var i=p.portNum-1,el=$("plink"+i); + var mc=$("pmac"+i); + if(mc)mc.textContent=parseInt(p.macs,16)&0x1fff; if(el)el.innerHTML=linkBadge(p); var sel=$("pspd"+i),v=p.isSFP?0:ADVSEL[parseInt(p.adv,2)]; if(sel&&v&&document.activeElement!==sel)sel.value=v; @@ -1196,8 +1186,7 @@ function applyPort(i){ postCmds(cmds).then(loadMtu).catch(function(){}); } tabHooks.ports={ - enter:function(){statusPoller.start();needPorts(function(){buildPorts();portsMacs()})}, - leave:function(){statusPoller.stop();l2Gen++}, + enter:function(){needPorts(buildPorts)}, status:portsStatus, }; @@ -1453,8 +1442,7 @@ function statsStatus(){ }); } tabHooks.stats={ - enter:function(){statusPoller.start()}, - leave:function(){statusPoller.stop();if(ctrPoll)ctrPoll.stop()}, + leave:function(){if(ctrPoll)ctrPoll.stop()}, status:statsStatus, }; @@ -1814,6 +1802,15 @@ function buildLag(){ for(var g=1;g<=4;g++)(function(g){ var card=h("div",{class:"card"}); card.appendChild(h("h2",{text:"LAG "+g})); + var mr=h("div",{style:"display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px",class:"small"}); + mr.appendChild(h("span",{class:"mut",text:t("lag_mode")})); + var ms=h("select",{class:"in",id:"lgm"+g}); + ms.appendChild(h("option",{value:"static",text:t("lag_static")})); + ms.appendChild(h("option",{value:"lacp",text:"LACP"})); + ms.addEventListener("change",function(){$("lgs"+g).textContent=ms.value==="lacp"?t("lacp_hint"):""}); + mr.appendChild(ms); + card.appendChild(mr); + card.appendChild(h("p",{class:"small mono",id:"lgs"+g,style:"margin-bottom:10px"})); var pr=h("div",{style:"display:flex;gap:10px;flex-wrap:wrap;margin-bottom:10px"}); for(var p=1;p<=S.n;p++)pr.appendChild(h("label",null,[ h("input",{type:"checkbox",id:"lg"+g+"p"+p}),document.createTextNode(" "+p+" "), @@ -1826,14 +1823,34 @@ function buildLag(){ }); card.appendChild(hr); card.appendChild(h("button",{class:"ctl pri",text:t("c_apply"),onclick:function(){lagApply(g)}})); + card.addEventListener("change",function(){card.dataset.dirty="1"}); w.appendChild(card); })(g); } +var lacpCfg=[0,0,0,0,0]; +function maskPorts(m){var r=[];for(var p=1;p<=S.n;p++)if((m>>S.physToLog[p-1])&1)r.push(p);return r.length?r.join(" "):"-"} function lagLoad(){ - return getJSON("/lag.json").then(function(s){ + return getJSON("/lacp.json").then(function(c){ + var tb=$("lacptbl").tBodies[0]; + tb.innerHTML=""; + c.lags.forEach(function(lg,i){ + var g=i+1; + lacpCfg[g]=parseInt(lg.cfg,16); + if($("lgm"+g).closest(".card").dataset.dirty)return; + $("lgm"+g).value=lacpCfg[g]?"lacp":"static"; + $("lgs"+g).textContent=lacpCfg[g]?"LACP: "+t("lacp_agg")+" "+(lg.aggValid?lg.agg:"("+t("lacp_neg")+")")+", "+t("lacp_members")+" "+maskPorts(parseInt(lg.members,16)):""; + }); + if(c.on)c.ports.forEach(function(p){ + if(p.lag===255)return; + var tr=tb.insertRow(); + [p.p,p.lag+1,p.a,p.pt,p.rs,parseInt(p.rx,16),p.psys].forEach(function(v){tr.insertCell().textContent=v}); + }); + return getJSON("/lag.json"); + }).then(function(s){ s.forEach(function(l){ var g=l.lagNum+1; - var members=parseInt(l.members,2); + if($("lgm"+g).closest(".card").dataset.dirty)return; + var members=lacpCfg[g]||parseInt(l.members,2); for(var p=1;p<=S.n;p++) $("lg"+g+"p"+p).checked=!!((members>>S.physToLog[p-1])&1); var hash=parseInt(l.hash,16); @@ -1842,21 +1859,25 @@ function lagLoad(){ }); } function lagApply(g){ - var cmd="lag "+g,n=0; + var lacp=$("lgm"+g).value==="lacp",cmd="lag "+g+(lacp?" lacp":""),n=0,pre=[]; + delete $("lgm"+g).closest(".card").dataset.dirty; for(var p=1;p<=S.n;p++)if($("lg"+g+"p"+p).checked){cmd+=" "+p;n++;} - if(!n){ + if(!lacp&&lacpCfg[g])pre.push("lag "+g+" lacp off"); + if(lacp&&!n)cmd="lag "+g+" lacp off"; + if(!n&&!lacp){ confirmModal(t("lag_clear_q",{n:g}),t("lag_clear_d"),function(){ - postCmd("lag "+g+" d").then(lagLoad).catch(function(){}); + postCmds(pre.concat(["lag "+g+" d"])).then(lagLoad).catch(function(){}); }); return; } var hcmd="laghash "+g,nh=0; HASHF.forEach(function(f){if($("lg"+g+"h"+f).checked){hcmd+=" "+f;nh++;}}); - var cmds=[cmd]; + var cmds=pre.concat([cmd]); if(nh)cmds.push(hcmd); postCmds(cmds).then(lagLoad).catch(function(){}); } -tabHooks.lag={enter:function(){needPorts(function(){buildLag();lagLoad().catch(function(){})})}}; +var lagPoller=new Poller(function(){return lagLoad().catch(function(){})},3000); +tabHooks.lag={enter:function(){needPorts(function(){buildLag();lagPoller.start()})},leave:function(){lagPoller.stop()}}; function lldpLoad(){ @@ -2245,6 +2266,7 @@ function mergeConf(base,texts){ else drop(/^eee /); conf.push(line);return; } + if((m=line.match(/^lag (\d) lacp off$/))){drop(new RegExp("^lag "+m[1]+" lacp( |$)"));return;} if(line==="mirror off"){drop(/^mirror /);return;} if(!isConfCmd(line))return; if((m=line.match(/^ingress (.+)$/))){ diff --git a/html/index.html b/html/index.html index f896dd13..f95c8219 100644 --- a/html/index.html +++ b/html/index.html @@ -55,11 +55,11 @@ a{color:var(--ac);text-decoration:none} #navfoot{padding:10px 16px;border-top:1px solid var(--bd);font-size:12px;color:var(--fg2)} #wrap{flex:1;min-width:0;display:flex;flex-direction:column} #top{ - display:flex;align-items:center;gap:10px;padding:10px 20px; + display:flex;align-items:center;flex-wrap:wrap;gap:10px;padding:8px 20px; background:var(--panel);border-bottom:1px solid var(--bd);position:sticky;top:0;z-index:5; } #burger{display:none;background:none;border:0;cursor:pointer;padding:4px} -#ttitle{font-size:16px;font-weight:650;flex:1} +#ttitle{font-size:16px;font-weight:650;min-width:120px} #dirty{ display:none;font-size:12px;font-weight:600;color:var(--warn); border:1px solid var(--warn);border-radius:20px;padding:2px 10px; @@ -112,19 +112,21 @@ label.row span.lb{width:110px;flex:none;color:var(--fg2);font-size:13px} } .switch input:checked+i{background:var(--ok)} .switch input:checked+i:before{transform:translateX(15px)} -#strip{display:flex;gap:8px;flex-wrap:wrap;padding:4px 0 2px} +#strip{display:flex;gap:6px;flex:1;min-width:0;overflow-x:auto;scrollbar-width:thin} +.port:first-child{margin-left:auto} +.port:last-child{margin-right:auto} .port{ - width:46px;border:2px solid var(--bd);border-radius:7px;padding:5px 0 3px; + width:40px;border:2px solid var(--bd);border-radius:7px;padding:3px 0 2px; text-align:center;cursor:pointer;background:var(--panel2);position:relative; } -.port.sfp{width:56px} -.port .pn{font-weight:650;font-size:13px} -.port .ps{font-size:10px;color:var(--fg2);display:block;line-height:1.2} +.port.sfp{width:50px} +.port .pn{font-weight:650;font-size:12px} +.port .ps{font-size:9px;color:var(--fg2);display:block;line-height:1.2} .port .jack{ - display:block;width:18px;height:12px;margin:3px auto 2px;border-radius:2px; - border:2px solid var(--fg2);border-top-width:5px;opacity:.55; + display:block;width:16px;height:10px;margin:2px auto 1px;border-radius:2px; + border:2px solid var(--fg2);border-top-width:4px;opacity:.55; } -.port.sfp .jack{width:28px;height:10px;border-top-width:3px} +.port.sfp .jack{width:24px;height:9px;border-top-width:3px} .port.up{border-color:var(--pc);background:color-mix(in srgb,var(--pc) 10%,var(--panel2))} .port.up .jack{border-color:var(--pc);opacity:1} .port.up .ps{color:var(--pc);font-weight:600} @@ -183,6 +185,10 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent} #ttitle{font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} #dirty{padding:2px 7px} } +@media (max-width:720px){ + #ttitle{flex:1} + #strip{order:3;flex-basis:100%} +}