eBPF: Tail calls (Part-1)
Objective
- to understand performing tail-calls in eBPF
 
Reasoning
In order to perform tail calls, we need to
- declare 
prototype of funcs to call 
- declare map: 
prog_array map with key=u32, values=signature_of_funcs  
- fill map:
- can be done in userspace as well in kernelspace
 
 
- use 
bpf_tail_call to redirect flow to func of interest 
Code
| programs.h | 
|---|
 | #include "maps.h" hl_lines="13 14"
// Called function
SEC("cgroup_skb/egress")
long egress2(struct __sk_buff* ctx){
    bpf_printk("[egress2] Someone called me");
    return SK_PASS;
}
// Initial function
SEC("cgroup_skb/egress")
long egress1(struct __sk_buff* ctx){
    bpf_printk("[egress1] Calling egress2");
    bpf_tail_call(ctx, &tail_programs, TAIL_CALL_EGRESS_2)
    return SK_PASS;
}
  | 
 
| maps.h | 
|---|
 | // declare the index in array to use for tail-called function
#define TAIL_CALL_EGRESS_2 0 
// declare the prototype of function to be stored
long egress2(struct __sk_buff* ctx);
// create map & initialize values
struct {
    __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
    __uint(max_entries, 1);
    __type(key, __u32);
    __array(values, long(struct __sk_buff* ctx)); // signature of function
} tail_programs SEC(".maps") = {
    .values = {
        [TAIL_CALL_EGRESS_2] = (void *)&egress2, // filling values
    },
};  
  | 
 
Observations
- same-cpu: callee function is executed by same-cpu
 
- same-context: caller and callee must have same ctx i.e program of same type
 
- no-new-stack: callee uses caller's stack
 
- no-return: callee doesn't returns to caller
 
Refer