Skip to content

Commit e99e198

Browse files
committed
Addressed review comments: error propagation / backpressure
1 parent 6e8e305 commit e99e198

4 files changed

Lines changed: 151 additions & 6 deletions

File tree

src/test/test_wolfguard_loopback.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ static void setup_loopback_stacks(uint64_t *now)
213213
/* ---- Stack A ---- */
214214
wolfIP_init(&stack_a);
215215

216-
/* Physical interface (non_ethernet, index 0) */
216+
/* Physical interface (non_ethernet, index TEST_PHYS_IF). */
217217
ll = wolfIP_getdev_ex(&stack_a, TEST_PHYS_IF);
218218
ll->non_ethernet = 1;
219219
ll->poll = phys_a_poll;
@@ -236,7 +236,7 @@ static void setup_loopback_stacks(uint64_t *now)
236236
/* Stack B */
237237
wolfIP_init(&stack_b);
238238

239-
/* Physical interface (non_ethernet, index 0) */
239+
/* Physical interface (non_ethernet, index TEST_PHYS_IF). */
240240
ll = wolfIP_getdev_ex(&stack_b, TEST_PHYS_IF);
241241
ll->non_ethernet = 1;
242242
ll->poll = phys_b_poll;

src/test/unit/unit.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,9 @@ Suite *wolf_suite(void)
776776
tcase_add_test(tc_proto, test_regression_loopback_pure_ack_drain_allows_next_send_cycle);
777777
tcase_add_test(tc_proto, test_regression_loopback_pure_ack_immediate_propagates_eagain_when_queue_full);
778778
tcase_add_test(tc_proto, test_regression_loopback_udp_tx_backpressure_retries_after_queue_drain);
779+
tcase_add_test(tc_proto, test_regression_ll_send_frame_returns_wolfip_error_codes);
780+
tcase_add_test(tc_proto, test_regression_loopback_ack_retry_pending_requeued_on_poll);
781+
tcase_add_test(tc_proto, test_regression_loopback_queue_full_pure_ack_backpressure_retry);
779782
tcase_add_test(tc_proto, test_regression_tcp_tx_desc_payload_len_keeps_descriptor_layout_sanity);
780783
tcase_add_test(tc_proto, test_regression_fast_recovery_cwnd_ssthresh_rfc5681);
781784
tcase_add_test(tc_proto, test_regression_paws_rejects_stale_timestamp);

src/test/unit/unit_tests_proto.c

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5076,6 +5076,133 @@ START_TEST(test_regression_loopback_udp_tx_backpressure_retries_after_queue_drai
50765076
}
50775077
END_TEST
50785078

5079+
START_TEST(test_regression_ll_send_frame_returns_wolfip_error_codes)
5080+
{
5081+
struct wolfIP s;
5082+
struct wolfIP_ll_dev *ll;
5083+
uint8_t frame[ETH_HEADER_LEN + IP_HEADER_LEN + TCP_HEADER_LEN] = {0};
5084+
5085+
wolfIP_init(&s);
5086+
mock_link_init(&s);
5087+
ll = wolfIP_getdev_ex(&s, TEST_PRIMARY_IF);
5088+
ck_assert_ptr_nonnull(ll);
5089+
5090+
ck_assert_int_eq(
5091+
wolfIP_ll_send_frame(NULL, TEST_PRIMARY_IF, frame, sizeof(frame)),
5092+
-WOLFIP_EINVAL);
5093+
ck_assert_int_eq(
5094+
wolfIP_ll_send_frame(&s, WOLFIP_MAX_INTERFACES, frame, sizeof(frame)),
5095+
-WOLFIP_EINVAL);
5096+
5097+
ll->send = NULL;
5098+
ck_assert_int_eq(
5099+
wolfIP_ll_send_frame(&s, TEST_PRIMARY_IF, frame, sizeof(frame)),
5100+
-WOLFIP_EINVAL);
5101+
5102+
ll->send = mock_send;
5103+
ck_assert_int_eq(
5104+
wolfIP_ll_send_frame(&s, TEST_PRIMARY_IF, frame, LINK_MTU + 1U),
5105+
-WOLFIP_EINVAL);
5106+
5107+
ll->non_ethernet = 1;
5108+
ck_assert_int_eq(
5109+
wolfIP_ll_send_frame(&s, TEST_PRIMARY_IF, frame, ETH_HEADER_LEN),
5110+
-WOLFIP_EINVAL);
5111+
}
5112+
END_TEST
5113+
5114+
START_TEST(test_regression_loopback_ack_retry_pending_requeued_on_poll)
5115+
{
5116+
struct wolfIP s;
5117+
struct tsocket *ts;
5118+
struct wolfIP_ll_dev *loop;
5119+
uint8_t frame[16] = {0};
5120+
uint8_t rx[IP_MTU_MAX];
5121+
unsigned int i;
5122+
uint64_t now = 300;
5123+
5124+
wolfIP_init(&s);
5125+
loop = wolfIP_getdev_ex(&s, TEST_LOOPBACK_IF);
5126+
ck_assert_ptr_nonnull(loop);
5127+
5128+
for (i = 0; i < WOLFIP_LOOPBACK_QUEUE_DEPTH; i++) {
5129+
ck_assert_int_eq(wolfIP_loopback_send(loop, frame, sizeof(frame)),
5130+
(int)sizeof(frame));
5131+
}
5132+
5133+
ts = &s.tcpsockets[0];
5134+
memset(ts, 0, sizeof(*ts));
5135+
ts->proto = WI_IPPROTO_TCP;
5136+
ts->S = &s;
5137+
ts->if_idx = TEST_LOOPBACK_IF;
5138+
ts->sock.tcp.state = TCP_ESTABLISHED;
5139+
ts->sock.tcp.ack = 100;
5140+
ts->sock.tcp.seq = 1000;
5141+
ts->src_port = 1234;
5142+
ts->dst_port = 4321;
5143+
ts->local_ip = 0x7F000001U;
5144+
ts->remote_ip = 0x7F000001U;
5145+
5146+
tcp_send_ack(ts);
5147+
ck_assert_uint_eq(ts->sock.tcp.ack_retry_pending, 1U);
5148+
5149+
ck_assert_int_gt(loop->poll(loop, rx, sizeof(rx)), 0);
5150+
5151+
loop->poll = mock_poll;
5152+
(void)wolfIP_poll(&s, now);
5153+
5154+
ck_assert_uint_eq(ts->sock.tcp.ack_retry_pending, 0U);
5155+
ck_assert_uint_eq(s.loopback_count, WOLFIP_LOOPBACK_QUEUE_DEPTH);
5156+
}
5157+
END_TEST
5158+
5159+
START_TEST(test_regression_loopback_queue_full_pure_ack_backpressure_retry)
5160+
{
5161+
struct wolfIP s;
5162+
struct tsocket *ts;
5163+
struct wolfIP_ll_dev *loop;
5164+
uint8_t frame[16] = {0};
5165+
uint8_t rx[IP_MTU_MAX];
5166+
unsigned int i;
5167+
uint64_t now = 350;
5168+
5169+
wolfIP_init(&s);
5170+
loop = wolfIP_getdev_ex(&s, TEST_LOOPBACK_IF);
5171+
ck_assert_ptr_nonnull(loop);
5172+
5173+
for (i = 0; i < WOLFIP_LOOPBACK_QUEUE_DEPTH; i++) {
5174+
ck_assert_int_eq(wolfIP_loopback_send(loop, frame, sizeof(frame)),
5175+
(int)sizeof(frame));
5176+
}
5177+
5178+
ts = &s.tcpsockets[1];
5179+
memset(ts, 0, sizeof(*ts));
5180+
ts->proto = WI_IPPROTO_TCP;
5181+
ts->S = &s;
5182+
ts->if_idx = TEST_LOOPBACK_IF;
5183+
ts->sock.tcp.state = TCP_ESTABLISHED;
5184+
ts->sock.tcp.ack = 200;
5185+
ts->sock.tcp.seq = 300;
5186+
ts->src_port = 5000;
5187+
ts->dst_port = 5001;
5188+
ts->local_ip = 0x7F000001U;
5189+
ts->remote_ip = 0x7F000001U;
5190+
5191+
/* Queue full -> pure ACK send must backpressure and mark retry pending. */
5192+
tcp_send_ack(ts);
5193+
ck_assert_uint_eq(ts->sock.tcp.ack_retry_pending, 1U);
5194+
ck_assert_uint_eq(s.loopback_count, WOLFIP_LOOPBACK_QUEUE_DEPTH);
5195+
5196+
/* Free one slot, then poll should retry and enqueue the pending ACK. */
5197+
ck_assert_int_gt(loop->poll(loop, rx, sizeof(rx)), 0);
5198+
loop->poll = mock_poll;
5199+
(void)wolfIP_poll(&s, now);
5200+
5201+
ck_assert_uint_eq(ts->sock.tcp.ack_retry_pending, 0U);
5202+
ck_assert_uint_eq(s.loopback_count, WOLFIP_LOOPBACK_QUEUE_DEPTH);
5203+
}
5204+
END_TEST
5205+
50795206
START_TEST(test_regression_tcp_tx_desc_payload_len_keeps_descriptor_layout_sanity)
50805207
{
50815208
struct wolfIP s;

src/wolfip.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,7 @@ struct tcpsocket {
10841084
uint8_t ctrl_rto_active;
10851085
uint8_t fin_wait_2_timeout_active;
10861086
uint8_t is_listener;
1087+
uint8_t ack_retry_pending;
10871088
ip4 local_ip, remote_ip;
10881089
uint32_t peer_rwnd;
10891090
uint16_t peer_mss;
@@ -1483,13 +1484,13 @@ static inline int wolfIP_ll_send_frame(struct wolfIP *s, unsigned int if_idx,
14831484
uint32_t frame_mtu;
14841485

14851486
if (!ll || !ll->send)
1486-
return -1;
1487+
return -WOLFIP_EINVAL;
14871488
frame_mtu = wolfIP_ll_frame_mtu(ll);
14881489
if (len > frame_mtu)
1489-
return -1;
1490+
return -WOLFIP_EINVAL;
14901491
if (ll->non_ethernet) {
14911492
if (len <= ETH_HEADER_LEN)
1492-
return -1;
1493+
return -WOLFIP_EINVAL;
14931494
return ll->send(ll, (uint8_t *)buf + ETH_HEADER_LEN, len - ETH_HEADER_LEN);
14941495
}
14951496
return ll->send(ll, buf, len);
@@ -2681,7 +2682,14 @@ static int tcp_send_empty(struct tsocket *t, uint8_t flags)
26812682

26822683
static void tcp_send_ack(struct tsocket *t)
26832684
{
2684-
(void)tcp_send_empty(t, TCP_FLAG_ACK);
2685+
int ret = tcp_send_empty(t, TCP_FLAG_ACK);
2686+
2687+
if (!t)
2688+
return;
2689+
if (ret == -WOLFIP_EAGAIN)
2690+
t->sock.tcp.ack_retry_pending = 1;
2691+
else if (ret >= 0)
2692+
t->sock.tcp.ack_retry_pending = 0;
26852693
}
26862694

26872695
static void tcp_send_reset_reply(struct wolfIP *s, unsigned int if_idx,
@@ -7600,6 +7608,13 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now)
76007608
struct pkt_desc *desc;
76017609
struct wolfIP_tcp_seg *tcp;
76027610
tcp_resync_inflight(s, ts, now);
7611+
if (ts->sock.tcp.ack_retry_pending) {
7612+
int ack_ret = tcp_send_empty(ts, TCP_FLAG_ACK);
7613+
if (ack_ret == -WOLFIP_EAGAIN)
7614+
ts->sock.tcp.ack_retry_pending = 1;
7615+
else if (ack_ret >= 0)
7616+
ts->sock.tcp.ack_retry_pending = 0;
7617+
}
76037618
in_flight = ts->sock.tcp.bytes_in_flight;
76047619
if (ts->sock.tcp.persist_active && (ts->sock.tcp.peer_rwnd > 0 ||
76057620
!tcp_has_pending_unsent_payload(ts)))

0 commit comments

Comments
 (0)