1

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)

  1. 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.

  2. Any solution of how all the 8 members can be defined in the struct flow_state_xdp?

  • Can you share a full reproduction program? I suspect the way `create_flow_state_xdp` is called matters here. – pchaigno Nov 30 '22 at 13:06
  • I have added the relevant code snippets showing the code flow. Please note that adding an additional new map and relevant structure solves the issues. But, the original question of why a single map cannot do the same job remains! – hundredmiles Nov 30 '22 at 15:36

0 Answers0