Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/workflows/stm32h563-m33mu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -449,3 +449,49 @@ jobs:
if [ -f /tmp/tcpdump.pid ]; then
sudo kill "$(cat /tmp/tcpdump.pid)" 2>/dev/null || true
fi

stm32h563_m33mu_vlan:
runs-on: ubuntu-latest
timeout-minutes: 20
container:
image: ghcr.io/wolfssl/wolfboot-ci-m33mu:v1.2
options: --privileged

steps:
- uses: actions/checkout@v4

- name: Install host tools
run: |
set -euo pipefail
apt-get update
# iproute2: 'ip' command (tap, vlan link-add)
# tcpdump: packet capture on tap0
# tshark: filter/parse the pcap for VID + direction assertions
# sudo: the integration script wraps privileged ops with sudo
apt-get install -y sudo iproute2 tcpdump tshark
Comment thread
danielinux marked this conversation as resolved.

- name: Run VLAN integration test (TCP echo over 802.1Q)
timeout-minutes: 15
env:
VLAN_VID: "100"
VLAN_PCP: "0"
M33MU_TIMEOUT: "60"
run: |
set -euo pipefail
# The script builds the firmware with ENABLE_VLAN=1, sets up tap0
# + tap0.${VLAN_VID}, boots m33mu, probes the TCP echo service on
# port 7 over the VLAN, and asserts via tshark that 802.1Q frames
# flowed in both directions on VID=${VLAN_VID}.
bash tools/scripts/debug-m33mu-vlan-local.sh

- name: Upload VLAN artifacts on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: vlan-debug-artifacts
path: |
/tmp/m33mu-vlan.log
/tmp/m33mu-vlan.pcap
/tmp/m33mu-vlan-tshark.txt
/tmp/m33mu-vlan-echo.txt
if-no-files-found: ignore
43 changes: 41 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,8 @@ UNIT_TEST_SRCS:=src/test/unit/unit.c \
src/test/unit/unit_tests_dhcp_edges.c \
src/test/unit/unit_tests_ip_arp_recv.c \
src/test/unit/unit_tests_dns_edges.c \
src/test/unit/unit_tests_misc_edges.c
src/test/unit/unit_tests_misc_edges.c \
src/test/unit/unit_tests_vlan.c

unit: build/test/unit

Expand All @@ -461,6 +462,9 @@ build/test/unit: $(UNIT_TEST_SRCS)
unit-multicast: CFLAGS+=-DIP_MULTICAST
unit-multicast: clean-unit unit

unit-vlan: CFLAGS+=-DWOLFIP_VLAN=1 -DWOLFIP_MAX_INTERFACES=6
unit-vlan: clean-unit unit

ESP_UNIT_CHECK_CFLAGS := $(CHECK_PKG_CFLAGS)
ifeq ($(UNAME_S),Darwin)
ifneq ($(CHECK_PREFIX),)
Expand Down Expand Up @@ -523,6 +527,8 @@ COV_UNIT:=$(COV_DIR)/unit
COV_UNIT_O:=$(COV_DIR)/unit.o
COV_MCAST_UNIT:=$(COV_DIR)/unit-multicast
COV_MCAST_UNIT_O:=$(COV_DIR)/unit-multicast.o
COV_VLAN_UNIT:=$(COV_DIR)/unit-vlan
COV_VLAN_UNIT_O:=$(COV_DIR)/unit-vlan.o

$(COV_UNIT_O): $(UNIT_TEST_SRCS)
@mkdir -p $(COV_DIR)
Expand Down Expand Up @@ -594,6 +600,39 @@ cov-multicast: unit-multicast $(COV_MCAST_UNIT)
--html-details -o build/coverage/multicast.html
@$(OPEN_CMD) build/coverage/multicast.html

$(COV_VLAN_UNIT_O): $(UNIT_TEST_SRCS)
@mkdir -p $(COV_DIR)
@echo "[CC] unit.c (vlan coverage)"
@$(CC) $(UNIT_CFLAGS) $(CFLAGS) -DWOLFIP_VLAN=1 -DWOLFIP_MAX_INTERFACES=6 --coverage -c src/test/unit/unit.c -o $(COV_VLAN_UNIT_O)

$(COV_VLAN_UNIT): LDFLAGS+=--coverage $(UNIT_LIBS)
$(COV_VLAN_UNIT): $(COV_VLAN_UNIT_O)
@echo "[LD] $@"
@$(CC) $(COV_VLAN_UNIT_O) -o $(COV_VLAN_UNIT) $(UNIT_LDFLAGS) $(LDFLAGS)

cov-vlan: unit-vlan $(COV_VLAN_UNIT)
@echo "[RUN] unit vlan (coverage)"
@rm -f $(COV_DIR)/*.gcda
@$(COV_VLAN_UNIT)
@echo "[COV] gcovr vlan html"
@mkdir -p build/coverage
@gcovr -r . --exclude "src/test/unit/.*" \
--gcov-ignore-errors=no_working_dir_found \
--merge-mode-functions=merge-use-line-min \
--html-details -o build/coverage/vlan.html
@$(OPEN_CMD) build/coverage/vlan.html

autocov-vlan: unit-vlan $(COV_VLAN_UNIT)
@echo "[RUN] unit vlan (coverage)"
@rm -f $(COV_DIR)/*.gcda
@$(COV_VLAN_UNIT)
@echo "[COV] gcovr vlan html"
@mkdir -p build/coverage
@gcovr -r . --exclude "src/test/unit/.*" \
--gcov-ignore-errors=no_working_dir_found \
--merge-mode-functions=merge-use-line-min \
--html-details -o build/coverage/vlan.html

# Install dynamic library to re-link linux applications
#
install:
Expand Down Expand Up @@ -692,7 +731,7 @@ build/test/test-wolfguard-interop: src/test/test_wolfguard_interop.c src/port/po
clean-test-wolfguard-interop:
@rm -f build/test/test-wolfguard-interop build/test/test_wolfguard_interop.o build/test/linux_tun.o

.PHONY: clean all static cppcheck cov autocov autocov-multicast cov-multicast unit-multicast unit-asan unit-ubsan unit-leaksan clean-unit \
.PHONY: clean all static cppcheck cov autocov autocov-multicast cov-multicast unit-multicast unit-vlan cov-vlan autocov-vlan unit-asan unit-ubsan unit-leaksan clean-unit \
unit-esp-asan unit-esp-ubsan unit-esp-leaksan clean-unit-esp \
unit-wolfguard unit-wolfguard-asan unit-wolfguard-ubsan clean-unit-wolfguard \
test-wolfguard-loopback test-wolfguard-loopback-asan test-wolfguard-loopback-ubsan \
Expand Down
23 changes: 23 additions & 0 deletions config.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,29 @@
#error "WOLFIP_ENABLE_LOOPBACK requires WOLFIP_MAX_INTERFACES > 1"
#endif

/* 802.1Q VLAN support. Off by default; when off, all VLAN code is removed
* by the preprocessor and behavior/ABI of the stack is unchanged.
*
* WOLFIP_VLAN_MAX is a hard cap on the number of *simultaneously live*
* VLAN sub-interfaces. The capacity must fit alongside the physical
* interface and, when loopback is enabled, also the loopback slot. */
#ifndef WOLFIP_VLAN
#define WOLFIP_VLAN 0
#endif
#ifndef WOLFIP_VLAN_MAX
#define WOLFIP_VLAN_MAX 4
#endif
#if WOLFIP_VLAN
#if WOLFIP_ENABLE_LOOPBACK
#define WOLFIP_VLAN_RESERVED_SLOTS 2 /* loopback + 1 physical */
#else
#define WOLFIP_VLAN_RESERVED_SLOTS 1 /* 1 physical */
#endif
#if (WOLFIP_MAX_INTERFACES < (WOLFIP_VLAN_RESERVED_SLOTS + WOLFIP_VLAN_MAX))
#error "WOLFIP_VLAN requires WOLFIP_MAX_INTERFACES >= 1 (physical) + (WOLFIP_ENABLE_LOOPBACK ? 1 : 0) + WOLFIP_VLAN_MAX"
#endif
#endif

/* Linux test configuration */
#define WOLFIP_IP "10.10.10.2"
#define HOST_STACK_IP "10.10.10.1"
Expand Down
24 changes: 24 additions & 0 deletions src/port/stm32h563/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ ENABLE_MQTT_BROKER ?= 0
# wolfBoot update partition. TZEN=0 only.
ENABLE_TFTP ?= 0

# 802.1Q VLAN sub-interface support. Set ENABLE_VLAN=1 to enable
# WOLFIP_VLAN at compile time and run all DHCP/TFTP/etc. traffic over
# a VLAN sub-interface with VID = VLAN_VID. Static IP configuration on
# the sub-interface is selected via VLAN_IP / VLAN_MASK / VLAN_GW; the
# physical interface stays untagged with no IP.
ENABLE_VLAN ?= 0
VLAN_VID ?= 100
VLAN_PCP ?= 0
VLAN_IP ?= 10.10.100.2
VLAN_MASK ?= 255.255.255.0
VLAN_GW ?= 10.10.100.1

# FreeRTOS integration: set FREERTOS=1 to run the HTTPS server from a
# FreeRTOS task using the blocking BSD socket wrapper layer.
FREERTOS ?= 0
Expand Down Expand Up @@ -360,6 +372,18 @@ SRCS += $(ROOT)/src/tftp/wolftftp.c

endif # ENABLE_TFTP

# -----------------------------------------------------------------------------
# 802.1Q VLAN
# -----------------------------------------------------------------------------
ifeq ($(ENABLE_VLAN),1)
CFLAGS += -DENABLE_VLAN -DWOLFIP_VLAN=1
# Need room for 1 loopback + 1 physical + at least 1 VLAN sub-iface.
# wolfIP default WOLFIP_MAX_INTERFACES is 2; bump to 6 to leave headroom.
CFLAGS += -DWOLFIP_MAX_INTERFACES=6
CFLAGS += -DVLAN_VID=$(VLAN_VID) -DVLAN_PCP=$(VLAN_PCP)
CFLAGS += -DVLAN_IP=\"$(VLAN_IP)\" -DVLAN_MASK=\"$(VLAN_MASK)\" -DVLAN_GW=\"$(VLAN_GW)\"
endif

# -----------------------------------------------------------------------------
# Build rules
# -----------------------------------------------------------------------------
Expand Down
23 changes: 23 additions & 0 deletions src/port/stm32h563/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,29 @@
#define WOLFIP_ENABLE_DHCP 1
#endif

/* 802.1Q VLAN sub-interface support. Off by default; enable on the make
* command line with ENABLE_VLAN=1 (the Makefile then passes -DWOLFIP_VLAN=1
* and bumps WOLFIP_MAX_INTERFACES so the sub-interface fits).
*
* The capacity check accounts for 1 physical + (loopback ? 1 : 0) +
* WOLFIP_VLAN_MAX sub-interface slots. */
#ifndef WOLFIP_VLAN
#define WOLFIP_VLAN 0
#endif
#ifndef WOLFIP_VLAN_MAX
#define WOLFIP_VLAN_MAX 4
#endif
#if WOLFIP_VLAN
#if WOLFIP_ENABLE_LOOPBACK
#define WOLFIP_VLAN_RESERVED_SLOTS 2
#else
#define WOLFIP_VLAN_RESERVED_SLOTS 1
#endif
#if (WOLFIP_MAX_INTERFACES < (WOLFIP_VLAN_RESERVED_SLOTS + WOLFIP_VLAN_MAX))
#error "WOLFIP_VLAN requires WOLFIP_MAX_INTERFACES >= 1 (physical) + (WOLFIP_ENABLE_LOOPBACK ? 1 : 0) + WOLFIP_VLAN_MAX"
#endif
#endif

/* Static IP fallback (used when DHCP is disabled or times out) */
#define WOLFIP_IP "192.168.12.11"
#define WOLFIP_NETMASK "255.255.255.0"
Expand Down
39 changes: 39 additions & 0 deletions src/port/stm32h563/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,44 @@ int main(void)
uart_puts("\n");
}

#ifdef ENABLE_VLAN
/* 802.1Q VLAN sub-interface: create a logical interface on top of the
* physical (untagged) interface and run all traffic through it. The
* physical interface stays without an IP; sockets bound on the VLAN
* IP will automatically tag outgoing frames and accept incoming frames
* matching the configured VID. */
{
unsigned int vlan_idx = 0;
ip4 vip = atoip4(VLAN_IP);
ip4 vnm = atoip4(VLAN_MASK);
ip4 vgw = atoip4(VLAN_GW);
int v_ret;

uart_puts("Creating VLAN sub-interface VID=");
uart_putdec((uint32_t)(VLAN_VID));
uart_puts(" PCP=");
uart_putdec((uint32_t)(VLAN_PCP));
uart_puts(" on physical if 0\n");
v_ret = wolfIP_vlan_create(IPStack, 0, (uint16_t)(VLAN_VID),
(uint8_t)(VLAN_PCP), 0, &vlan_idx);
if (v_ret < 0) {
uart_puts(" ERROR: wolfIP_vlan_create failed (-");
uart_putdec((uint32_t)(-v_ret));
uart_puts(")\n");
} else {
uart_puts(" VLAN sub-iface at idx ");
uart_putdec((uint32_t)vlan_idx);
uart_puts("\n IP: ");
uart_putip4(vip);
uart_puts("\n Mask: ");
uart_putip4(vnm);
uart_puts("\n GW: ");
uart_putip4(vgw);
uart_puts("\n");
wolfIP_ipconfig_set_ex(IPStack, vlan_idx, vip, vnm, vgw);
}
}
#else /* ENABLE_VLAN */
#ifdef DHCP
{
uint32_t dhcp_start_tick;
Expand Down Expand Up @@ -958,6 +996,7 @@ int main(void)
wolfIP_ipconfig_set(IPStack, ip, nm, gw);
}
#endif
#endif /* ENABLE_VLAN */

#ifdef WOLFIP_USE_FREERTOS
uart_puts("Starting FreeRTOS BSD socket layer...\n");
Expand Down
39 changes: 39 additions & 0 deletions src/test/unit/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "unit_tests_ip_arp_recv.c"
#include "unit_tests_dns_edges.c"
#include "unit_tests_misc_edges.c"
#include "unit_tests_vlan.c"

Suite *wolf_suite(void)
{
Expand Down Expand Up @@ -1481,6 +1482,44 @@ Suite *wolf_suite(void)
#endif /* WOLFIP_PACKET_SOCKETS */
tcase_add_test(tc_core, test_bind_port_in_use_different_ips_no_collision);

#if WOLFIP_VLAN
/* --- unit_tests_vlan.c (30 tests for 802.1Q support) --- */
tcase_add_test(tc_proto, test_vlan_api_create_basic);
tcase_add_test(tc_proto, test_vlan_api_create_vid_max_ok);
tcase_add_test(tc_proto, test_vlan_api_create_vid_4095_rejected);
tcase_add_test(tc_proto, test_vlan_api_create_vid_above_max_rejected);
tcase_add_test(tc_proto, test_vlan_api_create_pcp_above_7_rejected);
tcase_add_test(tc_proto, test_vlan_api_create_dei_above_1_rejected);
tcase_add_test(tc_proto, test_vlan_api_create_duplicate_vid_rejected);
tcase_add_test(tc_proto, test_vlan_api_create_same_vid_two_parents_ok);
tcase_add_test(tc_proto, test_vlan_api_create_parent_not_physical_rejected);
tcase_add_test(tc_proto, test_vlan_api_create_exhausts_max);
tcase_add_test(tc_proto, test_vlan_api_create_uninitialized_parent_rejected);
tcase_add_test(tc_proto, test_vlan_api_create_loopback_parent_rejected);
tcase_add_test(tc_proto, test_vlan_api_create_null_args_rejected);
tcase_add_test(tc_proto, test_vlan_api_delete_basic);
tcase_add_test(tc_proto, test_vlan_api_delete_physical_rejected);
tcase_add_test(tc_proto, test_vlan_api_delete_bad_ifidx_rejected);
tcase_add_test(tc_proto, test_vlan_api_get_null_args_rejected);
tcase_add_test(tc_proto, test_vlan_api_get_dangling_parent_pointer_rejected);
tcase_add_test(tc_proto, test_vlan_tx_active_without_parent_rejected);
tcase_add_test(tc_proto, test_vlan_tx_tag_inserted);
tcase_add_test(tc_proto, test_vlan_tx_pcp_and_dei_encoded);
tcase_add_test(tc_proto, test_vlan_tx_vid_zero_priority_tag);
tcase_add_test(tc_proto, test_vlan_tx_vid_4094_encoded);
tcase_add_test(tc_proto, test_vlan_tx_oversize_rejected);
tcase_add_test(tc_proto, test_vlan_tx_runt_rejected);
tcase_add_test(tc_proto, test_vlan_rx_tagged_match_delivered);
tcase_add_test(tc_proto, test_vlan_rx_tagged_mismatch_dropped);
tcase_add_test(tc_proto, test_vlan_rx_untagged_on_physical_ok);
tcase_add_test(tc_proto, test_vlan_rx_runt_tagged_dropped);
tcase_add_test(tc_proto, test_vlan_rx_multiple_subs_correct_dispatch);
tcase_add_test(tc_proto, test_vlan_rx_delete_then_dropped);
tcase_add_test(tc_proto, test_vlan_rx_dei_bit_accepted);
tcase_add_test(tc_proto, test_vlan_rx_tagged_arp_processed);
tcase_add_test(tc_proto, test_vlan_mtu_inherited);
#endif /* WOLFIP_VLAN */

suite_add_tcase(s, tc_core);
suite_add_tcase(s, tc_utils);
suite_add_tcase(s, tc_proto);
Expand Down
5 changes: 5 additions & 0 deletions src/test/unit/unit_shared.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@
#undef WOLFIP_PACKET_SOCKETS
#define WOLFIP_PACKET_SOCKETS 1
#undef WOLFIP_MAX_INTERFACES
#if WOLFIP_VLAN
/* Need room for 1 loopback + 1 physical + multiple VLAN sub-ifaces. */
#define WOLFIP_MAX_INTERFACES 6
#else
#define WOLFIP_MAX_INTERFACES 3
#endif
#undef WOLFIP_ENABLE_LOOPBACK
#define WOLFIP_ENABLE_LOOPBACK 1
#undef WOLFIP_ENABLE_FORWARDING
Expand Down
Loading
Loading