Skip to content

Commit 9dbb57a

Browse files
committed
ut_init
1 parent d878050 commit 9dbb57a

File tree

6 files changed

+388
-1
lines changed

6 files changed

+388
-1
lines changed

docs/proposal/ut_test.md

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
### Proposed Implementation Plan
2+
- First: Prepare to implement unit testing in the following order: sendmsg.c → cgroup_skb.c → cgroup_sock.c.
3+
- Test Framework: All tests will use the unitTests_BUILD_CONTEXT framework.
4+
- Mock Functions: For each _test.c file, include the necessary mocked BPF helper functions required during testing.
5+
- Testing Methods:
6+
- For branches that write to BPF maps, use coll.Maps["..."] on the Go testing side to verify whether the map contents are correct.
7+
- For branches that do not write to any map, the current approach is to use the BPF_LOG() macro to print debug information for verification.
8+
### Detailed Implementation Points
9+
- Mounting and Triggering Details for the Three Programs, and Current Testing Points
10+
#### For sendmsg.c:
11+
- Purpose: This file’s function is to prepend TLV (Type-Length-Value) metadata when sending messages.
12+
- Attachment Point: It uses SEC("sk_msg"), so it needs to be attached at the socket message layer.
13+
- Difference: Its mounting and triggering method differ from the other two programs.
14+
- Current Status: We are still experimenting with how to properly attach and trigger this eBPF program.
15+
#### Testing Points
16+
- 1:msg->family != AF_INET && msg->family != AF_INET6
17+
- Messages that are neither IPv4 nor IPv6 should be skipped directly.
18+
- 2:Inside the function get_origin_dst(struct sk_msg_md *msg, struct ip_addr *dst_ip, __u16 *dst_port)
19+
- The condition if (!storage || !storage->via_waypoint || storage->has_encoded) means:
20+
- If storage->via_waypoint is false, it indicates the message does not pass through a Waypoint, so no TLV needs to be constructed.
21+
- If storage->has_encoded is true, it means the TLV has already been inserted before and should not be inserted again.
22+
- 3:alloc_dst_length(msg, tlv_size + TLV_END_SIZE)
23+
- Tests related to buffer memory extension.
24+
- 4:SK_MSG_WRITE_BUF(msg, off, &type, TLV_TYPE_SIZE);
25+
- SK_MSG_WRITE_BUF(msg, off, &addr_size, TLV_LENGTH_SIZE);
26+
- encode_metadata_end(msg, off);
27+
- Verify that the TLV data is correctly written into the buffer.
28+
### For cgroup_skb.c
29+
- Purpose: This file intercepts network packets and monitors or collects statistics on connections that meet certain conditions.
30+
- Attachment Point: Can be attached to the cgroup, following the example of the testing method used in sockops.c.
31+
- Triggering: The program can be triggered during connection initiation (dial) in tests.
32+
#### Testing Points
33+
- 1:!is_monitoring_enable() || !is_periodic_report_enable()
34+
- When monitoring is disabled or periodic reporting is turned off, the program should skip processing.
35+
- 2:skb->family != AF_INET && skb->family != AF_INET6
36+
- Non-IPv4/IPv6 packets should be skipped directly.
37+
- 3:sock_conn_from_sim(skb)
38+
- Controls skipping of simulated connections.
39+
- 4:is_managed_by_kmesh_skb(skb) == false
40+
- Packets not managed by Kmesh should be skipped directly.
41+
- 5:Packets not managed by Kmesh should be skipped directly.
42+
- This function triggers reporting based on timing and performs operations on BPF maps.
43+
- Corresponding maps can be checked on the Go side for testing purposes.
44+
### For cgroup_sock.c
45+
- Purpose:During TCP connection initiation, this function performs traffic control and records/modifies the original destination address based on Kmesh’s management logic, and executes further processing via tail call when necessary.
46+
- Attachment Point: Can be attached to the cgroup, following the example of the testing method used in sockops.c.
47+
#### Testing Points
48+
- 1:handle_kmesh_manage_process(&kmesh_ctx) || !is_kmesh_enabled(ctx)
49+
- If the connection originates from the control plane, or if the current network namespace is not managed by Kmesh, skip processing.
50+
- 2:ctx->protocol != IPPROTO_TCP
51+
- Skip non-TCP protocols.
52+
- 3:frontend_v = map_lookup_frontend(&frontend_k);
53+
- If the lookup fails (no frontend found), skip processing.
54+
- 4:service_v = map_lookup_service(&service_k);
55+
- Branches depending on whether the service is found.
56+
- 5:set_original_dst_info()
57+
- Verify that the original destination address is correctly written into the bpf_sk_storage structure.
58+
### Both cgroup_skb.c and cgroup_sock.c are attached to the cgroup, so their mounting process is the same and the attachment and triggering have already been implemented as follows:
59+
```
60+
mount_cgroup2(t, cgroupPath)
61+
defer syscall.Unmount(cgroupPath, 0)
62+
//load the eBPF program
63+
coll, lk := load_bpf_2_cgroup(t, objFilePath, "..._prog", cgroupPath)
64+
defer coll.Close()
65+
defer lk.Close()
66+
// Set the BPF configuration
67+
setBpfConfig(t, coll, &factory.GlobalBpfConfig{
68+
BpfLogLevel: constants.BPF_LOG_DEBUG,
69+
AuthzOffload: constants.DISABLED,
70+
})
71+
startLogReader(coll)
72+
```
73+
#### Triggering cgroup_skb.c
74+
- To trigger cgroup_skb.c, the following code is needed:
75+
```
76+
conn, err := net.Dial("tcp", "127.0.0.1:8080")
77+
if err != nil {
78+
t.Fatalf("连接失败: %v", err)
79+
}
80+
defer conn.Close()
81+
```
82+
- The server-side code can be included or omitted.
83+
- 1: Write it like this — during the TCP three-way handshake, sending packets to the server will trigger the egress program, and the client receiving packets will trigger the ingress program.
84+
- 2:The server-side code can also be included, for example:
85+
```
86+
// ln, err := net.Listen("tcp", "127.0.0.1:8080")
87+
// if err != nil {
88+
// t.Fatalf("监听失败: %v", err)
89+
// }
90+
// defer ln.Close()
91+
92+
// go func() {
93+
// conn, err := ln.Accept()
94+
// if err != nil {
95+
// t.Logf("Accept error: %v", err)
96+
// return
97+
// }
98+
// defer conn.Close()
99+
// io.Copy(io.Discard, conn) // 丢弃接收数据
100+
// }()
101+
```
102+
- Both ingress and egress will be triggered.
103+
- Currently, we are still considering whether it is necessary to implement triggering only in one of these cases.
104+
#### Triggering cgroup_sock.c
105+
```
106+
conn, err := net.Dial("tcp", "1.1.1.1:80") // 目标地址不重要
107+
if err != nil {
108+
t.Logf("connect failed (ok, just for trigger): %v", err)
109+
} else {
110+
conn.Close()
111+
```
112+
### Question
113+
- 1
114+
- To achieve generality for mounting to cgroup, a proName parameter can be added to this function to make it more generic.
115+
```
116+
func load_bpf_2_cgroup(t *testing.T, objFilename string, cgroupPath string) (*ebpf.Collection, link.Link) {
117+
if cgroupPath == "" {
118+
t.Fatal("cgroupPath is empty")
119+
}
120+
if objFilename == "" {
121+
t.Fatal("objFilename is empty")
122+
}
123+
124+
// load the eBPF program
125+
spec := loadAndPrepSpec(t, path.Join(*testPath, objFilename))
126+
var (
127+
coll *ebpf.Collection
128+
err error
129+
)
130+
131+
// Load the eBPF collection into the kernel
132+
coll, err = ebpf.NewCollection(spec)
133+
if err != nil {
134+
var ve *ebpf.VerifierError
135+
if errors.As(err, &ve) {
136+
t.Fatalf("verifier error: %+v", ve)
137+
} else {
138+
t.Fatal("loading collection:", err)
139+
}
140+
}
141+
spec.Programs["sockops_prog"].AttachType)
142+
lk, err := link.AttachCgroup(link.CgroupOptions{
143+
Path: constants.Cgroup2Path,
144+
Attach: spec.Programs["sockops_prog"].AttachType,
145+
Program: coll.Programs["sockops_prog"],
146+
})
147+
t.Log(spec.Programs["sockops_prog"].AttachType)
148+
if err != nil {
149+
coll.Close()
150+
t.Fatalf("Failed to attach cgroup: %v", err)
151+
}
152+
return coll, lk
153+
}
154+
```
155+
- Turn it into
156+
```
157+
func load_bpf_prog_to_cgroup(t *testing.T, objFilename string, progName string, cgroupPath string) (*ebpf.Collection, link.Link) {
158+
if cgroupPath == "" {
159+
t.Fatal("cgroupPath is empty")
160+
}
161+
if objFilename == "" {
162+
t.Fatal("objFilename is empty")
163+
}
164+
165+
// load the eBPF program
166+
spec := loadAndPrepSpec(t, path.Join(*testPath, objFilename))
167+
var (
168+
coll *ebpf.Collection
169+
err error
170+
)
171+
// Load the eBPF collection into the kernel
172+
coll, err = ebpf.NewCollection(spec)
173+
if err != nil {
174+
var ve *ebpf.VerifierError
175+
if errors.As(err, &ve) {
176+
t.Fatalf("verifier error: %+v", ve)
177+
} else {
178+
t.Fatal("loading collection:", err)
179+
}
180+
}
181+
lk, err := link.AttachCgroup(link.CgroupOptions{
182+
Path: constants.Cgroup2Path,
183+
Attach: spec.Programs[progName].AttachType,
184+
Program: coll.Programs[progName],
185+
})
186+
t.Log(spec.Programs[progName].AttachType)
187+
if err != nil {
188+
coll.Close()
189+
t.Fatalf("Failed to attach cgroup: %v", err)
190+
}
191+
return coll, lk
192+
}
193+
```
194+
- 2
195+
- Does this function need to be modified
196+
```
197+
func loadAndPrepSpec(t *testing.T, elfPath string) *ebpf.CollectionSpec {
198+
spec, err := ebpf.LoadCollectionSpec(elfPath)
199+
if err != nil {
200+
t.Fatalf("load spec %s: %v", elfPath, err)
201+
}
202+
// Unpin all maps, as we don't want to interfere with other tests
203+
for _, m := range spec.Maps {
204+
m.Pinning = ebpf.PinNone
205+
}
206+
207+
for n, p := range spec.Programs {
208+
switch p.Type {
209+
// https://docs.ebpf.io/linux/syscall/BPF_PROG_TEST_RUN/
210+
case ebpf.XDP, ebpf.SchedACT, ebpf.SchedCLS, ebpf.SocketFilter, ebpf.CGroupSKB, ebpf.SockOps:
211+
continue
212+
}
213+
214+
t.Logf("Skipping program '%s' of type '%s': BPF_PROG_RUN not supported", p.Name, p.Type)
215+
delete(spec.Programs, n)
216+
}
217+
218+
return spec
219+
}
220+
- The purpose of this function is to load metadata, so ebpf.SkMsg and ebpf.CGroupSockAddr need to be included to prevent deletion.

test/bpf_ut/bpftest/bpf_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ func loadAndPrepSpec(t *testing.T, elfPath string) *ebpf.CollectionSpec {
209209
for n, p := range spec.Programs {
210210
switch p.Type {
211211
// https://docs.ebpf.io/linux/syscall/BPF_PROG_TEST_RUN/
212-
case ebpf.XDP, ebpf.SchedACT, ebpf.SchedCLS, ebpf.SocketFilter, ebpf.CGroupSKB, ebpf.SockOps:
212+
case ebpf.XDP, ebpf.SchedACT, ebpf.SchedCLS, ebpf.SocketFilter, ebpf.CGroupSKB, ebpf.SockOps, ebpf.SkMsg, ebpf.CGroupSockAddr:
213213
continue
214214
}
215215

0 commit comments

Comments
 (0)