kopia lustrzana https://github.com/espressif/esp-idf
esp_eth pytest: increased robustness of the L2 test
Added filtering frames based on MAC addresspull/11218/head
rodzic
6987644d67
commit
f6715c9c29
|
@ -12,7 +12,7 @@
|
|||
#include "arpa/inet.h" // for ntohs, etc.
|
||||
#include "esp_log.h"
|
||||
|
||||
#define TEST_ETH_TYPE 0x2222
|
||||
#define TEST_ETH_TYPE 0x3300
|
||||
#define TEST_CTRL_ETH_TYPE (TEST_ETH_TYPE + 1)
|
||||
|
||||
#define WAIT_AFTER_CONN_MS 2500
|
||||
|
@ -30,6 +30,7 @@
|
|||
typedef struct
|
||||
{
|
||||
EventGroupHandle_t eth_event_group;
|
||||
uint8_t dst_mac_addr[ETH_ADDR_LEN];
|
||||
int unicast_rx_cnt;
|
||||
int multicast_rx_cnt;
|
||||
int brdcast_rx_cnt;
|
||||
|
@ -37,12 +38,13 @@ typedef struct
|
|||
bool check_rx_data;
|
||||
} recv_info_t;
|
||||
|
||||
|
||||
esp_err_t l2_packet_txrx_test_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv) {
|
||||
recv_info_t *recv_info = (recv_info_t*)priv;
|
||||
EventGroupHandle_t eth_event_group = recv_info->eth_event_group;
|
||||
emac_frame_t *pkt = (emac_frame_t *)buffer;
|
||||
// check header
|
||||
if (pkt->proto == TEST_ETH_TYPE) { // data packet
|
||||
if (pkt->proto == ntohs(TEST_ETH_TYPE)) { // data packet
|
||||
uint8_t local_mac_addr[ETH_ADDR_LEN];
|
||||
esp_eth_ioctl(hdl, ETH_CMD_G_MAC_ADDR, local_mac_addr);
|
||||
// check data content
|
||||
|
@ -70,6 +72,7 @@ esp_err_t l2_packet_txrx_test_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t
|
|||
}
|
||||
} else if (ntohs(pkt->proto) == TEST_CTRL_ETH_TYPE) { // control packet
|
||||
if (pkt->data[0] == POKE_RESP) {
|
||||
memcpy(recv_info->dst_mac_addr, pkt->dest, ETH_ADDR_LEN);
|
||||
printf("Poke response received\n");
|
||||
xEventGroupSetBits(eth_event_group, ETH_POKE_RESP_RECV_BIT);
|
||||
}
|
||||
|
@ -139,6 +142,12 @@ TEST_CASE("ethernet broadcast transmit", "[ethernet_l2]")
|
|||
.brdcast_rx_cnt = 0
|
||||
};
|
||||
|
||||
uint8_t local_mac_addr[ETH_ADDR_LEN] = {};
|
||||
TEST_ESP_OK(mac->get_addr(mac, local_mac_addr));
|
||||
// test app will parse the DUT MAC from this line of log output
|
||||
printf("DUT MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", local_mac_addr[0], local_mac_addr[1], local_mac_addr[2],
|
||||
local_mac_addr[3], local_mac_addr[4], local_mac_addr[5]);
|
||||
|
||||
TEST_ESP_OK(esp_eth_update_input_path(eth_handle, l2_packet_txrx_test_cb, &recv_info));
|
||||
TEST_ESP_OK(esp_eth_start(eth_handle)); // start Ethernet driver state machine
|
||||
|
||||
|
@ -150,7 +159,7 @@ TEST_CASE("ethernet broadcast transmit", "[ethernet_l2]")
|
|||
poke_and_wait(eth_handle, NULL, 0, eth_event_rx_group);
|
||||
|
||||
emac_frame_t *pkt = malloc(1024);
|
||||
pkt->proto = TEST_ETH_TYPE;
|
||||
pkt->proto = htons(TEST_ETH_TYPE);
|
||||
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, pkt->src));
|
||||
memset(pkt->dest, 0xff, ETH_ADDR_LEN); // broadcast addr
|
||||
for (int i = 0; i < (1024 - ETH_HEADER_LEN); ++i){
|
||||
|
@ -158,7 +167,8 @@ TEST_CASE("ethernet broadcast transmit", "[ethernet_l2]")
|
|||
}
|
||||
|
||||
TEST_ESP_OK(esp_eth_transmit(eth_handle, pkt, 1024));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
// give it some time to complete transmit
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
free(pkt);
|
||||
|
||||
TEST_ESP_OK(esp_eth_stop(eth_handle));
|
||||
|
@ -268,10 +278,8 @@ TEST_CASE("ethernet start/stop stress test under heavy traffic", "[ethernet_l2]"
|
|||
|
||||
// create dummy data packet used for traffic generation
|
||||
emac_frame_t *pkt = calloc(1, 1500);
|
||||
pkt->proto = TEST_ETH_TYPE;
|
||||
// we don't care about dest MAC address much, however it is better to not be broadcast or multifcast to not flood
|
||||
// other network nodes
|
||||
memset(pkt->dest, 0xBA, ETH_ADDR_LEN);
|
||||
pkt->proto = htons(TEST_ETH_TYPE);
|
||||
memcpy(pkt->dest, recv_info.dst_mac_addr, ETH_ADDR_LEN);
|
||||
memcpy(pkt->src, local_mac_addr, ETH_ADDR_LEN);
|
||||
|
||||
printf("EMAC start/stop stress test under heavy Tx traffic\n");
|
||||
|
@ -323,6 +331,10 @@ TEST_CASE("ethernet start/stop stress test under heavy traffic", "[ethernet_l2]"
|
|||
|
||||
free(pkt);
|
||||
|
||||
// Add an extra delay to be sure that there is no traffic generated by the test script during the driver un-installation.
|
||||
// It was observed unintended behavior of the switch used in test environment when link is set down under heavy load.
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
|
||||
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
|
||||
TEST_ESP_OK(esp_event_loop_delete_default());
|
||||
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
|
||||
|
|
|
@ -12,7 +12,7 @@ import pytest
|
|||
from pytest_embedded import Dut
|
||||
from scapy.all import Ether, raw
|
||||
|
||||
ETH_TYPE = 0x2222
|
||||
ETH_TYPE = 0x3300
|
||||
|
||||
|
||||
class EthTestIntf(object):
|
||||
|
@ -37,7 +37,7 @@ class EthTestIntf(object):
|
|||
self.target_if = my_if
|
||||
break
|
||||
if self.target_if == '':
|
||||
raise Exception('network interface not found')
|
||||
raise RuntimeError('network interface not found')
|
||||
logging.info('Use %s for testing', self.target_if)
|
||||
|
||||
@contextlib.contextmanager
|
||||
|
@ -63,22 +63,30 @@ class EthTestIntf(object):
|
|||
except Exception as e:
|
||||
raise e
|
||||
|
||||
def recv_resp_poke(self, i:int=0) -> None:
|
||||
def recv_resp_poke(self, mac:str, i:int=0) -> None:
|
||||
eth_type_ctrl = self.eth_type + 1
|
||||
with self.configure_eth_if(eth_type_ctrl) as so:
|
||||
so.settimeout(30)
|
||||
try:
|
||||
eth_frame = Ether(so.recv(60))
|
||||
if eth_frame.load[0] == 0xfa:
|
||||
for _ in range(10):
|
||||
try:
|
||||
eth_frame = Ether(so.recv(60))
|
||||
except Exception as e:
|
||||
raise e
|
||||
if mac == eth_frame.src and eth_frame.load[0] == 0xfa:
|
||||
if eth_frame.load[1] != i:
|
||||
raise Exception('Missed Poke Packet')
|
||||
raise RuntimeError('Missed Poke Packet')
|
||||
logging.info('Poke Packet received...')
|
||||
eth_frame.dst = eth_frame.src
|
||||
eth_frame.src = so.getsockname()[4]
|
||||
eth_frame.load = bytes.fromhex('fb') # POKE_RESP code
|
||||
so.send(raw(eth_frame))
|
||||
except Exception as e:
|
||||
raise e
|
||||
break
|
||||
else:
|
||||
logging.warning('Unexpected Control packet')
|
||||
logging.warning('Expected Ctrl command: 0xfa, actual: 0x%x', eth_frame.load[0])
|
||||
logging.warning('Source MAC %s', eth_frame.src)
|
||||
else:
|
||||
raise RuntimeError('No Poke Packet!')
|
||||
|
||||
def traffic_gen(self, mac: str, pipe_rcv:connection.Connection) -> None:
|
||||
with self.configure_eth_if() as so:
|
||||
|
@ -120,47 +128,57 @@ def ethernet_l2_test(dut: Dut) -> None:
|
|||
with target_if.configure_eth_if() as so:
|
||||
so.settimeout(30)
|
||||
dut.write('"ethernet broadcast transmit"')
|
||||
res = dut.expect(
|
||||
r'DUT MAC: ([0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2})'
|
||||
)
|
||||
|
||||
# wait for POKE msg to be sure the switch already started forwarding the port's traffic
|
||||
# (there might be slight delay due to the RSTP execution)
|
||||
target_if.recv_resp_poke()
|
||||
dut_mac = res.group(1).decode('utf-8')
|
||||
target_if.recv_resp_poke(mac=dut_mac)
|
||||
|
||||
for _ in range(10):
|
||||
eth_frame = Ether(so.recv(1024))
|
||||
if dut_mac == eth_frame.src:
|
||||
break
|
||||
else:
|
||||
raise RuntimeError('No broadcast received from expected DUT MAC addr')
|
||||
|
||||
eth_frame = Ether(so.recv(1024))
|
||||
for i in range(0, 1010):
|
||||
if eth_frame.load[i] != i & 0xff:
|
||||
raise Exception('Packet content mismatch')
|
||||
raise RuntimeError('Packet content mismatch')
|
||||
dut.expect_unity_test_output()
|
||||
|
||||
dut.expect_exact("Enter next test, or 'enter' to see menu")
|
||||
dut.write('"ethernet recv_pkt"')
|
||||
res = dut.expect(
|
||||
r'([\s\S]*)'
|
||||
r'DUT MAC: ([0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2})'
|
||||
)
|
||||
dut_mac = res.group(1).decode('utf-8')
|
||||
# wait for POKE msg to be sure the switch already started forwarding the port's traffic
|
||||
# (there might be slight delay due to the RSTP execution)
|
||||
target_if.recv_resp_poke()
|
||||
target_if.recv_resp_poke(mac=dut_mac)
|
||||
target_if.send_eth_packet('ff:ff:ff:ff:ff:ff') # broadcast frame
|
||||
target_if.send_eth_packet('01:00:00:00:00:00') # multicast frame
|
||||
target_if.send_eth_packet(res.group(2)) # unicast frame
|
||||
target_if.send_eth_packet(mac=dut_mac) # unicast frame
|
||||
dut.expect_unity_test_output(extra_before=res.group(1))
|
||||
|
||||
dut.expect_exact("Enter next test, or 'enter' to see menu")
|
||||
dut.write('"ethernet start/stop stress test under heavy traffic"')
|
||||
res = dut.expect(
|
||||
r'([\s\S]*)'
|
||||
r'DUT MAC: ([0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2})'
|
||||
)
|
||||
dut_mac = res.group(1).decode('utf-8')
|
||||
# Start/stop under heavy Tx traffic
|
||||
for tx_i in range(10):
|
||||
target_if.recv_resp_poke(tx_i)
|
||||
target_if.recv_resp_poke(dut_mac, tx_i)
|
||||
dut.expect_exact('Ethernet stopped')
|
||||
|
||||
for rx_i in range(10):
|
||||
target_if.recv_resp_poke(rx_i)
|
||||
target_if.recv_resp_poke(dut_mac, rx_i)
|
||||
# Start/stop under heavy Rx traffic
|
||||
pipe_rcv, pipe_send = Pipe(False)
|
||||
tx_proc = Process(target=target_if.traffic_gen, args=(res.group(2), pipe_rcv, ))
|
||||
tx_proc = Process(target=target_if.traffic_gen, args=(dut_mac, pipe_rcv, ))
|
||||
tx_proc.start()
|
||||
dut.expect_exact('Ethernet stopped')
|
||||
pipe_send.send(0) # just send some dummy data
|
||||
|
@ -188,7 +206,6 @@ def test_esp_ethernet(dut: Dut) -> None:
|
|||
@pytest.mark.parametrize('config', [
|
||||
'default_ip101',
|
||||
], indirect=True)
|
||||
@pytest.mark.flaky(reruns=3, reruns_delay=5)
|
||||
def test_esp_emac_hal(dut: Dut) -> None:
|
||||
ethernet_int_emac_hal_test(dut)
|
||||
|
||||
|
@ -198,7 +215,6 @@ def test_esp_emac_hal(dut: Dut) -> None:
|
|||
@pytest.mark.parametrize('config', [
|
||||
'default_ip101',
|
||||
], indirect=True)
|
||||
@pytest.mark.flaky(reruns=3, reruns_delay=5)
|
||||
def test_esp_eth_ip101(dut: Dut) -> None:
|
||||
ethernet_l2_test(dut)
|
||||
|
||||
|
@ -208,6 +224,5 @@ def test_esp_eth_ip101(dut: Dut) -> None:
|
|||
@pytest.mark.parametrize('config', [
|
||||
'default_lan8720',
|
||||
], indirect=True)
|
||||
@pytest.mark.flaky(reruns=3, reruns_delay=5)
|
||||
def test_esp_eth_lan8720(dut: Dut) -> None:
|
||||
ethernet_l2_test(dut)
|
||||
|
|
Ładowanie…
Reference in New Issue