Skip to content

Commit 19a0cd6

Browse files
committed
Proposal_Update
1 parent 9dbb57a commit 19a0cd6

File tree

5 files changed

+123
-327
lines changed

5 files changed

+123
-327
lines changed

docs/proposal/ut_test.md

Lines changed: 123 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,98 @@
1-
### Proposed Implementation Plan
2-
- First: Prepare to implement unit testing in the following order: sendmsg.c → cgroup_skb.c → cgroup_sock.c.
1+
---
2+
title: Add Unit Testing Support for eBPF Programs in Kmesh
3+
authors:
4+
- "@wxnzb"
5+
reviewers:
6+
- "@lizhencheng"
7+
8+
approvers:
9+
- "@lizhencheng"
10+
11+
creation-date: 2025-01-15
12+
13+
---
14+
15+
16+
### Summary
17+
18+
<!--
19+
This section is incredibly important for producing high-quality, user-focused
20+
documentation such as release notes or a development roadmap.
21+
22+
A good summary is probably at least a paragraph in length.
23+
-->
24+
25+
### Motivation
26+
27+
<!--
28+
This section is for explicitly listing the motivation, goals, and non-goals of
29+
this KEP. Describe why the change is important and the benefits to users.
30+
-->
31+
32+
When developing eBPF programs in Kmesh, verifying their functionality requires compiling and performing black-box testing. Following Cilium's approach, we introduced a dedicated testing framework for eBPF programs. The framework is now fully set up, and we need contributors to help complete the test cases for each eBPF program.
33+
34+
#### Goals
35+
36+
<!--
37+
List the specific goals of the KEP. What is it trying to achieve? How will we
38+
know that this has succeeded?
39+
-->
40+
41+
- Successfully running unit test code for Kmesh's eBPF sendMsg program.
42+
43+
- Successfully running unit test code for Kmesh's eBPF cgroup program.
44+
45+
- Documentation written in English for the tests of both sendMsg and cgroup programs.
46+
47+
#### Non-Goals
48+
49+
<!--
50+
What is out of scope for this KEP? Listing non-goals helps to focus discussion
51+
and make progress.
52+
-->
53+
54+
### Proposal
55+
56+
<!--
57+
This is where we get down to the specifics of what the proposal actually is.
58+
This should have enough detail that reviewers can understand exactly what
59+
you're proposing, but should not include things like API designs or
60+
implementation. What is the desired outcome and how do we measure success?.
61+
The "Design Details" section below is for the real
62+
nitty-gritty.
63+
-->
64+
65+
- Prepare to implement unit testing in the following order: sendmsg.c → cgroup_skb.c → cgroup_sock.c.
66+
367
- Test Framework: All tests will use the unitTests_BUILD_CONTEXT framework.
68+
469
- Mock Functions: For each _test.c file, include the necessary mocked BPF helper functions required during testing.
70+
571
- Testing Methods:
672
- For branches that write to BPF maps, use coll.Maps["..."] on the Go testing side to verify whether the map contents are correct.
773
- 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
74+
75+
76+
### Design Details
77+
78+
<!--
79+
This section should contain enough information that the specifics of your
80+
change are understandable. This may include API specs (though not always
81+
required) or even code snippets. If there's any ambiguity about HOW your
82+
proposal will be implemented, this is the place to discuss them.
83+
-->
84+
85+
- Detailed Implementation Points
986
- Mounting and Triggering Details for the Three Programs, and Current Testing Points
10-
#### For sendmsg.c:
87+
88+
89+
- For sendmsg.c
1190
- Purpose: This file’s function is to prepend TLV (Type-Length-Value) metadata when sending messages.
1291
- Attachment Point: It uses SEC("sk_msg"), so it needs to be attached at the socket message layer.
1392
- Difference: Its mounting and triggering method differ from the other two programs.
1493
- Current Status: We are still experimenting with how to properly attach and trigger this eBPF program.
15-
#### Testing Points
94+
95+
- Testing Points
1696
- 1:msg->family != AF_INET && msg->family != AF_INET6
1797
- Messages that are neither IPv4 nor IPv6 should be skipped directly.
1898
- 2:Inside the function get_origin_dst(struct sk_msg_md *msg, struct ip_addr *dst_ip, __u16 *dst_port)
@@ -25,11 +105,15 @@
25105
- SK_MSG_WRITE_BUF(msg, off, &addr_size, TLV_LENGTH_SIZE);
26106
- encode_metadata_end(msg, off);
27107
- Verify that the TLV data is correctly written into the buffer.
28-
### For cgroup_skb.c
108+
109+
110+
111+
- For cgroup_skb.c
29112
- Purpose: This file intercepts network packets and monitors or collects statistics on connections that meet certain conditions.
30113
- Attachment Point: Can be attached to the cgroup, following the example of the testing method used in sockops.c.
31114
- Triggering: The program can be triggered during connection initiation (dial) in tests.
32-
#### Testing Points
115+
116+
- Testing Points
33117
- 1:!is_monitoring_enable() || !is_periodic_report_enable()
34118
- When monitoring is disabled or periodic reporting is turned off, the program should skip processing.
35119
- 2:skb->family != AF_INET && skb->family != AF_INET6
@@ -38,13 +122,17 @@
38122
- Controls skipping of simulated connections.
39123
- 4:is_managed_by_kmesh_skb(skb) == false
40124
- Packets not managed by Kmesh should be skipped directly.
41-
- 5:Packets not managed by Kmesh should be skipped directly.
125+
- 5:observe_on_data(sk);
42126
- This function triggers reporting based on timing and performs operations on BPF maps.
43127
- Corresponding maps can be checked on the Go side for testing purposes.
44-
### For cgroup_sock.c
128+
129+
130+
131+
- For cgroup_sock.c
45132
- 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.
46133
- Attachment Point: Can be attached to the cgroup, following the example of the testing method used in sockops.c.
47-
#### Testing Points
134+
135+
- Testing Points
48136
- 1:handle_kmesh_manage_process(&kmesh_ctx) || !is_kmesh_enabled(ctx)
49137
- If the connection originates from the control plane, or if the current network namespace is not managed by Kmesh, skip processing.
50138
- 2:ctx->protocol != IPPROTO_TCP
@@ -55,12 +143,15 @@
55143
- Branches depending on whether the service is found.
56144
- 5:set_original_dst_info()
57145
- 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:
146+
147+
148+
- 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
149+
59150
```
60151
mount_cgroup2(t, cgroupPath)
61152
defer syscall.Unmount(cgroupPath, 0)
62153
//load the eBPF program
63-
coll, lk := load_bpf_2_cgroup(t, objFilePath, "..._prog", cgroupPath)
154+
coll, lk := load_bpf_2_cgroup(t, objFilePath, "..._prog", cgroupPath)
64155
defer coll.Close()
65156
defer lk.Close()
66157
// Set the BPF configuration
@@ -70,151 +161,23 @@
70161
})
71162
startLogReader(coll)
72163
```
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.
164+
165+
166+
167+
### Alternatives
168+
169+
<!--
170+
What other approaches did you consider, and why did you rule them out? These do
171+
not need to be as detailed as the proposal, but should include enough
172+
information to express the idea and why it was not acceptable.
173+
-->
174+
175+
<!--
176+
Note: This is a simplified version of kubernetes enhancement proposal template.
177+
https://github.com/kubernetes/enhancements/tree/3317d4cb548c396a430d1c1ac6625226018adf6a/keps/NNNN-kep-template
178+
-->
179+
180+
181+
182+
183+

0 commit comments

Comments
 (0)