I am trying to collect simple flow level statistics using eBPF program.
I define a map as follows:
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, struct network_tuple_xdp);
__type(value, struct flow_state_xdp);
__uint(max_entries, 64);
} flow_state_xdp_map SEC(".maps");
UPDATE: adding a new additional map solves the error.
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, struct network_tuple_xdp);
__type(value, struct flow_state_xdp_2);
__uint(max_entries, 64);
} flow_state_xdp_map_2 SEC(".maps");
The structures used in the above map are defined as follows:
struct network_tuple_xdp
{
__u32 saddr;
__u32 daddr;
__u32 sport;
__u32 dport;
};
struct flow_state_xdp
{
__u32 flow_initialized;
__u32 seq_num_curr;
__u32 seq_num_prev;
__u32 rto_count;
__u32 tsval;
__u32 tsecr;
__u32 flow_size;
__u32 fct;
};
UPDATE: Structure for the new map. If you use this structure, then comment out the last 4 members in the struct flow_state_xdp
struct flow_state_xdp_2
{
__u32 tsval;
__u32 tsecr;
__u32 flow_size;
__u32 fct;
};
I initialize the members of the structures in the following function:
static struct flow_state_xdp *
create_flow_state_xdp(struct xdp_md *ctx,
struct packet_info *p_info,
struct network_tuple_xdp *key)
{
struct flow_state_xdp flow_state = {
.seq_num_prev = 0,
.seq_num_curr = p_info->seq_num,
.flow_initialized = 0,
.rto_count = 0,
.tsval = 0,
.tsecr = 0,
.flow_size = 0,
.fct = 0,
};
if (bpf_map_update_elem(&flow_state_xdp_map, key, &flow_state,
BPF_NOEXIST) < 0)
{
send_map_full_event(ctx, p_info, XMAP_FLOWSTATE);
return NULL;
}
return bpf_map_lookup_elem(&flow_state_xdp_map, key);
}
static struct flow_state_xdp *
create_flow_state_xdp_2(struct xdp_md *ctx,
struct packet_info *p_info,
struct network_tuple_xdp *key)
{ // same as above function with updated names of variables accordingly}
UPDATE: How create_flow_state_xdp
is called...
static void packet_event_xdp(struct xdp_md *ctx,
struct packet_info *p_info,
struct network_tuple_xdp *key)
{
struct flow_state_xdp *flow_stats =
bpf_map_lookup_elem(&flow_state_xdp_map, key);
// exclude this statement to reproduce the error
struct flow_state_xdp_2 *flow_stats2 =
bpf_map_lookup_elem(&flow_state_xdp_map_2, key);
if (flow_stats)
{ // some operations if the key (flow tuple) for the flow exists }
else // create new entry for flow
{
flow_stats = create_flow_state_xdp(ctx, p_info, key);
// exclude this statement to reproduce the error
flow_stats2 = create_flow_state_xdp_2(ctx, p_info, key);
}
}
static void prog_xdp(struct xdp_md *ctx)
{
struct packet_info p_info = { 0 };
struct network_tuple_xdp *key = get_flow_key_from_packet_xdp(ctx, &p_info);
packet_event_xdp(ctx, &p_info, key);
}
SEC("xdp")
int xdp_ingress(struct xdp_md *ctx)
{
prog_xdp(ctx);
return XDP_PASS;
}
However, the program is not loaded due to the following error of combined stack size too large
as mentioned below:
libbpf: prog 'prog_xdp_ingress': BPF program load failed: Permission denied
libbpf: prog 'prog_xdp_ingress': -- BEGIN PROG LOAD LOG --
combined stack size of 2 calls is 544. Too large
processed 192213 insns (limit 1000000) max_states_per_insn 31 total_states 12609 peak_states 1056 mark_read 41
-- END PROG LOAD LOG --
This error does not happen when there are 4 members in struct flow_state_xdp
(seq_num_prev
, seq_num_curr
, flow_initialized
and rto_count
)
Could some explain what causes the error of combined stack size? Considering limitation of stack size, I tried with
BPF_MAP_TYPE_PERCPU_HASH
too but get the same error. Also, I make sure that the alignment of the whole structure is a multiple of 8 bytes.Any solution of how all the 8 members can be defined in the
struct flow_state_xdp
?