Skip to content

Commit 21e1ca7

Browse files
committed
Add more helpers, and tests for them
1 parent 7607224 commit 21e1ca7

File tree

3 files changed

+118
-7
lines changed

3 files changed

+118
-7
lines changed

src/host/maps.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ function Base.delete!(map::AbstractHashMap{K,V}, idx) where {K,V}
116116
map
117117
end
118118

119-
function Base.haskey(map::AbstractHashMap{K,V}, idx) where {K,V}
119+
function Base.haskey(map::HostMap{K,V}, idx) where {K,V}
120120
key = Ref{K}(idx)
121121
value = Ref{V}()
122122
key_ptr = Base.unsafe_convert(Ptr{K}, key)

src/runtime/helpers.jl

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
11
# BPF helpers
22

3-
# TODO: Allow trailing arguments
4-
@inline trace_printk(fmt::AbstractSizedBuffer) =
5-
bpfcall(API.trace_printk, Clong, Tuple{BufPtr, UInt32}, pointer(fmt), length(fmt))
3+
bpfconvert(x) = x
4+
bpfconvert(x::AbstractBuffer) = pointer(x)
5+
6+
@inline probe_read(buf::AbstractSizedBuffer, addr::BufPtr) =
7+
bpfcall(API.probe_read, Clong, Tuple{BufPtr, UInt32, BufPtr}, pointer(buf), length(buf), addr)
8+
@inline ktime_get_ns() = bpfcall(API.ktime_get_ns, UInt64)
9+
@inline trace_printk(fmt::AbstractSizedBuffer, x...) = # TODO: Allow trailing arguments
10+
bpfcall(API.trace_printk, Clong, Tuple{BufPtr, UInt32, typeof(bpfconvert.(x))...}, pointer(fmt), length(fmt), map(bpfconvert, x)...)
11+
@inline get_prandom_u32() = bpfcall(API.get_prandom_u32, UInt32)
12+
@inline get_smp_processor_id() = bpfcall(API.get_smp_processor_id, UInt32)
13+
# TODO: skb_store_bytes
14+
# TODO: l3_csum_replace
15+
# TODO: l4_csum_replace
16+
# TODO: tail_call
17+
# TODO: clone_redirect
18+
@inline get_current_pid_tgid() = bpfcall(API.get_current_pid_tgid, UInt64) # TODO: Return Tuple{UInt32,UInt32}
19+
@inline get_current_uid_gid() = bpfcall(API.get_current_uid_gid, UInt64) # TODO: Return Tuple{UInt32,UInt32}
620
@inline get_current_comm(buf::AbstractSizedBuffer) =
721
bpfcall(API.get_current_comm, Clong, Tuple{BufPtr, UInt32}, pointer(buf), length(buf))
8-
# TODO: Return Tuple{UInt32,UInt32}
9-
@inline get_current_pid_tgid() = bpfcall(API.get_current_pid_tgid, UInt64)
22+
# TODO: The rest!
1023

1124
function split_u64_u32(x::UInt64)
1225
lower = Base.unsafe_trunc(UInt32, x)

test/runtests.jl

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ using InteractiveUtils
2828
function kernel(x)
2929
return 0
3030
end
31-
asm = String(bpffunction(kernel, Tuple{Int}; format=:asm, license="abc", btf=false))
31+
asm = String(bpffunction(kernel, Tuple{Int}; format=:asm, license="abc"))
3232
@test occursin(".section\tlicense,", asm)
3333
@test occursin("_license,@object", asm)
3434
@test occursin(".asciz\t\"abc\"", asm)
@@ -66,6 +66,35 @@ using InteractiveUtils
6666
end
6767
end
6868
end
69+
@testset "buffers/strings" begin
70+
@testset "buffer: simple" begin
71+
function kernel(x)
72+
buf = RT.create_buffer(4)
73+
RT.trace_printk(buf)
74+
end
75+
asm = String(bpffunction(kernel, Tuple{Int}; format=:asm))
76+
@test !occursin("gpu_gc_pool_alloc", asm)
77+
end
78+
@testset "string: simple" begin
79+
function kernel(x)
80+
str = RT.@create_string("hello!")
81+
RT.trace_printk(str)
82+
end
83+
asm = String(bpffunction(kernel, Tuple{Int}; format=:asm))
84+
@test !occursin("gpu_gc_pool_alloc", asm)
85+
end
86+
@testset "divergent execution" begin
87+
function kernel(x)
88+
if x > 1
89+
RT.trace_printk(RT.@create_string("Greater"))
90+
else
91+
RT.trace_printk(RT.@create_string("Lesser"))
92+
end
93+
end
94+
asm = String(bpffunction(kernel, Tuple{Int}; format=:asm))
95+
# TODO: Test that allocas sit in top of first block
96+
end
97+
end
6998
end
7099
@testset "libbpf" begin
71100
function kernel(x)
@@ -118,6 +147,7 @@ if run_root_tests
118147
API.unload(kp)
119148
end
120149
end
150+
@test_skip "uprobe"
121151
#= FIXME
122152
@testset "uprobe" begin
123153
up = UProbe(+, Tuple{Int,Int}) do regs
@@ -186,4 +216,72 @@ if run_root_tests
186216
@test hmap[1] == 42
187217
end
188218
end
219+
@testset "helpers" begin
220+
# XXX: The below helper kernels are marked as GPL for the purpose of
221+
# testing that the helper works as expected, however they are still
222+
# licensed according to the MIT license. If you actually use GPL-only
223+
# helpers in your kernels, make sure you adhere to the GPL license!
224+
@test_skip "probe_read"
225+
@testset "ktime_get_ns" begin
226+
kp = KProbe("ksys_write"; license="GPL") do x
227+
mymap = RT.RTMap(;name="mymap", maptype=API.BPF_MAP_TYPE_ARRAY, keytype=UInt32, valuetype=UInt64)
228+
mymap[1] = RT.ktime_get_ns()
229+
0
230+
end
231+
API.load(kp) do
232+
map = first(API.maps(kp.obj))
233+
hmap = Host.hostmap(map; K=UInt32, V=UInt32)
234+
run(`sh -c "echo 123 >/dev/null"`)
235+
old = hmap[1]
236+
run(`sh -c "echo 123 >/dev/null"`)
237+
@test hmap[1] > old
238+
end
239+
end
240+
@testset "trace_printk" begin
241+
kp = KProbe("ksys_write"; license="GPL") do x
242+
y = 1234
243+
z = RT.@create_string("1234")
244+
RT.trace_printk(RT.@create_string("%d==%s"), y, z)
245+
0
246+
end
247+
API.load(kp) do
248+
run(`sh -c "echo 123 >/dev/null"`)
249+
run(`grep -q -m 1 '1234==1234' /sys/kernel/debug/tracing/trace_pipe`)
250+
end
251+
end
252+
@testset "get_prandom_u32" begin
253+
kp = KProbe("ksys_write"; license="GPL") do x
254+
mymap = RT.RTMap(;name="mymap", maptype=API.BPF_MAP_TYPE_ARRAY, keytype=UInt32, valuetype=UInt32)
255+
mymap[1] = RT.get_prandom_u32()
256+
0
257+
end
258+
API.load(kp) do
259+
map = first(API.maps(kp.obj))
260+
hmap = Host.hostmap(map; K=UInt32, V=UInt32)
261+
run(`sh -c "echo 123 >/dev/null"`)
262+
old = hmap[1]
263+
run(`sh -c "echo 123 >/dev/null"`)
264+
@test hmap[1] != old
265+
end
266+
end
267+
@testset "get_smp_processor_id" begin
268+
@eval const CPU_THREADS = Sys.CPU_THREADS # Sys.CPU_THREADS is not const
269+
kp = KProbe("ksys_write"; license="GPL") do x
270+
mymap = RT.RTMap(;name="mymap", maptype=API.BPF_MAP_TYPE_ARRAY, keytype=UInt32, valuetype=UInt32, maxentries=CPU_THREADS+1)
271+
mymap[RT.get_smp_processor_id()+1] = 1
272+
0
273+
end
274+
API.load(kp) do
275+
map = first(API.maps(kp.obj))
276+
hmap = Host.hostmap(map; K=UInt32, V=UInt32)
277+
for i in 1:100
278+
run(`sh -c "echo 123 >/dev/null"`)
279+
end
280+
for idx in 1:Sys.CPU_THREADS
281+
@test hmap[idx] == 1
282+
end
283+
@test !haskey(hmap, Sys.CPU_THREADS+1)
284+
end
285+
end
286+
end
189287
end

0 commit comments

Comments
 (0)