Unix & Linux Stack Exchange
Q&A for users of Linux, FreeBSD and other Unix-like operating systems
Latest Questions
2
votes
1
answers
3670
views
linux bpftool not found in linux-tools-common for kernel 4.19.232
I am trying to check if `bpf` is properly installed in my linux kernel. It's enabled in the kernel as shown: ``` jakew@desktop:~$ cat config | grep BPF CONFIG_CGROUP_BPF=y CONFIG_BPF=y CONFIG_BPF_SYSCALL=y CONFIG_BPF_JIT_ALWAYS_ON=y # CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set CONFIG_IPV6_SEG6_BPF=y C...
I am trying to check if
bpf
is properly installed in my linux kernel. It's enabled in the kernel as shown:
jakew@desktop:~$ cat config | grep BPF
CONFIG_CGROUP_BPF=y
CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT_ALWAYS_ON=y
# CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set
CONFIG_IPV6_SEG6_BPF=y
CONFIG_NETFILTER_XT_MATCH_BPF=y
CONFIG_BPFILTER=y
CONFIG_BPFILTER_UMH=m
CONFIG_NET_CLS_BPF=y
CONFIG_NET_ACT_BPF=y
CONFIG_BPF_JIT=y
CONFIG_BPF_STREAM_PARSER=y
CONFIG_LWTUNNEL_BPF=y
CONFIG_HAVE_EBPF_JIT=y
CONFIG_BPF_EVENTS=y
# CONFIG_TEST_BPF is not set
I tried to install bpftool
to check up on bpf
, and it seems like i need to install it via linux_tools_common with: sudo apt install linux_tools_common
. When I tried to run bpftool
, it showed this error:
WARNING: bpftool not found for kernel 4.19.232
You may need to install the following packages for this specific kernel:
linux-tools-4.19.232-4.19.232
linux-cloud-tools-4.19.232-4.19.232
You may also want to install one of the following packages to keep up to date:
linux-tools-4.19.232
linux-cloud-tools-4.19.232
however, sudo apt install linux-tools-4.19.232
showed an error saying package not found.
Not sure how I can get bpftool
to work so that I can explore more into bpf
?
Thanks
jake wong
(141 rep)
Dec 4, 2022, 07:37 PM
• Last activity: May 31, 2025, 08:02 PM
2
votes
1
answers
50
views
How are network stack modifications tested?
I have the task to develop a modification (using eBPF) of the TCP stack of the Linux kernel, and I need to test its interoperability with non-modified kernels. Specifically, the eBPF program should be able to inspect some TCP header information, and possible retransmit the packet to a different IP....
I have the task to develop a modification (using eBPF) of the TCP stack of the Linux kernel, and I need to test its interoperability with non-modified kernels. Specifically, the eBPF program should be able to inspect some TCP header information, and possible retransmit the packet to a different IP. How are such modifications usually tested?
So far I've considered:
1. Using one VM for the modified version, and one VM for the unmodified, and then using mininet to connect them and create various testing scenarios.
2. Using containernet (instead of mininet) to load containers with the eBPF program, but attempt to create a runtime flag in the eBPF program so that it will only act in one of the containers.
3. Use separate hardware, and create a physical testbed (which I find undesirable).
How do those of you that work on such projects usually test your changes?
Joppiedoppie
(23 rep)
May 30, 2025, 01:27 PM
• Last activity: May 30, 2025, 02:00 PM
1
votes
0
answers
26
views
What does the phrase "consider native interface" refer to when the nftables wiki says that xt_bpf match is unsupported
In [this](https://wiki.nftables.org/wiki-nftables/index.php/Supported_features_compared_to_xtables) list of unsupported xtables features. xt_bpf is listed as one of the unsupported features. The comment says to "consider native interface". But what interface is being referred to here? This is the on...
In [this](https://wiki.nftables.org/wiki-nftables/index.php/Supported_features_compared_to_xtables) list of unsupported xtables features. xt_bpf is listed as one of the unsupported features. The comment says to "consider native interface". But what interface is being referred to here? This is the only ever mention of bpf in the entire nftables wiki.
Philippe
(569 rep)
Mar 21, 2025, 01:19 PM
2
votes
0
answers
25
views
Task name shown as <...> in the output of EBPF program
I wrote a simple EBPF program which prints a message when the `execve` system call is invoked. I print the message using the `bpf_trace_printk` function. In the output, the task name for some processes is shown as ` `. For example, I ran the `sh` command and the output corresponding to that is the f...
I wrote a simple EBPF program which prints a message when the
execve
system call is invoked. I print the message using the bpf_trace_printk
function. In the output, the task name for some processes is shown as `. For example, I ran the
sh` command and the output corresponding to that is the following:
b' -588130 ...21 512047.173196: bpf_trace_printk: Hello World!'
As you can see above, the task name is shown as ` instead of
sh`. Why is that happening? How can I get the actual task name to be displayed?
russell.price
(53 rep)
Jan 14, 2025, 10:32 PM
0
votes
1
answers
51
views
eBPF `bpf_core_read` returns incorrect value
As @andy-dalton suggests. I changed type of `err` and initialized it. But it still outputs the same results. The modified code: ```c SEC("sockops") int bpf_sockops_cb(struct bpf_sock_ops *skops) { u32 op = 0; long err; err = bpf_core_read(&op, sizeof(op), &skops->op); if (err) { bpf_printk("err code...
As @andy-dalton suggests. I changed type of
err
and initialized it. But it still outputs the same results.
The modified code:
SEC("sockops")
int bpf_sockops_cb(struct bpf_sock_ops *skops) {
u32 op = 0;
long err;
err = bpf_core_read(&op, sizeof(op), &skops->op);
if (err) {
bpf_printk("err code %ld\n", err);
}
bpf_printk("op1 = %u, op2 = %u \n", op, skops->op);
return 0;
}
The outputs:
curl-286392 ....1 44631.729219: bpf_trace_printk: op1 = 3245625024, op2 = 3
curl-286392 ....1 44631.729223: bpf_trace_printk: op1 = 3245625024, op2 = 2
curl-286392 ....1 44631.729223: bpf_trace_printk: op1 = 3245625024, op2 = 1
curl-286392 ....1 44631.729224: bpf_trace_printk: op1 = 3245625024, op2 = 6
----------
My eBPF program as follows.
#include "vmlinux.h"
#include
#include
#include
#include
#include "common.h"
char __license[] SEC("license") = "GPL";
SEC("sockops")
int bpf_sockops_cb(struct bpf_sock_ops *skops) {
u32 op;
int err;
err = bpf_core_read(&op, sizeof(op), &skops->op);
if (err) {
bpf_printk("err\n");
}
bpf_printk("op1 = %u, op2 = %u \n", op, skops->op);
return 0;
}
When I check the tracing output by cat /sys/kernel/debug/tracing/trace_pipe
, it shows that op1
!= op2
.
curl-1466326 ....1 241519.609044: bpf_trace_printk: op1 = 3913290112, op2 = 3
curl-1466326 ....1 241519.609048: bpf_trace_printk: op1 = 3913290112, op2 = 2
curl-1466326 ....1 241519.609048: bpf_trace_printk: op1 = 3913290112, op2 = 1
curl-1466326 ....1 241519.609049: bpf_trace_printk: op1 = 3913290112, op2 = 6
Why does op1
and op2
become different ?
maplgebra
(121 rep)
Dec 9, 2024, 06:13 AM
• Last activity: Dec 10, 2024, 03:22 AM
0
votes
0
answers
44
views
How does bpftrace implement its printf function?
the bpftrace language supports the function `printf` which can write something to the terminal, but as far as I know ebpf running in kernel mode cannot call arbitrary kernel functions, so how is that implemented? My rough guess is that bpftrace compile its `printf` function to `bpf_trace_printk`(whi...
the bpftrace language supports the function
printf
which can write something to the terminal, but as far as I know ebpf running in kernel mode cannot call arbitrary kernel functions, so how is that implemented?
My rough guess is that bpftrace compile its printf
function to bpf_trace_printk
(which is a bpf helper being able to write formated text into TraceFS) and then the tracer process reads from /sys/kernel/tracing/trace_pipe
to duplicate those text to stdout of the tracer process. But that routine would just be too slow.
炸鱼薯条德里克
(1435 rep)
Dec 7, 2024, 01:33 AM
• Last activity: Dec 7, 2024, 03:42 AM
0
votes
0
answers
29
views
BPF program attached to `getname` won't get called when calling the `renameat2` syscall
I'm fiddling with a BPF program that needs to attach to the two "getname" functions that are being called from the `renameat2` syscall, defined in [linux/fs/namei.c][1] as: ```c SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname, unsigned...
I'm fiddling with a BPF program that needs to attach to the two "getname" functions that are being called from the
renameat2
syscall, defined in linux/fs/namei.c as:
SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
int, newdfd, const char __user *, newname, unsigned int, flags)
{
return do_renameat2(olddfd, getname(oldname), newdfd, getname(newname),
flags);
}
getname
calls getname_flags
, which in turn calls strncpy_from_user
. I need to access the char __user * name
parameter, thus I tried creating kprobes, fentries and fexits (with a simple "print" program) to try and intercept all three of those functions.
With getname*, I get a lot of output meaning that my BPF program are actually being runned. Although, when calling "renameat2" (e.g. when using the linux mv
command), I get no output at all.
This is, in essence, the program I'm currently using, which doesn't get called when using the mv
command:
SEC("fentry/getname_flags")
int BPF_PROG(hijack_getname, char *filename) {
uid_t uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
if (uid == 1002) { //hardcoded uid
bpf_printk(" [%s]", filename);
}
}
If I create a BPF tracepoint program that attaches to the entry and exit of renameat2, I can clearly see that there's no "getname" call between entry and exit.
As I said, I also tried with kprobe and fexit. I can't manage to attach to strncpy_from_user
without getting some weird errors about "Os: 22 - invalid argument"
I really can't figure out what's happening, thus any help would be appreciated :,)
(P.S. I also posted this on stackoverflow)
Dennis Orlando
(81 rep)
Dec 4, 2024, 05:18 PM
0
votes
0
answers
39
views
When `BPF(eBPF)` traces the call stack, all user-mode functions are `[unknown]`. Why is this?
Experimental environment ```bash ┌──[root@vms99.liruilongs.github.io]-[/usr/share/bcc/tools] └─$hostnamectl Static hostname: vms99.liruilongs.github.io Icon name: computer-vm Chassis: vm Machine ID: ea70bf6266cb413c84266d4153276342 Boot ID: 0d01838b0095494c82d1befb174a317d Virtualization: vmware Ope...
Experimental environment
┌──[root@vms99.liruilongs.github.io]-[/usr/share/bcc/tools]
└─$hostnamectl
Static hostname: vms99.liruilongs.github.io
Icon name: computer-vm
Chassis: vm
Machine ID: ea70bf6266cb413c84266d4153276342
Boot ID: 0d01838b0095494c82d1befb174a317d
Virtualization: vmware
Operating System: Rocky Linux 8.9 (Green Obsidian)
CPE OS Name: cpe:/o:rocky:rocky:8:GA
Kernel: Linux 4.18.0-513.9.1.el8_9.x86_64
Architecture: x86-64
┌──[root@vms99.liruilongs.github.io]-[/usr/share/bcc/tools]
└─$
When using BPF/eBPF
to trace the call stack, I found that all user-mode functions are [unknown]
┌──[root@vms99.liruilongs.github.io]-[/usr/share/bcc/tools]
└─$profile
Sampling at 49 Hertz of all threads by user + kernel stack... Hit Ctrl-C to end.
^C
_raw_spin_unlock_irqrestore
_raw_spin_unlock_irqrestore
prepare_to_swait_event
rcu_gp_kthread
kthread
ret_from_fork
- rcu_sched (14)
1
kmem_cache_alloc_node
kmem_cache_alloc_node
__alloc_skb
__ip_append_data.isra.50
ip_append_data.part.51
ip_send_unicast_reply
tcp_v4_send_reset
tcp_v4_rcv
ip_protocol_deliver_rcu
ip_local_deliver_finish
ip_local_deliver
ip_rcv
__netif_receive_skb_core
process_backlog
__napi_poll
net_rx_action
__softirqentry_text_start
do_softirq_own_stack
do_softirq.part.16
__local_bh_enable_ip
ip_finish_output2
ip_output
__ip_queue_xmit
__tcp_transmit_skb
tcp_connect
tcp_v4_connect
__inet_stream_connect
inet_stream_connect
__sys_connect
__x64_sys_connect
do_syscall_64
entry_SYSCALL_64_after_hwframe
[unknown]
- haproxy (1203)
1
show_vma_header_prefix
show_vma_header_prefix
show_map_vma
show_map
seq_read
vfs_read
ksys_read
do_syscall_64
entry_SYSCALL_64_after_hwframe
[unknown]
[unknown]
- awk (39726)
1
.............
┌──[root@vms99.liruilongs.github.io]-[/usr/share/bcc/tools]
└─$
What is the reason for this? Is it because the program lacks debugging information? Or some other reason?
I used Python
to write a lock
demo, and this also happened
┌──[root@vms99.liruilongs.github.io]-[~]
└─$cat lock_demo.py
import threading
import time
lock = threading.Lock()
def worker(id):
print(f"Worker {id} started")
with lock:
print(f"Worker {id} acquired lock")
time.sleep(2) # 模拟长时间的计算或 I/O
print(f"Worker {id} released lock")
threads = []
for i in range(5):
t = threading.Thread(target=worker, args=(i,))
threads.append(t)
t.start()
for t in threads:
t.join()
print("All workers finished")
threadsnoop
┌──[root@vms99.liruilongs.github.io]-[~]
└─$threadsnoop
TIME(ms) PID COMM FUNC
0 51671 b'python3' b'[unknown]'
0 51671 b'python3' b'[unknown]'
0 51671 b'python3' b'[unknown]'
0 51671 b'python3' b'[unknown]'
0 51671 b'python3' b'[unknown]'
offcputime
┌──[root@vms99.liruilongs.github.io]-[~/FlameGraph]
└─$offcputime -p pgrep -f lock_demo.py
Tracing off-CPU time (us) of PID 51397 by user + kernel stack... Hit Ctrl-C to end.
^C
.......................
finish_task_switch
__sched_text_start
schedule
futex_wait_queue_me
futex_wait
do_futex
__x64_sys_futex
do_syscall_64
entry_SYSCALL_64_after_hwframe
[unknown]
- python3 (51402)
157
finish_task_switch
__sched_text_start
schedule
futex_wait_queue_me
futex_wait
do_futex
__x64_sys_futex
do_syscall_64
entry_SYSCALL_64_after_hwframe
[unknown]
- python3 (51400)
213
finish_task_switch
__sched_text_start
schedule
futex_wait_queue_me
futex_wait
do_futex
__x64_sys_futex
do_syscall_64
entry_SYSCALL_64_after_hwframe
[unknown]
- python3 (51397)
267
finish_task_switch
__sched_text_start
schedule
do_nanosleep
hrtimer_nanosleep
common_nsleep_timens
__x64_sys_clock_nanosleep
do_syscall_64
entry_SYSCALL_64_after_hwframe
[unknown]
[unknown]
- python3 (51400)
2002609
finish_task_switch
__sched_text_start
schedule
do_nanosleep
hrtimer_nanosleep
common_nsleep_timens
__x64_sys_clock_nanosleep
do_syscall_64
entry_SYSCALL_64_after_hwframe
[unknown]
[unknown]
- python3 (51402)
2003178
..................
┌──[root@vms99.liruilongs.github.io]-[~/FlameGraph]
└─$
Any help will be greatly appreciated, best wishes
山河以无恙
(185 rep)
Oct 21, 2024, 01:58 AM
• Last activity: Oct 22, 2024, 01:40 AM
4
votes
1
answers
839
views
How to get the current cgroup ID from C/C++?
The [eBPF helper functions](https://man7.org/linux/man-pages/man7/bpf-helpers.7.html) define `bpf_get_current_cgroup_id` for eBPF programs, which does the obvious thing ``` u64 bpf_get_current_cgroup_id(void) Return A 64-bit integer containing the current cgroup id based on the cgroup within which t...
The [eBPF helper functions](https://man7.org/linux/man-pages/man7/bpf-helpers.7.html) define
bpf_get_current_cgroup_id
for eBPF programs, which does the obvious thing
u64 bpf_get_current_cgroup_id(void)
Return A 64-bit integer containing the current cgroup id
based on the cgroup within which the current task
is running.
However I can't find an equivalent system call (something similar to [getpid](https://man7.org/linux/man-pages/man2/getppid.2.html)) that I can use in a regular old C program
Am I just completely missing the relevant function? Or does userspace need to do something different to get the cgroup ID for the current task?
user547386
(41 rep)
Oct 31, 2022, 08:15 PM
• Last activity: Aug 16, 2024, 09:24 AM
0
votes
1
answers
110
views
New added android kernel bpf helpers are not detected
I'm trying to patch an android kernel 4.9 to support `probe_read_{user, kernel} and probe_read_{user, kernel}` helpers. For the backporting I took example from another patch that adds `bpf_probe_read_str` helper. While I've patched the kernel to add the helpers and running bpftrace --info, the str h...
I'm trying to patch an android kernel 4.9 to support
probe_read_{user, kernel} and probe_read_{user, kernel}
helpers. For the backporting I took example from another patch that adds bpf_probe_read_str
helper. While I've patched the kernel to add the helpers and running bpftrace --info, the str helper shows up but the newly added ones don't.
bpftrace output
System
OS: Linux 4.9.337-g4fcceb75c5cd #1 SMP PREEMPT Sat May 18 17:26:12 EEST 2024
Arch: aarch64
Build
version: v0.19.1
LLVM: 14.0.6
unsafe probe: yes
bfd: no
libdw (DWARF support): no
libbpf: failed to find valid kernel BTF
Kernel helpers
probe_read: yes
probe_read_str: yes
probe_read_user: no
probe_read_user_str: no
probe_read_kernel: no
probe_read_kernel_str: no
get_current_cgroup_id: no
send_signal: no
override_return: no
get_boot_ns: no
dpath: no
skboutput: no
get_tai_ns: no
get_func_ip: no
Kernel features
Instruction limit: -1
Loop support: no
btf: no
module btf: no
map batch: no
uprobe refcount (depends on Build:bcc bpf_attach_uprobe refcount): no
Map types
hash: yes
percpu hash: yes
array: yes
percpu array: yes
stack_trace: yes
perf_event_array: yes
ringbuf: no
Probe types
kprobe: yes
tracepoint: yes
perf_event: yes
kfunc: no
kprobe_multi: no
raw_tp_special: no
iter: no
probe_read_{user, kernel} and probe_read_{user, kernel}
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index cc5ba47062e8..48762ecbfd66 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -88,6 +88,7 @@ static inline unsigned long __copy_from_user_nocache(void *to,
* happens, handle that and return -EFAULT.
*/
extern long probe_kernel_read(void *dst, const void *src, size_t size);
+extern long probe_kernel_read_strict(void *dst, const void *src, size_t size);
extern long __probe_kernel_read(void *dst, const void *src, size_t size);
/*
@@ -126,6 +127,8 @@ extern long notrace probe_user_write(void __user *dst, const void *src, size_t s
extern long notrace __probe_user_write(void __user *dst, const void *src, size_t size);
extern long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count);
+long strncpy_from_unsafe_strict(char *dst, const void *unsafe_addr,
+ long count);
extern long strncpy_from_unsafe_user(char *dst, const void __user *unsafe_addr,
long count);
extern long strnlen_unsafe_user(const void __user *unsafe_addr, long count);
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 67d7d771a944..d1036b0ba1fa 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -552,6 +552,11 @@ enum bpf_func_id {
*/
BPF_FUNC_get_socket_uid,
+ BPF_FUNC_probe_read_user,
+ BPF_FUNC_probe_read_kernel,
+ BPF_FUNC_probe_read_user_str,
+ BPF_FUNC_probe_read_kernel_str,
+
__BPF_FUNC_MAX_ID,
};
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 83b20092b84c..e872ab1fb235 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -85,44 +85,6 @@ BPF_CALL_3(bpf_probe_read, void *, dst, u32, size, const void *, unsafe_ptr)
return ret;
}
-static const struct bpf_func_proto bpf_probe_read_proto = {
- .func = bpf_probe_read,
- .gpl_only = true,
- .ret_type = RET_INTEGER,
- .arg1_type = ARG_PTR_TO_RAW_STACK,
- .arg2_type = ARG_CONST_STACK_SIZE,
- .arg3_type = ARG_ANYTHING,
-};
-
-BPF_CALL_3(bpf_probe_read_str, void *, dst, u32, size, const void *, unsafe_ptr)
-{
- int ret;
-
- /*
- * The strncpy_from_unsafe() call will likely not fill the entire
- * buffer, but that's okay in this circumstance as we're probing
- * arbitrary memory anyway similar to bpf_probe_read() and might
- * as well probe the stack. Thus, memory is explicitly cleared
- * only in error case, so that improper users ignoring return
- * code altogether don't copy garbage; otherwise length of string
- * is returned that can be used for bpf_perf_event_output() et al.
- */
- ret = strncpy_from_unsafe(dst, unsafe_ptr, size);
- if (unlikely(ret < 0))
- memset(dst, 0, size);
-
- return ret;
-}
-
-static const struct bpf_func_proto bpf_probe_read_str_proto = {
- .func = bpf_probe_read_str,
- .gpl_only = true,
- .ret_type = RET_INTEGER,
- .arg1_type = ARG_PTR_TO_RAW_STACK,
- .arg2_type = ARG_CONST_STACK_SIZE,
- .arg3_type = ARG_ANYTHING,
-};
-
BPF_CALL_3(bpf_probe_write_user, void *, unsafe_ptr, const void *, src,
u32, size)
{
@@ -465,6 +427,139 @@ static const struct bpf_func_proto bpf_current_task_under_cgroup_proto = {
.arg2_type = ARG_ANYTHING,
};
+BPF_CALL_3(bpf_probe_read_user, void *, dst, u32, size,
+ const void __user *, unsafe_ptr)
+{
+ int ret = probe_user_read(dst, unsafe_ptr, size);
+
+ if (unlikely(ret < 0))
+ memset(dst, 0, size);
+
+ return ret;
+}
+
+static const struct bpf_func_proto bpf_probe_read_user_proto = {
+ .func = bpf_probe_read_user,
+ .gpl_only = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_PTR_TO_RAW_STACK,
+ .arg2_type = ARG_CONST_STACK_SIZE,
+ .arg3_type = ARG_ANYTHING,
+};
+
+BPF_CALL_3(bpf_probe_read_user_str, void *, dst, u32, size,
+ const void __user *, unsafe_ptr)
+{
+ int ret = strncpy_from_unsafe_user(dst, unsafe_ptr, size);
+
+ if (unlikely(ret < 0))
+ memset(dst, 0, size);
+
+ return ret;
+}
+
+static const struct bpf_func_proto bpf_probe_read_user_str_proto = {
+ .func = bpf_probe_read_user_str,
+ .gpl_only = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_PTR_TO_RAW_STACK,
+ .arg2_type = ARG_CONST_STACK_SIZE,
+ .arg3_type = ARG_ANYTHING,
+};
+
+static __always_inline int
+bpf_probe_read_kernel_common(void *dst, u32 size, const void *unsafe_ptr,
+ const bool compat)
+{
+ int ret;
+ ret = compat ? probe_kernel_read(dst, unsafe_ptr, size) :
+ probe_kernel_read_strict(dst, unsafe_ptr, size);
+ if (unlikely(ret < 0))
+ memset(dst, 0, size);
+ return ret;
+}
+
+BPF_CALL_3(bpf_probe_read_kernel, void *, dst, u32, size,
+ const void *, unsafe_ptr)
+{
+ return bpf_probe_read_kernel_common(dst, size, unsafe_ptr, false);
+}
+
+static const struct bpf_func_proto bpf_probe_read_kernel_proto = {
+ .func = bpf_probe_read_kernel,
+ .gpl_only = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_PTR_TO_RAW_STACK,
+ .arg2_type = ARG_CONST_STACK_SIZE,
+ .arg3_type = ARG_ANYTHING,
+};
+
+BPF_CALL_3(bpf_probe_read_compat, void *, dst, u32, size,
+ const void *, unsafe_ptr)
+{
+ return bpf_probe_read_kernel_common(dst, size, unsafe_ptr, true);
+}
+
+static const struct bpf_func_proto bpf_probe_read_compat_proto = {
+ .func = bpf_probe_read_compat,
+ .gpl_only = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_PTR_TO_RAW_STACK,
+ .arg2_type = ARG_CONST_STACK_SIZE,
+ .arg3_type = ARG_ANYTHING,
+};
+
+static __always_inline int
+bpf_probe_read_kernel_str_common(void *dst, u32 size, const void *unsafe_ptr,
+ const bool compat)
+{
+ int ret;
+ /*
+ * The strncpy_from_unsafe_*() call will likely not fill the entire
+ * buffer, but that's okay in this circumstance as we're probing
+ * arbitrary memory anyway similar to bpf_probe_read_*() and might
+ * as well probe the stack. Thus, memory is explicitly cleared
+ * only in error case, so that improper users ignoring return
+ * code altogether don't copy garbage; otherwise length of string
+ * is returned that can be used for bpf_perf_event_output() et al.
+ */
+ ret = compat ? strncpy_from_unsafe(dst, unsafe_ptr, size) :
+ strncpy_from_unsafe_strict(dst, unsafe_ptr, size);
+ if (unlikely(ret < 0))
+ memset(dst, 0, size);
+ return ret;
+}
+
+BPF_CALL_3(bpf_probe_read_kernel_str, void *, dst, u32, size,
+ const void *, unsafe_ptr)
+{
+ return bpf_probe_read_kernel_str_common(dst, size, unsafe_ptr, false);
+}
+
+static const struct bpf_func_proto bpf_probe_read_kernel_str_proto = {
+ .func = bpf_probe_read_kernel_str,
+ .gpl_only = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_PTR_TO_RAW_STACK,
+ .arg2_type = ARG_CONST_STACK_SIZE,
+ .arg3_type = ARG_ANYTHING,
+};
+
+BPF_CALL_3(bpf_probe_read_compat_str, void *, dst, u32, size,
+ const void *, unsafe_ptr)
+{
+ return bpf_probe_read_kernel_str_common(dst, size, unsafe_ptr, true);
+}
+
+static const struct bpf_func_proto bpf_probe_read_compat_str_proto = {
+ .func = bpf_probe_read_compat_str,
+ .gpl_only = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_PTR_TO_RAW_STACK,
+ .arg2_type = ARG_CONST_STACK_SIZE,
+ .arg3_type = ARG_ANYTHING,
+};
+
static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id)
{
switch (func_id) {
@@ -474,10 +569,8 @@ static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id)
return &bpf_map_update_elem_proto;
case BPF_FUNC_map_delete_elem:
return &bpf_map_delete_elem_proto;
- case BPF_FUNC_probe_read:
- return &bpf_probe_read_proto;
case BPF_FUNC_probe_read_str:
- return &bpf_probe_read_str_proto;
+ return &bpf_probe_read_compat_str_proto;
case BPF_FUNC_ktime_get_ns:
return &bpf_ktime_get_ns_proto;
case BPF_FUNC_tail_call:
@@ -504,6 +597,17 @@ static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id)
return &bpf_current_task_under_cgroup_proto;
case BPF_FUNC_get_prandom_u32:
return &bpf_get_prandom_u32_proto;
+ case BPF_FUNC_probe_read_user:
+ return &bpf_probe_read_user_proto;
+ case BPF_FUNC_probe_read_kernel:
+ return &bpf_probe_read_kernel_proto;
+ case BPF_FUNC_probe_read:
+ return &bpf_probe_read_compat_proto;
+ case BPF_FUNC_probe_read_user_str:
+ return &bpf_probe_read_user_str_proto;
+ case BPF_FUNC_probe_read_kernel_str:
+ return &bpf_probe_read_kernel_str_proto;
+
default:
return NULL;
}
diff --git a/mm/maccess.c b/mm/maccess.c
index 03ea550f5a74..583935a288ad 100644
--- a/mm/maccess.c
+++ b/mm/maccess.c
@@ -47,6 +47,9 @@ probe_write_common(void __user *dst, const void *src, size_t size)
long __weak probe_kernel_read(void *dst, const void *src, size_t size)
__attribute__((alias("__probe_kernel_read")));
+long __weak probe_kernel_read_strict(void *dst, const void *src, size_t size)
+ __attribute__((alias("__probe_kernel_read")));
+
long __probe_kernel_read(void *dst, const void *src, size_t size)
{
long ret;
@@ -157,6 +160,10 @@ EXPORT_SYMBOL_GPL(probe_user_write);
* If @count is smaller than the length of the string, copies @count-1 bytes,
* sets the last byte of @dst buffer to NUL and returns @count.
*/
+long __weak strncpy_from_unsafe_strict(char *dst, const void *unsafe_addr,
+ long count)
+ __attribute__((alias("strncpy_from_unsafe")));
+
long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count)
{
mm_segment_t old_fs = get_fs();
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index a339bea1f4c8..e6caf916d217 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -516,6 +516,11 @@ enum bpf_func_id {
*/
BPF_FUNC_get_socket_uid,
+ BPF_FUNC_probe_read_user,
+ BPF_FUNC_probe_read_kernel,
+ BPF_FUNC_probe_read_user_str,
+ BPF_FUNC_probe_read_kernel_str,
+
__BPF_FUNC_MAX_ID,
};
bpf: add bpf_probe_read_str helper
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 83b20092b84c..59182e6d6f51 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -465,6 +465,36 @@ static const struct bpf_func_proto bpf_current_task_under_cgroup_proto = {
.arg2_type = ARG_ANYTHING,
};
+BPF_CALL_3(bpf_probe_read_str, void *, dst, u32, size,
+ const void *, unsafe_ptr)
+{
+ int ret;
+
+ /*
+ * The strncpy_from_unsafe() call will likely not fill the entire
+ * buffer, but that's okay in this circumstance as we're probing
+ * arbitrary memory anyway similar to bpf_probe_read() and might
+ * as well probe the stack. Thus, memory is explicitly cleared
+ * only in error case, so that improper users ignoring return
+ * code altogether don't copy garbage; otherwise length of string
+ * is returned that can be used for bpf_perf_event_output() et al.
+ */
+ ret = strncpy_from_unsafe(dst, unsafe_ptr, size);
+ if (unlikely(ret < 0))
+ memset(dst, 0, size);
+
+ return ret;
+}
+
+static const struct bpf_func_proto bpf_probe_read_str_proto = {
+ .func = bpf_probe_read_str,
+ .gpl_only = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_PTR_TO_RAW_STACK,
+ .arg2_type = ARG_CONST_STACK_SIZE,
+ .arg3_type = ARG_ANYTHING,
+};
+
static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id)
{
switch (func_id) {
@@ -504,6 +534,8 @@ static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id)
return &bpf_current_task_under_cgroup_proto;
case BPF_FUNC_get_prandom_u32:
return &bpf_get_prandom_u32_proto;
+ case BPF_FUNC_probe_read_str:
+ return &bpf_probe_read_str_proto;
default:
return NULL;
}
Marcel
(1 rep)
May 18, 2024, 02:54 PM
• Last activity: May 24, 2024, 04:52 PM
7
votes
2
answers
6151
views
How do packets flow through the kernel
When it comes to packet filtering/management I never actually know what is going on inside the kernel. There are so many different tools that act on the packets, either from userspace (modifying kernel-space subsystems) or directly on kernel-space. Is there any place where each tool documents the in...
When it comes to packet filtering/management I never actually know what is going on inside the kernel. There are so many different tools that act on the packets, either from userspace (modifying kernel-space subsystems) or directly on kernel-space.
Is there any place where each tool documents the interaction with other tools, or where they act. I feel like there should be a diagram somewhere specifying what is going on for people who aren't technical enough to go and read the kernel code.
So here's my example:
A packet is received on one of my network interfaces and I have:
- UFW
- iptables
- IPv4 subsystem (routing)
- IPVs
- eBPF
Ok, so I know that UFW is a frontend for iptables, and iptables is a frontend for Netfiler. So now we're on kernel space and our tools are Netfiler, IPVs, IPv4 and eBPF.
Again, the interactions between Netfilter and the IPv4 subsystems are easy to find since these are very old (not in a bad way) subsystems, so lack of docs would be very strange. This diagram is an overview of the interaction:
But what about IPVs and eBPF? What's the actual order in which kernel subsystems act upon the packets when these two are in the kernel?
I always find amazing people who try to go into the guts and help others understand, for example, [this description of the interaction between LVS and Netfilter](http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/LVS-HOWTO.filter_rules.html) .
But shouldn't this be documented in a more official fashion? I'm not looking for an explanation here as to how these submodules interact, I know I could find it myself by searching. My question is more general as to why is there no official documentation that actually tries to explain what is going on inside these kernel subsystems. Is it documented somewhere that I just don't know of? Is there any reason not to try to explain these tools?
I apologize if I'm not making any sense. I just started learning about these things.

AFP_555
(311 rep)
Jan 26, 2022, 05:55 PM
• Last activity: May 23, 2024, 03:53 PM
2
votes
1
answers
250
views
eBPF in real-time systems
I've a question about real-time systems, in particular in LynxOS (LynxOS-178). I would need information on the compatibility and presence of eBPF in these systems. Can anyone help me? I haven't found any documentation online, but I would like to have this information to be able to evaluate which pro...
I've a question about real-time systems, in particular in LynxOS (LynxOS-178).
I would need information on the compatibility and presence of eBPF in these systems.
Can anyone help me?
I haven't found any documentation online, but I would like to have this information to be able to evaluate which product is best to use to achieve my purpose.
Serena Schenone
(21 rep)
Apr 30, 2024, 11:16 AM
• Last activity: May 1, 2024, 08:13 AM
2
votes
1
answers
565
views
How to get argv[0] in bpftrace?
I have this rather simple script: ```bpftrace #!/usr/bin/bpftrace tracepoint:syscalls:sys_enter_exec* { @start[pid] = nsecs; printf("START;%-6d;", pid); join(args->argv); } tracepoint:syscalls:sys_enter_exit* { $from = @start[pid]; $until = nsecs; printf("STOP;%-5d;%-16d\n", pid, $until-$from); } ``...
I have this rather simple script:
#!/usr/bin/bpftrace
tracepoint:syscalls:sys_enter_exec*
{
@start[pid] = nsecs;
printf("START;%-6d;", pid);
join(args->argv);
}
tracepoint:syscalls:sys_enter_exit*
{
$from = @start[pid];
$until = nsecs;
printf("STOP;%-5d;%-16d\n", pid, $until-$from);
}
I'd much rather have it print args->argv
instead of printing the often multi-line join(args->argv)
.
Problem is that printf("START;%-6d;%s", pid, args->argv);
doesn't work:
/tmp/foo.bt:5:5-48: ERROR: printf: %s specifier expects a value of type string (integer supplied)
printf("START;%-6d;%s", pid, args->argv);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pretty sure args->argv
is a string array, so this kind of surprises me. How do I solve this?
Marcus Müller
(47107 rep)
Sep 19, 2023, 09:49 AM
• Last activity: Dec 14, 2023, 09:13 AM
0
votes
0
answers
79
views
Can I use systemd resource management to deny port only outside containers
On an up-to-date fedora 39, I have set up podman for rootless containers and I limit the ports a user may bind to by creating /etc/systemd/system/user-1000.slice.d/user-resources.conf with ``` [Slice] SocketBindAllow = 12345 SocketBindDeny = any ``` Now as expected, the user cannot bind to port 2020...
On an up-to-date fedora 39, I have set up podman for rootless containers and I limit the ports a user may bind to by creating
/etc/systemd/system/user-1000.slice.d/user-resources.conf
with
[Slice]
SocketBindAllow = 12345
SocketBindDeny = any
Now as expected, the user cannot bind to port 20202 for example:
$ nc -4 -lp 20202
Ncat: bind to 0.0.0.0:20202: Operation not permitted. QUITTING.
However what bothers me is that it's not even possible to bind to a denied port *within* a container without exposing the port:
$ podman run docker.io/library/alpine nc -lp 20202
nc: bind: Operation not permitted
Is this a bug? Is there anything I can do about it?
Gamification
(231 rep)
Dec 7, 2023, 10:02 AM
1
votes
0
answers
273
views
eBPF vs verified Linux Kernel Modules
In what way is eBPF superior to a kernel module verified on the user-side? I'm not disputing the value of verified code; both approaches would be fully statically verified. Both approaches require capabilities usually only given to privileged users. However, running the verifier in user-space gives...
In what way is eBPF superior to a kernel module verified on the user-side?
I'm not disputing the value of verified code; both approaches would be fully statically verified.
Both approaches require capabilities usually only given to privileged users.
However, running the verifier in user-space gives the user more choices between verifiers, safety-levels, and permissible assumptions. The verifier can also be more rapidly developed separately from the kernel.
---
**Things I read before asking this question**:
- I found [this hackernews thread](https://news.ycombinator.com/item?id=14726311) , which only says that _some_ limited eBPF filters do not need privilege, but I understand most eBPF applications still will require privilege?
- I found [this page](https://github.com/nyrahul/ebpf-guide/blob/master/docs/ebpf_vs_kernmod.rst) , which claims
> Kernel modules have a specific entry point (init_module()) and exit (cleanup_module()) point. eBPF can be hooked to any kprobe/kretprobe/tracepoint and thus can be used for tracing
Contrary to the previous quote, it seems kprobe/kretprobe/tracepoints can be hooked (aka registered) from loadable kernel modules according to Linux documentation on [kprobes/kretprobes](https://docs.kernel.org/trace/kprobes.html) and [tracepoints](https://docs.kernel.org/trace/tracepoints.html) .
- [This page](https://github.com/nyrahul/ebpf-guide/blob/master/docs/ebpf_vs_kernmod.rst) also claims that eBPF cannot be pre-empted and kernel modules can. Whenever I Google anything about the Linux kernel preempting module code, they always talk about pre-emptying user-space never kernel-space. I don't know what it means that the "Kernel module follows regular kernel code preemption logic" but on the other hand "eBPF instruction-set execution cannot be preempted by kernel".
charmoniumQ
(255 rep)
Sep 28, 2023, 04:21 PM
• Last activity: Sep 28, 2023, 04:32 PM
1
votes
1
answers
918
views
Redirect port using TC BPF
I'm want to use `TC BPF` to redirect incoming traffic from port `80` to port `8080`. Below is my own code, but I've also tried the example from [man 8 tc-bpf](https://man7.org/linux/man-pages/man8/tc-bpf.8.html) (search for `8080`) and I get the same result. ``` #include #include #include #include #...
I'm want to use
TC BPF
to redirect incoming traffic from port 80
to port 8080
.
Below is my own code, but I've also tried the example from [man 8 tc-bpf](https://man7.org/linux/man-pages/man8/tc-bpf.8.html) (search for 8080
) and I get the same result.
#include
#include
#include
#include
#include
#include
#include
#include
#include
static inline void set_tcp_dport(struct __sk_buff *skb, int nh_off,
__u16 old_port, __u16 new_port)
{
bpf_l4_csum_replace(skb, nh_off + offsetof(struct tcphdr, check),
old_port, new_port, sizeof(new_port));
bpf_skb_store_bytes(skb, nh_off + offsetof(struct tcphdr, dest),
&new_port, sizeof(new_port), 0);
}
SEC("tc_my")
int tc_bpf_my(struct __sk_buff *skb)
{
struct iphdr ip;
struct tcphdr tcp;
if (0 != bpf_skb_load_bytes(skb, sizeof(struct ethhdr), &ip, sizeof(struct iphdr))) {
bpf_printk("bpf_skb_load_bytes iph failed");
return TC_ACT_OK;
}
if (0 != bpf_skb_load_bytes(skb, sizeof(struct ethhdr) + (ip.ihl %pI4:%u", &ip.saddr, src_port, &ip.daddr, dst_port);
if (dst_port != 80)
return TC_ACT_OK;
set_tcp_dport(skb, ETH_HLEN + sizeof(struct iphdr), __constant_htons(80), __constant_htons(8080));
return TC_ACT_OK;
}
char LICENSE[] SEC("license") = "GPL";
On machine A, I am running:
clang -g -O2 -Wall -target bpf -c tc_my.c -o tc_my.o
tc qdisc add dev ens160 clsact
tc filter add dev ens160 ingress bpf da obj tc_my.o sec tc_my
nc -l 8080
On machine B:
nc $IP_A 80
On machine B, nc
seems connected, but ss
shows:
SYN-SENT 0 1 $IP_B:53442 $IP_A:80 users:(("nc",pid=30180,fd=3))
On machine A, connection remains in SYN-RECV
before being dropped.
I was expecting my program to behave as if I added this iptables
rule:
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-port 8080
Maybe my expectations are wrong, but I would like to understand why. How can I get my TC BPF
redirect to work?
SOLUTION
-----------------
Following the explanation in my accepted answer, here is an example code which works for TCP, does ingress NAT 90->8080, and egress de-NAT 8080->90.
#include
#include
#include
#include
#include
#include
#include
#include
#include
static inline void set_tcp_dport(struct __sk_buff *skb, int nh_off,
__u16 old_port, __u16 new_port)
{
bpf_l4_csum_replace(skb, nh_off + offsetof(struct tcphdr, check),
old_port, new_port, sizeof(new_port));
bpf_skb_store_bytes(skb, nh_off + offsetof(struct tcphdr, dest),
&new_port, sizeof(new_port), 0);
}
static inline void set_tcp_sport(struct __sk_buff *skb, int nh_off,
__u16 old_port, __u16 new_port)
{
bpf_l4_csum_replace(skb, nh_off + offsetof(struct tcphdr, check),
old_port, new_port, sizeof(new_port));
bpf_skb_store_bytes(skb, nh_off + offsetof(struct tcphdr, source),
&new_port, sizeof(new_port), 0);
}
SEC("tc_ingress")
int tc_ingress_(struct __sk_buff *skb)
{
struct iphdr ip;
struct tcphdr tcp;
if (0 != bpf_skb_load_bytes(skb, sizeof(struct ethhdr), &ip, sizeof(struct iphdr)))
{
bpf_printk("bpf_skb_load_bytes iph failed");
return TC_ACT_OK;
}
if (0 != bpf_skb_load_bytes(skb, sizeof(struct ethhdr) + (ip.ihl %pI4:%u", &ip.saddr, src_port, &ip.daddr, dst_port);
if (dst_port != 90)
return TC_ACT_OK;
set_tcp_dport(skb, ETH_HLEN + sizeof(struct iphdr), __constant_htons(90), __constant_htons(8080));
return TC_ACT_OK;
}
SEC("tc_egress")
int tc_egress_(struct __sk_buff *skb)
{
struct iphdr ip;
struct tcphdr tcp;
if (0 != bpf_skb_load_bytes(skb, sizeof(struct ethhdr), &ip, sizeof(struct iphdr)))
{
bpf_printk("bpf_skb_load_bytes iph failed");
return TC_ACT_OK;
}
if (0 != bpf_skb_load_bytes(skb, sizeof(struct ethhdr) + (ip.ihl %pI4:%u", &ip.saddr, src_port, &ip.daddr, dst_port);
if (src_port != 8080)
return TC_ACT_OK;
set_tcp_sport(skb, ETH_HLEN + sizeof(struct iphdr), __constant_htons(8080), __constant_htons(90));
return TC_ACT_OK;
}
char LICENSE[] SEC("license") = "GPL";
Here is how I build and loaded the different sections in my program:
clang -g -O2 -Wall -target bpf -c tc_my.c -o tc_my.o
tc filter add dev ens32 ingress bpf da obj /tc_my.o sec tc_ingress
tc filter add dev ens32 egress bpf da obj /tc_my.o sec tc_egress
greenro
(13 rep)
Sep 14, 2023, 01:04 PM
• Last activity: Sep 15, 2023, 09:25 AM
10
votes
2
answers
4705
views
Understanding of BPF
When I need to capture some packets using `tcpdump`, I use command like: ``` tcpdump -i eth0 "dst host 192.168.1.0" ``` I always think the *dst host 192.168.1.0* part is something called BPF, Berkeley Packet Filter. To me, it's a simple language to filter network packets. But today my roommate tells...
When I need to capture some packets using
tcpdump
, I use command like:
tcpdump -i eth0 "dst host 192.168.1.0"
I always think the *dst host 192.168.1.0* part is something called BPF, Berkeley Packet Filter. To me, it's a simple language to filter network packets. But today my roommate tells me that BPF can be used to capture performance info. According to his description, it's like the tool perfmon
on Windows. Is it true? Is it the same BPF as I mentioned in the beginning of the question?
Fajela Tajkiya
(1065 rep)
Apr 18, 2022, 10:07 PM
• Last activity: Sep 1, 2023, 10:17 AM
1
votes
1
answers
797
views
Log all commands executed regardless of shell?
Suppose a user runs the following command: zcat file.gz | grep something | gzip > grepped.gz I'm looking for a kernel feature (a BPF filter perhaps?) that would note all of the `execve`s, chain together their stdins/stdouts and reconstruct that in a similar form, putting it into system logs. Is ther...
Suppose a user runs the following command:
zcat file.gz | grep something | gzip > grepped.gz
I'm looking for a kernel feature (a BPF filter perhaps?) that would note all of the
execve
s, chain together their stdins/stdouts and reconstruct that in a similar form, putting it into system logs. Is there a way to do that without interfacing with the shells?
d33tah
(1381 rep)
May 10, 2023, 10:45 AM
• Last activity: May 10, 2023, 06:21 PM
1
votes
1
answers
161
views
DPROBES (DTRACE_PROBE) for measuring high latency stuff under 1µsec
Currently, I'm analyzing the performance of a high latency application but I'm not confident in my measurements at all. So far, I have used `DPROBES` for instrumentation and [BCC/funclatency][1] for measuring. Would someone be able to verify those numbers? Also, if someone knows of a better method,...
Currently, I'm analyzing the performance of a high latency application but I'm not confident in my measurements at all. So far, I have used
DPROBES
for instrumentation and BCC/funclatency for measuring.
Would someone be able to verify those numbers? Also, if someone knows of a better method, please let me know.
measuring usleep(1)
: avg = 53962 nsecs
#include
#include
int main() {
int i;
for(i=0; i
int main() {
int i;
for(i=0; i
#include
#include
#include
int main() {
struct timespec tim, tim2;
tim.tv_sec = 0;
tim.tv_nsec = 200L;
int i;
for (i=0; i<100000; i++){
DTRACE_PROBE("hello-usdt", probe-main-start);
if(nanosleep(&tim , &tim2) < 0 ){
printf("Nano sleep system call failed \n");
return -1;
}
DTRACE_PROBE("hello-usdt", probe-main-end);
}
printf("Nano sleep successfull \n");
return 0;
}
A little modification was made to the funclatency
code:
# attach probes
usdt = USDT(path = "path to application")
usdt.enable_probe(probe = "probe-main-start", fn_name = "trace_func_entry")
usdt.enable_probe(probe = "probe-main-end", fn_name = "trace_func_return")
b = BPF(text = bpf_text, usdt_contexts = [usdt])
Am I unable to measure anything below 0.8usec with this method?
Furthermore I cannot believe that nanosleep(200)
"oversleep" by 50 usec.
Bahamas
(113 rep)
Jan 28, 2023, 02:31 PM
• Last activity: Jan 31, 2023, 09:30 PM
2
votes
2
answers
814
views
What are the limitations of eBPF feature-wise?
I understood it is mainly used for observability (ie read-only). I saw you can route packets, but can you do more than that? Can you also manipulate the file system, send signals and write from an eBPF program?
I understood it is mainly used for observability (ie read-only).
I saw you can route packets, but can you do more than that?
Can you also manipulate the file system, send signals and write from an eBPF program?
funerr
(123 rep)
Sep 27, 2022, 10:48 PM
• Last activity: Sep 28, 2022, 09:24 AM
Showing page 1 of 20 total questions