test: build the LACP test on the real headers, drop the port_hash test

The LACP test now compiles with the shared harness flags and
sdcc_shim.h against the firmware headers, so the copies under
test/lacp/shim are gone. test_port_tables already covers the trunk hash
seed that test/port_hash checked against its own register copies.
lacp_in() declares its locals at the top, which the stricter host build
needs.
This commit is contained in:
d00f committed 2026-10-12 22:02:56 +02:00
1 parent 1bfe632174
commit 4a14f50932
14 files changed
+12 -243

No files matched your search

+6 -10
View File
@@ -28,7 +28,8 @@ TESTS = $(BUILDDIR)/test_cmd_editor \
$(BUILDDIR)/test_port_tables \
$(BUILDDIR)/test_page_json \
$(BUILDDIR)/test_httpd_tx \
$(BUILDDIR)/test_tick_gate
$(BUILDDIR)/test_tick_gate \
$(BUILDDIR)/test_lacp
# The table tests link the register mock and one environment file; stub/
# stands in for the two headers a firmware build generates.
@@ -54,29 +55,24 @@ $(BUILDDIR)/test_tick_gate: test_tick_gate.c support.c $(SRCROOT)/cmd_editor.c |
$(BUILDDIR)/test_page_json: test_page_json.c $(TABLE_ENV) hw_mock.h | $(BUILDDIR)
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
# rtl837x_lacp.c is compiled UNMODIFIED from the firmware tree.
$(BUILDDIR)/test_lacp: test_lacp.c $(SRCROOT)/rtl837x_lacp.c | $(BUILDDIR)
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
# httpd/httpd.c and uip/uip.c are compiled UNMODIFIED from the firmware tree;
# this test carries the environment below them itself.
$(BUILDDIR)/test_httpd_tx: test_httpd_tx.c $(SRCROOT)/httpd/httpd.c $(SRCROOT)/uip/uip.c | $(BUILDDIR)
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
# Sandboxes with a Makefile of their own; each fails the run when it fails.
SUBTESTS = lacp port_hash
run: $(TESTS)
@fail=0; for t in $(TESTS); do \
echo "=== $$t ==="; \
$$t || fail=1; \
echo; \
done; \
for d in $(SUBTESTS); do \
echo "=== $$d ==="; \
$(MAKE) -C $$d test || fail=1; \
echo; \
done; \
if [ $$fail -ne 0 ]; then echo "TESTS FAILED"; exit 1; else echo "ALL TESTS PASSED"; fi
clean:
rm -rf $(BUILDDIR)
@for d in $(SUBTESTS); do $(MAKE) -C $$d clean; done
.PHONY: all run clean
+1 -2
View File
@@ -48,8 +48,7 @@ fires — so it drops straight into CI.
| `test_port_tables` | `rtl837x_port.c` | VLAN entry layout and round trip, PVID register sharing, static multicast and management entries, per-port flush, trunk membership and hash seed |
| `test_page_json` | `httpd/page_impl.c` + `rtl837x_port.c` | `/vlan.json`, `/vlanlist`, `/l2.json` (walk, wrap marker, paging inside `outbuf`), 64-bit counters in `/status.json` and `/counters.json` |
| `test_httpd_tx` | `httpd/httpd.c` + `uip/uip.c` | a GET of a static file against a client that moves its receive window: ACK accounting, continuation chunks out of flash, retransmission |
| `lacp/` | `rtl837x_lacp.c` | state machines against a simulated 802.3ad partner: convergence, mis-cabling, expiry, re-election, two groups, LACPDU containment entries |
| `port_hash/` | `port_lag_members_set()` | a LAG seeds its own hash register |
| `test_lacp` | `rtl837x_lacp.c` | state machines against a simulated 802.3ad partner: convergence, mis-cabling, expiry, re-election, two groups, delivery by trap |
## Adding a test for another module
1. Write `test_<module>.c` with `main()` driving the module's entry points and
-1
View File
@@ -1 +0,0 @@
build/
-31
View File
@@ -1,31 +0,0 @@
# Host-side sandbox for the firmware LACP state machines.
#
# Compiles the UNMODIFIED ../../rtl837x_lacp.c against shim headers: SDCC
# storage-class keywords are blanked via -D, and the module copy lives in
# build/ so quote-includes resolve to shim/ (its own directory has no real
# platform headers) instead of the firmware tree. rtl837x_trap.h is copied
# alongside it for the same reason: TRAP_RX_BODY() is what delivery by trap
# rests on, so the test must use the real macro, not a shim restating it.
CC ?= cc
CFLAGS = -std=c11 -Wall -Wextra -Wno-unknown-pragmas \
-D__xdata= -D__code= -D__banked= -D__reentrant= \
-Ishim -I../..
all: test
test: build/lacp_sim
./build/lacp_sim
verbose: build/lacp_sim
./build/lacp_sim -v
build/lacp_sim: lacp_sim.c ../../rtl837x_lacp.c ../../rtl837x_lacp.h ../../rtl837x_trap.h shim/*.h
mkdir -p build
cp ../../rtl837x_lacp.c build/lacp_under_test.c
cp ../../rtl837x_trap.h build/rtl837x_trap.h
$(CC) $(CFLAGS) -o $@ lacp_sim.c build/lacp_under_test.c
clean:
rm -rf build
.PHONY: all test verbose clean
-12
View File
@@ -1,12 +0,0 @@
/* Host-build shim: rtl837x_lacp.c reads min_port/max_port and, for the
* console dump, the front-panel numbering. The real map is not the identity
* on any machine, so the harness uses a shuffled one to keep a logical index
* from passing as a physical port by accident. */
#ifndef _SHIM_MACHINE_H_
#define _SHIM_MACHINE_H_
#include <stdint.h>
struct machine { uint8_t min_port; uint8_t max_port; uint8_t log_to_phys_port[9]; };
extern const struct machine machine;
struct machine_runtime { uint8_t isRTL8373; };
extern struct machine_runtime machine_detected;
#endif
-63
View File
@@ -1,63 +0,0 @@
/*
* Host-build shim for rtl837x_common.h - just enough for rtl837x_lacp.c.
* Layouts of rtl_tag/vlan_tag and the frame-desc size mirror the real header;
* the harness static-asserts the resulting on-wire struct sizes.
*/
#ifndef _SHIM_RTL837X_COMMON_H_
#define _SHIM_RTL837X_COMMON_H_
#include <stdint.h>
#include <string.h> /* memcpy/memset - firmware provides its own */
struct rtl_tag {
uint16_t tag;
uint8_t version;
uint8_t reason;
uint16_t flags;
uint16_t pmask; /* TX: port bitmask; RX: 4-bit port number */
};
struct vlan_tag {
uint16_t svlan;
uint16_t vlan;
};
#define RTL_TAG_SIZE (sizeof (struct rtl_tag))
#define VLAN_TAG_SIZE (sizeof (struct vlan_tag))
#define RTL_FRAME_TAG_ID 0x8899
#define RTL_FRAME_TAG_VERSION 0x04
#define RTL_FRAME_DESC_SIZE 12
#define ETHER_HEADER_SIZE 14
#define HTONS(n) ((uint16_t)((((uint16_t)(n)) << 8) | (((uint16_t)(n)) >> 8)))
/* Console output - provided by the harness */
void print_string(char *s);
void print_byte(uint8_t b);
void print_short(uint16_t v);
void write_char(char c);
#endif
/* Host-build shim: port masks used by lacp_isolation_update() */
#ifndef PMASK_CPU
#define CPU_PORT 9
#define PMASK_9 0x1ff
#define PMASK_6 0x1f8
#define PMASK_CPU 0x200
#endif
/* Host-build shim: directed-egress/strip-tag bit (bit15 of TX pmask word) */
#ifndef RTL_TAG_ALLOW
#define RTL_TAG_ALLOW 0x8000
#endif
/* Host-build shim: tag flags word bits (tag_rtl8_4) */
#ifndef RTL_TAG_LEARN_DIS
#define RTL_TAG_LEARN_DIS 0x0020
#define RTL_TAG_KEEP 0x0080
#define SYS_TICK_HZ 200
extern volatile uint32_t ticks;
#define TICKS_DUE(last, period) ((uint8_t)((uint8_t)ticks - (last)) >= (period))
#endif
-7
View File
@@ -1,7 +0,0 @@
/* Host-build shim: the harness mocks trunk programming and records calls */
#ifndef _SHIM_RTL837X_PORT_H_
#define _SHIM_RTL837X_PORT_H_
#include <stdint.h>
void port_lag_members_set(uint8_t lag, uint16_t members);
void port_isolate(uint8_t port, uint16_t pmask);
#endif
-19
View File
@@ -1,19 +0,0 @@
/*
* Host-build shim for rtl837x_regs.h - the register numbers rtl837x_lacp.c
* touches, with the values from the real header so a wrong constant shows up
* as a failing expectation rather than as a silent no-op.
*/
#ifndef _SHIM_RTL837X_REGS_H_
#define _SHIM_RTL837X_REGS_H_
#include <stdint.h>
#define RTL837X_RMA2_CONF 0x4ed4
#define RTL837X_RMA_ACT_TRAP 0x10
#define RTL837X_RMA_ACT_DROP 0x20
/* Registers touched by lacp_send's CPU-port targeting */
#define RTL837X_PORT_ISOLATION_BASE 0x50c0
#define RTL837X_REG_NIC_TXCMD 0x7850
#endif
-9
View File
@@ -1,9 +0,0 @@
/* Host-build shim for uip.h - frame buffer + TX hook used by rtl837x_lacp.c */
#ifndef _SHIM_UIP_H_
#define _SHIM_UIP_H_
#include <stdint.h>
#define UIP_CONF_BUFFER_SIZE 600
struct uip_eth_addr { uint8_t addr[6]; };
extern uint16_t uip_len;
void tcpip_output(void);
#endif
-2
View File
@@ -1,2 +0,0 @@
test_lag_hash
port_lag_members_set.inc
-6
View File
@@ -1,6 +0,0 @@
test: port_lag_members_set.inc
gcc -Wall -Wextra -O1 -o test_lag_hash test_lag_hash.c && ./test_lag_hash
port_lag_members_set.inc: ../../rtl837x_port.c
awk '/^void port_lag_members_set/,/^}/' $< > $@
clean:
rm -f test_lag_hash port_lag_members_set.inc
-68
View File
@@ -1,68 +0,0 @@
/* Host test for port_lag_members_set(): the default load-balancing hash must be
* seeded into the CURRENT trunk's register (BASE + lag*4), never trunk 0's, and
* must not overwrite a hash that is already set. Compiles the REAL function
* (extracted verbatim from rtl837x_port.c) against register-recording shims. */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define __banked
#define __xdata
#define __code
/* register defs (mirror rtl837x_regs.h) */
#define RTL837X_TRK_MBR_CTRL_BASE 0x4f38
#define RTL837X_TRK_HASH_CTRL_BASE 0x4f48
#define LAG_HASH_SOURCE_PORT_NUMBER 0x01
#define LAG_HASH_L2_SMAC 0x02
#define LAG_HASH_L2_DMAC 0x04
#define LAG_HASH_L3_SIP 0x08
#define LAG_HASH_L3_DIP 0x10
#define LAG_HASH_L4_SPORT 0x20
#define LAG_HASH_L4_DPORT 0x40
#define LAG_HASH_DEFAULT (LAG_HASH_L2_SMAC|LAG_HASH_L2_DMAC|LAG_HASH_L3_SIP|LAG_HASH_L3_DIP|LAG_HASH_L4_SPORT|LAG_HASH_L4_DPORT)
#define LAG_HASH_RESET (LAG_HASH_SOURCE_PORT_NUMBER|LAG_HASH_L2_SMAC|LAG_HASH_L2_DMAC|LAG_HASH_L3_SIP|LAG_HASH_L3_DIP|LAG_HASH_L4_SPORT)
uint8_t SFR_DATA_24, SFR_DATA_16, SFR_DATA_8, SFR_DATA_0;
uint8_t sfr_data[4];
static uint32_t reg_store[0x10000];
void reg_read_m(uint16_t r){ uint32_t v=reg_store[r];
sfr_data[0]=(v>>24)&0xff; sfr_data[1]=(v>>16)&0xff; sfr_data[2]=(v>>8)&0xff; sfr_data[3]=v&0xff; }
void reg_write(uint16_t r){ reg_store[r]=((uint32_t)SFR_DATA_24<<24)|((uint32_t)SFR_DATA_16<<16)|((uint32_t)SFR_DATA_8<<8)|SFR_DATA_0; }
void print_string(char*s){(void)s;} void print_byte(uint8_t b){(void)b;}
void print_short(uint16_t s){(void)s;} void write_char(char c){(void)c;}
#define REG_SET(r,v) do{ SFR_DATA_24=((uint32_t)(v)>>24)&0xff; SFR_DATA_16=((uint32_t)(v)>>16)&0xff; \
SFR_DATA_8=((uint32_t)(v)>>8)&0xff; SFR_DATA_0=(v)&0xff; reg_write(r); }while(0)
#define REG_WRITE(r,a,b,c,d) do{ SFR_DATA_24=(a); SFR_DATA_16=(b); SFR_DATA_8=(c); SFR_DATA_0=(d); reg_write(r); }while(0)
/* THE REAL FUNCTION (extracted from rtl837x_port.c at build time) */
#include "port_lag_members_set.inc"
static int fails;
#define CK(cond,msg,...) do{ if(cond){printf("PASS " msg "\n",##__VA_ARGS__);} else {printf("FAIL " msg "\n",##__VA_ARGS__); fails++;} }while(0)
int main(void){
for(int lag=0; lag<4; lag++){
memset(reg_store,0,sizeof(reg_store));
port_lag_members_set(lag, 0x0180);
uint16_t h = RTL837X_TRK_HASH_CTRL_BASE + (lag<<2);
uint16_t m = RTL837X_TRK_MBR_CTRL_BASE + (lag<<2);
CK(reg_store[h]==LAG_HASH_DEFAULT, "lag%d: default 0x%02x -> hash reg 0x%04x", lag, LAG_HASH_DEFAULT, h);
CK(reg_store[m]==0x0180, "lag%d: members 0x0180 -> mbr reg 0x%04x", lag, m);
if(lag) CK(reg_store[RTL837X_TRK_HASH_CTRL_BASE]==0, "lag%d: trunk-0 hash NOT clobbered", lag);
}
/* guard: existing hash must survive a later member change */
memset(reg_store,0,sizeof(reg_store));
reg_store[RTL837X_TRK_HASH_CTRL_BASE+(1<<2)] = 0x06; /* lag1 already L2 */
port_lag_members_set(1, 0x00c0);
CK(reg_store[RTL837X_TRK_HASH_CTRL_BASE+(1<<2)]==0x06, "guard: preset lag1 hash 0x06 preserved");
/* the chip's reset value counts as unset and is replaced by the default */
memset(reg_store,0,sizeof(reg_store));
reg_store[RTL837X_TRK_HASH_CTRL_BASE+(2<<2)] = LAG_HASH_RESET;
port_lag_members_set(2, 0x0003);
CK(reg_store[RTL837X_TRK_HASH_CTRL_BASE+(2<<2)]==LAG_HASH_DEFAULT, "reset value 0x%02x replaced by default on lag2", LAG_HASH_RESET);
printf(fails? "\n=== FAIL (%d) ===\n" : "\n=== ALL PASS ===\n", fails);
return fails?1:0;
}
+1 -11
View File
@@ -1,13 +1,3 @@
/*
* Host-side sandbox for the RTL837x LACP implementation.
*
* Compiles the UNMODIFIED rtl837x_lacp.c against shim headers (see shim/) and
* drives it with synthetic LACPDUs from a simulated partner switch/bond. This
* exercises the real state machines that ship in the firmware image - only
* the platform below them (frame I/O, trunk registers, console) is mocked.
*
* Run: make -C test/lacp (exit code 0 = all scenarios pass)
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
@@ -31,7 +21,7 @@ uint8_t lacpEnabled;
uint16_t management_vlan; /* mocked; slow-protocol path zeroes it per-frame */
static int verbose = 0;
void print_string(char *s) { if (verbose) fputs(s, stdout); }
void print_string(const char *s) { if (verbose) fputs(s, stdout); }
void print_byte(uint8_t b) { if (verbose) printf("%02x", b); }
void print_short(uint16_t v) { if (verbose) printf("%04x", v); }
void write_char(char c) { if (verbose) putchar(c); }