Firefox filled a saved login into the System tab's password fields and
its user name into the NTP poll interval, the input before them. That
input event marked the Time card as edited, so ntpLoad() left NTP off,
the server empty and the time zone at UTC-12:00.
The strip no longer wraps. Ports shrink to fit the row and scroll
when they cannot, so the header on a phone stays at two rows. The
strip moves under the title only below 720 px, where it no longer
fits beside it. Drop the unused d_ports strings and the strip title.
The row of port icons lived in a card on the Dashboard, so link
state and speed were out of sight on every other tab. Move it into the
header between the title and the save button, a little smaller, and
poll /status.json whenever the page is open instead of only on the
Dashboard, Ports and Statistics tabs; the existing idle and hidden-tab
gating still pauses it. On narrow screens the strip wraps to its own
row under the title.
The column counts the addresses the switch learns from incoming frames,
so "Connected" suggested a connection it does not show. The translations
follow the words the L2 tab already uses for learned entries.
Save to flash merges the running log into the startup configuration.
Neither its toggle nor its overwrite rules knew "lldp on|off", so every
switch of LLDP added another line: four switches left four lines.
"port <n> lldp permit|block" fell under the rule for "port <n> <speed>",
so setting a port's speed dropped its LLDP setting from the saved
configuration, and the other way round.
"lldp on|off" is now a toggle, and a per-port LLDP setting replaces only
an earlier per-port LLDP setting of that port.
The button in the header was always drawn as the primary action, on
every page, so it competed with each page's own buttons, for example
the upload button on the Firmware page. It is now a plain button and
turns primary together with the "unsaved changes" badge.
The port tooltip and the port details showed "TX good / bad: 8794 / 0
pkts", which reads as 8794 bad packets. Each counter now has its own
line, labelled as on the Statistics page, and the two strings only that
line used are removed from every language.
"table.t th" sets text-align:left and is more specific than ".num", so
the headers of the counter columns on the dashboard and the statistics
page stayed left-aligned above right-aligned values.
The column listed the MAC addresses of the L2 table entries of a port, which cost a chain of paged /l2.json requests every tenth status poll. The status JSON carries the count now, so the column reads it from there and the page does not touch the L2 table at all.
The register counts the dynamic entries, so the static ones the list used to include are not in the number.
lacp_in() always leaves uip_len at 0, so the tcpip_output() after it
never ran. The LAG page names the active members by front-panel port
instead of a logical mask. The partner key is not part of selection;
say so under Known limits.
Dynamic link aggregation on top of the static LAGG, for RTL8372/8373:
receive, selection and mux state machines (coupled mux, one aggregator
per group), with "lacp show" to look inside. Each of the four trunk
groups runs its own aggregator on the candidate ports assigned with
"lag <n> lacp <ports>"; the engine starts with the first such group and
stops with the last.
LACPDUs reach the CPU through the reserved-multicast trap, so delivery
needs no L2 entry and nothing written per VLAN or per PVID. The trap
acts on the address before the VLAN lookup and before the ingress
filters, so a LACPDU also arrives on a port that admits tagged frames
only and on a port STP holds in blocking, neither of which a forwarded
one reaches. A trapped frame carries no VLAN tag,
so lacp_in() takes the offset of the PDU body from TRAP_RX_BODY(). The
action is set with trap_rma_set(), which leaves the flags sharing that
register alone, and "lacp off" puts the slow-protocols drop default
back. doc/lacp.md and doc/link_aggregation.md record what was measured,
including why the trap looked like a dead end at first.
The web UI gets a Static/LACP mode per group on the LAG page with live
status, and the startup-config validator knows the per-group syntax. A
host-side sandbox for the state machines runs in the test harness
together with the LAG hash check. It drives both forms of an incoming
LACPDU, so the body offset of a trapped one is covered as well.
The L2 table page iterated with the "next unicast" read method, so
static multicast entries such as an IGMP group were invisible. It now
iterates with "next address", skips L3 entries (their layout carries IP
addresses where a MAC is expected), and reports the lowest member of a
multicast entry's port mask, so such an entry shows up as a static
entry on that port.
A port taken out of LACP forgets its partner, so "lacp show" after
"lacp off" no longer reports one. Applying the same candidate set to a
group again, as the LAG page does on every Apply, leaves the trunk
alone instead of tearing it down for a second or two. lacp_in() checks
the frame length and ethertype before reading a LACPDU, so a runt or a
foreign frame on the slow-protocols address cannot leave stale buffer
bytes as a partner. The sandbox covers these three in T20-T22. On the
LAG page, LACP mode with no ports checked sends "lag N lacp off", and
the startup-config validator wants at least one port after "lacp".
Needed to increase buffer size for this to send app.js
The logical port status is what is returned in the array, for
non-sequential systems we need to map through physToLog rather
than just subtracting 1
physToLog is 1 based! not 0; also fixing up typecasts
Reimplementing using an array of objects to represent ports.
The previous approach of a bitmask of logical ports, was just too
simple on devices such as the SWGT024_V2_0_MANAGED which has
gaps in the port assignments.
timing with ticks
Fixing up the log_to_phys_port assignment
2000 is about every 10 seconds, so scaling up to once every 30ish
Removing the attempt to block lldp frames,
This does not work however the hard work has been done for us in
the #514 so we can borrow that work later on
Moving the global on/off onto the LLDP page
Building a table of LLDP status from the S ports. Later on, if
we wish to implement an lldp receiver we can display the remote
details here
Adding support to the cmd parser for the lldp commands
A matrix of the ports, one row per ingress port, showing which ports a
frame entering there may leave through. The port number of a row turns
red when the port is not fully open, and the cell for the port itself is
marked since it is always allowed. Apply sends one "isolate" command per
changed row, and Allow all ticks the whole matrix.
The switch side is a new /isolation.json, which reports each port's
allowance mask read back from the hardware. The page is an Isolation
section of the single-page UI.
With several switches open, every tab was called "Switch". The
dashboard tab now shows the hostname, and the login page shows the
hostname seen at the last login on that address (kept in localStorage,
which is per switch), or the address itself before the first login.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The firmware page accepted any valid image, also one built for a
different board whose SFP, LED and button pins differ. Every image
carries its machine name as a NUL-terminated string, the same one the
switch reports as hw_ver; when the selected image lacks it, the page
now warns below the check result and in the confirmation dialog. The
upload stays possible on purpose.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds a German dictionary to LANG in app.js (all 317 keys, placeholders
unchanged), the language selector entry in index.html and the login
strings in login.html. Uses Swiss spelling (ss instead of ß), which
reads correctly for all German speakers.
Checked against a mock of the httpd endpoints: every section renders
with the German strings; no layout changes compared to English.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The switch has no battery backed clock, only a seconds counter that starts
at zero on every boot. An SNTP client keeps UTC as the time of the last
answer plus the seconds counted since: "ntp server <name|ip>", "ntp interval
<minutes>", "ntp timezone <+hh:mm>", "ntp dst off|eu|us", "ntp on|off",
"ntp" and "time". A server given by name goes through the DNS resolver, an
answer from an unsynchronised server is ignored, and a failed attempt is
repeated after 30 seconds.
The local time adds the time zone offset and, while the European or United
States rule says so, one hour. The date is split with a shift and subtract
division and a walk over the years, so no 32-bit division from the library
ends up in the common area.
The System page gets the NTP settings and shows the local time.