mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
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:
1 parent
9bd301447b
commit
7e90f6a126
14 files changed
+12
-243
No files matched your search
+4
-2
@@ -270,6 +270,8 @@ void lacp_send(uint8_t port) __banked
|
||||
*/
|
||||
void lacp_in(void) __banked
|
||||
{
|
||||
__xdata uint8_t port, lag;
|
||||
|
||||
lacp_rxbody = TRAP_RX_BODY();
|
||||
if (uip_len < lacp_rxbody + sizeof(struct lacpdu_in)) {
|
||||
uip_len = 0;
|
||||
@@ -284,12 +286,12 @@ void lacp_in(void) __banked
|
||||
/* Per rtl837x_common.h, pmask carries a 4-bit port number on RX
|
||||
* (hardware-verified on RTL8373: per-port rx counters track the actual
|
||||
* ingress port through full LACP convergence). */
|
||||
__xdata uint8_t port = ((uint8_t)HTONS(LACP_H->rtl_tag.pmask)) & 0x0f;
|
||||
port = ((uint8_t)HTONS(LACP_H->rtl_tag.pmask)) & 0x0f;
|
||||
if (port < machine.min_port || port > machine.max_port)
|
||||
return;
|
||||
|
||||
/* Only ports assigned to a LACP-mode LAG participate in the protocol. */
|
||||
__xdata uint8_t lag = lacp_port_lag[port];
|
||||
lag = lacp_port_lag[port];
|
||||
if (lag == LACP_LAG_NONE)
|
||||
return;
|
||||
if (lacp_sys_eq(LACP_I->actor.sys, uip_ethaddr.addr))
|
||||
|
||||
+6
-10
@@ -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
@@ -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 +0,0 @@
|
||||
build/
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1,2 +0,0 @@
|
||||
test_lag_hash
|
||||
port_lag_members_set.inc
|
||||
@@ -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
|
||||
@@ -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,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); }
|
||||
Reference in new issue
Block a user