I'm trying to generate delay in acknowledgement using eBPF kernel program for egress packet. I'm running the python+c program using bcc. i tried mdelay/msleep/udelay etc functions with delay.h library in c, it gives me LLVM error that "Program using external function which can't be resolved".
Then I tried implementing sleep functionality : Taking 3 variables: tprev (which get the current time at starting of prog) tnow(this gets current time as the loop starts and gets updates in each iteration with current time) timer: this is the duration for which we want program to be delayed. the while loop is: while((tnow - tprev) ≤ timer) but ebpf prog treat it as n infinite loop and gives error that infinite loop detected. Whereas it's not an infinite loop.
Is there a way to introduce delay in Ack or delay in general in eBPF program and How?
The short answer is no(not in eBPF). At least not as of kernel 5.18. This is because eBPF programs, particularly those running in the network stack are often called from code that should never sleep.
What perhaps is most useful in your case is that TC(Traffic Control) programs can ask TC to delay a packet for you. The actual delay happens outside of the eBPF program, in the TC subsystem. You can request TC to send the packet at a given time by setting
__sk_buff->tstamp
. Note: this only works for Egress(outgoing) traffic not Ingress(incomming) traffic. This behavior can also be triggered via TC configuration without using eBPF.Yes, you can't use the stdlib in eBPF programs since they use kernel facilities which are unavailable in eBPF.
Side notes:
We do have "sleepable" programs, but only syscall, LSM and tracing programs can be sleepable. "sleepable" doesn't mean we can call some sort of sleep helper with a duration, it means we can call helper functions which in turn may sleep(for example bpf_copy_from_user_stack). So you don't have control over how long the program will sleep.
Another time related feature is BPF timers, which actually allow you to set a timer and execute a callback after a given time. The limitation here is that you can't pass any arguments to this callback, and it is called without a context. So after setting the timer, the original program will continue and return as usual.