Skip to content

Commit 44078a1

Browse files
author
branch-coverage-leader
committed
test+build(ff_dpdk_kni): Stage-7+ FU-S7-KNI-ENABLE — per-target -DFF_KNI + 7 TCs
Adds per-target Makefile override: $(LIB_OBJS_DIR)/ff_dpdk_kni.o: KNI_EXTRA_CFLAGS := -DFF_KNI so the FF_KNI-gated OSPF case + (!enable_kni) protocol_filter guards become reachable from the unit suite. Stub int enable_kni=0 in test_ff_dpdk_kni.c (not linking ff_dpdk_if.o). Adds 7 TCs targeting: TC-12 ipv4_ospf_returns_ospf (FF_KNI: case IPPROTO_OSPFIGP) TC-13 tcp_kni_enabled_short (L209 protocol_filter_tcp len<hdr) TC-14 udp_kni_enabled_short (L221 protocol_filter_udp len<hdr) TC-15 tcp_kni_enabled_match_returns_kni (L199 protocol_filter_l4 hit + L342 enable_kni=1) TC-16 tcp_kni_enabled_miss_returns_unknown (L199 false leg) TC-17 udp_kni_enabled_match_returns_kni (L350 enable_kni=1) TC-18 init_null_port_lists (L114 kni_set_bitmap !p early-return) ff_dpdk_kni.c line 27.5% -> 59.9% (+32.4pp) ff_dpdk_kni.c branch 40.9% -> 51.6% (+10.7pp) Project merged branch 59.9% -> 60.5% (+0.6pp) Tests 11 -> 18 / 0 fail / valgrind 11/11 / 0 definite leaks G8 ratchet: ff_dpdk_kni line 40->55, branch 35->47
1 parent fdf4ba4 commit 44078a1

4 files changed

Lines changed: 245 additions & 2 deletions

File tree

docs/unit_test_spec/zh_cn/79-stage7-review.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,46 @@ Phase 9 review+mirror : 0
126126
```
127127

128128
EOF
129+
130+
---
131+
132+
## §9 Stage-7+ Follow-up: FU-S7-KNI-ENABLE
133+
134+
**触发**:Stage-7 验收时 ff_dpdk_kni 52 missing branches 多在 `#ifdef FF_KNI` 内或被 dead-code 剥离,未达预期。
135+
136+
**实施**
137+
1. **Makefile per-target 覆盖**`$(LIB_OBJS_DIR)/ff_dpdk_kni.o: KNI_EXTRA_CFLAGS := -DFF_KNI`,仅对 kni.o 启用 FF_KNI(避免污染其他 lib obj)。
138+
2. **stub 补 enable_kni**`int enable_kni = 0;`(lib/ff_dpdk_if.c 提供,未链接 → 在 test 文件本地 stub)。
139+
3. **新 7 TCs**(test_ff_dpdk_kni.c):
140+
- TC-S7-KNI-12 ipv4_ospf_returns_ospf:`case IPPROTO_OSPFIGP: return FILTER_OSPF`(FF_KNI-only case)
141+
- TC-S7-KNI-13/14 tcp/udp_kni_enabled_short:覆盖 protocol_filter_tcp/udp 的 `len < hdr` 真分支(L209/221)
142+
- TC-S7-KNI-15 tcp_kni_enabled_match_returns_kni:覆盖 protocol_filter_l4 的 `if(get_bitmap()) return FILTER_KNI`(L199)+ `if (!enable_kni)` 假分支(L342)
143+
- TC-S7-KNI-16 tcp_kni_enabled_miss_returns_unknown:覆盖 L199 假分支
144+
- TC-S7-KNI-17 udp_kni_enabled_match_returns_kni:覆盖 L350 假分支
145+
- TC-S7-KNI-18 init_null_port_lists:覆盖 kni_set_bitmap `if(!p) return;` 早返(L114)
146+
147+
**结果**
148+
149+
| 指标 | Stage-7 末 | Stage-7+ 末 | Δ |
150+
|---|---|---|---|
151+
| ff_dpdk_kni.c **line** | 27.5% | **59.9%** | **+32.4pp** |
152+
| ff_dpdk_kni.c **branch** | 40.9% | **51.6%** | **+10.7pp** |
153+
| ff_dpdk_kni.c branch denom | 88 | 93 | +5(FF_KNI 新启 case+if)|
154+
| ff_dpdk_kni.c branch hit | 36 | 48 | +12 |
155+
| **Project merged branch** | 59.92% | **60.51%** | **+0.59pp** |
156+
| Project merged line | 60.4% | **62.9%** | +2.5pp |
157+
| ff_dpdk_kni TC count | 11 | **18** | +7 |
158+
| valgrind | 11/11 PASS | **11/11 PASS** ||
159+
160+
**G8 ratchet**`ff_dpdk_kni.c` line 40→55、branch 35→47(actual −5pp 安全边界)。
161+
162+
**剩余 missing**(仍未覆盖,需更复杂手段):
163+
- L142/148/149/161/163:kni_process_tx 的 ratelimit + tx_dropped 分支 — 需要构造完整 rte_eth_devices[port_id] PMD ops(极复杂,建议 Stage-8 用 LD_PRELOAD wrap 或起 KNI 真整合套件)
164+
- L181/183/185:kni_process_rx 同上
165+
- L426/435/466/476/480/486:ff_kni_alloc 的 process_type / virtio_user / ring_create 内部分支 — 需 rte_eal_hotplug_add 真 vdev 注册
166+
167+
**FU-S8-KNI-PROCESS**(继任 follow-up,留 Stage-8):
168+
- 选项 A:在 unit 里加 `--wrap=rte_eth_tx_burst` / `--wrap=rte_eth_rx_burst` 的 mock,仿造一个最小的 burst 计数器,覆盖 L161/163/181/183/185(约 +6 branches 可达)
169+
- 选项 B:起 `tests/integration/test_ff_kni_integration.c`,在真 DPDK + virtio_user 环境下跑 ff_kni_alloc 全路径(Stage-8 D2 集成扩容)
170+
171+
EOF

tests/unit/Makefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,14 @@ check: all
150150
$(LIB_OBJS_DIR):
151151
@mkdir -p $@
152152

153+
# Per-target extra CFLAGS for selected lib objects.
154+
# FU-S7-KNI-ENABLE (Stage-7 follow-up): build ff_dpdk_kni.o with -DFF_KNI so
155+
# that the test suite can exercise the OSPF case and the (!enable_kni)
156+
# protocol_filter guard branches (otherwise dead code in the unit build).
157+
$(LIB_OBJS_DIR)/ff_dpdk_kni.o: KNI_EXTRA_CFLAGS := -DFF_KNI
158+
153159
$(LIB_OBJS_DIR)/%.o: $(LIB_DIR)/%.c | $(LIB_OBJS_DIR)
154-
$(CC) $(CFLAGS) $(DPDK_CFLAGS) -c $< -o $@
160+
$(CC) $(CFLAGS) $(DPDK_CFLAGS) $(KNI_EXTRA_CFLAGS) -c $< -o $@
155161

156162
# ----- common stubs -----
157163
$(COMMON_DIR)/%.o: $(COMMON_DIR)/%.c

tests/unit/coverage_threshold.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ BEGIN {
7878
# line via real EAL --vdev=net_null0; the unit number below is the
7979
# sub-set reachable in pure-mock unit scope.
8080
tline["ff_dpdk_if.c"] = 4; tbr["ff_dpdk_if.c"] = 2 # actual (unit-only): line=5.7% branch=3.6% (merged: line=30.5% branch=22.1%)
81-
tline["ff_dpdk_kni.c"] = 40; tbr["ff_dpdk_kni.c"] = 35 # actual: line=47.2% branch=40.9%
81+
tline["ff_dpdk_kni.c"] = 55; tbr["ff_dpdk_kni.c"] = 47 # actual: line=59.9% branch=51.6% (Stage-7+ FU-S7-KNI-ENABLE)
8282
8383
pass = 0; fail = 0; total_files = 0
8484
}

tests/unit/test_ff_dpdk_kni.c

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ __thread unsigned int per_lcore__lcore_id = 0;
6363
/* nb_dev_ports defined in ff_dpdk_if.c (which we don't link here) */
6464
int nb_dev_ports = 0;
6565

66+
/* FU-S7-KNI-ENABLE: with -DFF_KNI compiled into ff_dpdk_kni.o, the lib
67+
* references `extern int enable_kni;` (defined in ff_dpdk_if.c which we
68+
* do NOT link). Provide the stub here; tests that need the
69+
* (!enable_kni) false-leg flip it to 1 around the call. */
70+
int enable_kni = 0;
71+
6672
/* ------------------------------------------------------------------------ */
6773
/* Module-level EAL/mempool/ring (one-time init via rte_eal_init) */
6874
/* ------------------------------------------------------------------------ */
@@ -399,6 +405,186 @@ test_ff_kni_init_tcp_udp_port_bitmaps(void **state)
399405
kni_stat = saved_kni_stat;
400406
}
401407

408+
/* ======================================================================== */
409+
/* Stage-7 follow-up FU-S7-KNI-ENABLE: branches gated by -DFF_KNI */
410+
/* ======================================================================== */
411+
412+
#ifndef IPPROTO_OSPFIGP
413+
#define IPPROTO_OSPFIGP 89
414+
#endif
415+
416+
/* Helper: build a minimal IPv4 packet starting with version+IHL byte; the
417+
* caller patches proto and (optionally) appends an L4 header. The
418+
* packet's IPv4 header length is exactly 20 bytes (IHL=5). */
419+
static void
420+
ff_test_build_ipv4(uint8_t *buf, size_t buf_len, uint8_t proto)
421+
{
422+
memset(buf, 0, buf_len);
423+
buf[0] = 0x45; /* version=4 IHL=5 */
424+
buf[9] = proto; /* next-proto */
425+
}
426+
427+
/* TC-S7-KNI-12: IPv4+OSPF (proto=89) -> FILTER_OSPF. Covers the FF_KNI-
428+
* gated `case IPPROTO_OSPFIGP: return FILTER_OSPF;` branch (L335-338). */
429+
static void
430+
test_ff_kni_proto_filter_ipv4_ospf_returns_ospf(void **state)
431+
{
432+
(void)state;
433+
uint8_t pkt[64];
434+
ff_test_build_ipv4(pkt, sizeof(pkt), IPPROTO_OSPFIGP);
435+
enum FilterReturn rv = ff_kni_proto_filter(pkt, sizeof(pkt),
436+
RTE_ETHER_TYPE_IPV4);
437+
assert_int_equal(rv, FILTER_OSPF);
438+
}
439+
440+
/* TC-S7-KNI-13: IPv4+TCP with enable_kni=1 and a too-short L4 fragment
441+
* after the IP header -> FILTER_UNKNOWN via protocol_filter_tcp's
442+
* `len < sizeof(rte_tcp_hdr)` true leg (L209 br=0). */
443+
static void
444+
test_ff_kni_proto_filter_ipv4_tcp_kni_enabled_short(void **state)
445+
{
446+
(void)state;
447+
/* IP hdr 20 + 5 bytes TCP fragment (< sizeof(rte_tcp_hdr)=20). */
448+
uint8_t pkt[25];
449+
ff_test_build_ipv4(pkt, sizeof(pkt), IPPROTO_TCP);
450+
451+
int saved = enable_kni; enable_kni = 1;
452+
enum FilterReturn rv = ff_kni_proto_filter(pkt, sizeof(pkt),
453+
RTE_ETHER_TYPE_IPV4);
454+
enable_kni = saved;
455+
assert_int_equal(rv, FILTER_UNKNOWN);
456+
}
457+
458+
/* TC-S7-KNI-14: IPv4+UDP with enable_kni=1 and a too-short L4 fragment
459+
* -> FILTER_UNKNOWN via protocol_filter_udp's len<hdr true leg (L221). */
460+
static void
461+
test_ff_kni_proto_filter_ipv4_udp_kni_enabled_short(void **state)
462+
{
463+
(void)state;
464+
/* IP hdr 20 + 5 bytes UDP fragment (< sizeof(rte_udp_hdr)=8). */
465+
uint8_t pkt[25];
466+
ff_test_build_ipv4(pkt, sizeof(pkt), IPPROTO_UDP);
467+
468+
int saved = enable_kni; enable_kni = 1;
469+
enum FilterReturn rv = ff_kni_proto_filter(pkt, sizeof(pkt),
470+
RTE_ETHER_TYPE_IPV4);
471+
enable_kni = saved;
472+
assert_int_equal(rv, FILTER_UNKNOWN);
473+
}
474+
475+
/* TC-S7-KNI-15: enable_kni=1, ff_kni_init had registered TCP port 80 in
476+
* the bitmap, packet has dst_port=80 (network order) -> FILTER_KNI.
477+
* Covers protocol_filter_l4's true leg (L199) AND the `if (!enable_kni)`
478+
* false leg in the IPPROTO_TCP case (L342). */
479+
static void
480+
test_ff_kni_proto_filter_ipv4_tcp_kni_enabled_match_returns_kni(void **state)
481+
{
482+
(void)state;
483+
SKIP_IF_NO_EAL();
484+
485+
/* (Re)build the port bitmaps under our control. Save+restore the
486+
* caller-managed kni_rp/kni_stat as the existing TC-U-P3-KNI-11 does. */
487+
struct rte_ring **saved_kni_rp = kni_rp;
488+
struct kni_interface_stats **saved_kni_stat = kni_stat;
489+
ff_kni_init(/*nb_ports*/1, /*tcp*/"80", /*udp*/"53");
490+
rte_free(kni_rp);
491+
rte_free(kni_stat);
492+
kni_rp = saved_kni_rp;
493+
kni_stat = saved_kni_stat;
494+
495+
/* IPv4(20) + TCP(20). dst_port lives at IP hdr offset 20 + TCP byte 2..3. */
496+
uint8_t pkt[40];
497+
ff_test_build_ipv4(pkt, sizeof(pkt), IPPROTO_TCP);
498+
/* dst_port=80 in network byte order. set_bitmap stores the htons-ed
499+
* port; get_bitmap is called with hdr->dst_port (already big-endian),
500+
* so writing 0x00,0x50 directly produces the same bit index. */
501+
pkt[20 + 2] = 0x00;
502+
pkt[20 + 3] = 0x50;
503+
504+
int saved = enable_kni; enable_kni = 1;
505+
enum FilterReturn rv = ff_kni_proto_filter(pkt, sizeof(pkt),
506+
RTE_ETHER_TYPE_IPV4);
507+
enable_kni = saved;
508+
assert_int_equal(rv, FILTER_KNI);
509+
}
510+
511+
/* TC-S7-KNI-16: enable_kni=1, packet has dst_port=8080 NOT in the bitmap
512+
* -> FILTER_UNKNOWN (protocol_filter_l4 false leg, L199 br=0). */
513+
static void
514+
test_ff_kni_proto_filter_ipv4_tcp_kni_enabled_miss_returns_unknown(void **state)
515+
{
516+
(void)state;
517+
SKIP_IF_NO_EAL();
518+
519+
struct rte_ring **saved_kni_rp = kni_rp;
520+
struct kni_interface_stats **saved_kni_stat = kni_stat;
521+
ff_kni_init(1, "80", "53");
522+
rte_free(kni_rp);
523+
rte_free(kni_stat);
524+
kni_rp = saved_kni_rp;
525+
kni_stat = saved_kni_stat;
526+
527+
uint8_t pkt[40];
528+
ff_test_build_ipv4(pkt, sizeof(pkt), IPPROTO_TCP);
529+
/* dst_port=8080=0x1F90 in network order. */
530+
pkt[20 + 2] = 0x1F;
531+
pkt[20 + 3] = 0x90;
532+
533+
int saved = enable_kni; enable_kni = 1;
534+
enum FilterReturn rv = ff_kni_proto_filter(pkt, sizeof(pkt),
535+
RTE_ETHER_TYPE_IPV4);
536+
enable_kni = saved;
537+
assert_int_equal(rv, FILTER_UNKNOWN);
538+
}
539+
540+
/* TC-S7-KNI-17: enable_kni=1 + UDP dst_port=53 matches bitmap -> FILTER_KNI.
541+
* Covers `if (!enable_kni)` false leg in IPPROTO_UDP case (L350). */
542+
static void
543+
test_ff_kni_proto_filter_ipv4_udp_kni_enabled_match_returns_kni(void **state)
544+
{
545+
(void)state;
546+
SKIP_IF_NO_EAL();
547+
548+
struct rte_ring **saved_kni_rp = kni_rp;
549+
struct kni_interface_stats **saved_kni_stat = kni_stat;
550+
ff_kni_init(1, "80", "53");
551+
rte_free(kni_rp);
552+
rte_free(kni_stat);
553+
kni_rp = saved_kni_rp;
554+
kni_stat = saved_kni_stat;
555+
556+
/* IPv4(20) + UDP(8). dst_port=53 (0x0035) at IP+2..3. */
557+
uint8_t pkt[28];
558+
ff_test_build_ipv4(pkt, sizeof(pkt), IPPROTO_UDP);
559+
pkt[20 + 2] = 0x00;
560+
pkt[20 + 3] = 0x35;
561+
562+
int saved = enable_kni; enable_kni = 1;
563+
enum FilterReturn rv = ff_kni_proto_filter(pkt, sizeof(pkt),
564+
RTE_ETHER_TYPE_IPV4);
565+
enable_kni = saved;
566+
assert_int_equal(rv, FILTER_KNI);
567+
}
568+
569+
/* TC-S7-KNI-18: ff_kni_init with NULL tcp_ports / udp_ports exercises
570+
* kni_set_bitmap's L114 `if(!p) return;` early-return branch. */
571+
static void
572+
test_ff_kni_init_null_port_lists(void **state)
573+
{
574+
(void)state;
575+
SKIP_IF_NO_EAL();
576+
577+
struct rte_ring **saved_kni_rp = kni_rp;
578+
struct kni_interface_stats **saved_kni_stat = kni_stat;
579+
/* Both args NULL — kni_set_bitmap is invoked twice and returns
580+
* immediately on the !p check. Init must still succeed. */
581+
ff_kni_init(/*nb_ports*/1, /*tcp*/NULL, /*udp*/NULL);
582+
rte_free(kni_rp);
583+
rte_free(kni_stat);
584+
kni_rp = saved_kni_rp;
585+
kni_stat = saved_kni_stat;
586+
}
587+
402588
/* ------------------------------------------------------------------------ */
403589
/* Main runner */
404590
/* ------------------------------------------------------------------------ */
@@ -418,6 +604,14 @@ main(void)
418604
cmocka_unit_test_setup_teardown(test_ff_kni_proto_filter_ipv4_oversized_ihl, test_setup, NULL),
419605
cmocka_unit_test_setup_teardown(test_ff_kni_proto_filter_ipv4_ipip_recurse, test_setup, NULL),
420606
cmocka_unit_test_setup_teardown(test_ff_kni_init_tcp_udp_port_bitmaps, test_setup, NULL),
607+
/* Stage-7 follow-up FU-S7-KNI-ENABLE: branches gated by -DFF_KNI */
608+
cmocka_unit_test_setup_teardown(test_ff_kni_proto_filter_ipv4_ospf_returns_ospf, test_setup, NULL),
609+
cmocka_unit_test_setup_teardown(test_ff_kni_proto_filter_ipv4_tcp_kni_enabled_short, test_setup, NULL),
610+
cmocka_unit_test_setup_teardown(test_ff_kni_proto_filter_ipv4_udp_kni_enabled_short, test_setup, NULL),
611+
cmocka_unit_test_setup_teardown(test_ff_kni_proto_filter_ipv4_tcp_kni_enabled_match_returns_kni, test_setup, NULL),
612+
cmocka_unit_test_setup_teardown(test_ff_kni_proto_filter_ipv4_tcp_kni_enabled_miss_returns_unknown, test_setup, NULL),
613+
cmocka_unit_test_setup_teardown(test_ff_kni_proto_filter_ipv4_udp_kni_enabled_match_returns_kni, test_setup, NULL),
614+
cmocka_unit_test_setup_teardown(test_ff_kni_init_null_port_lists, test_setup, NULL),
421615
};
422616
return cmocka_run_group_tests(tests, group_setup, group_teardown);
423617
}

0 commit comments

Comments
 (0)