-1

I am trying to record TCP flows - if new, create an entry into a hash map with the 5-tuple as the key and then push out a new flow event (identified by SYN flag).

The problem I encounter is with the function bpf_map_update_elem(). When I use this function, all the member values of the structures are rendered as zero. However, when I disable this function (do not add new flows in the hash map), the values of the member variables are as expected.

struct flow_state
{
    __u64 t_start;
    __u64 t_end;
    struct network_tuple network_tuple;
};

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __type(key, struct network_tuple);
    __type(value, struct flow_state);
    __uint(max_entries, 16384);
} flow_state_map SEC(".maps");


static __always_inline int
update_flow_state(struct pkt_info *pkt, __u32 flow_status)
{
    // bpf_printk("flow last seq2: %llu", pkt->tcp_seq);
    // bpf_printk("dport121: %d", bpf_ntohs(pkt->network_tuple.dport));
    if (FLOW_START == flow_status)
    {
        bpf_printk("|updateFlow|sport: %d|dport: %d|seq: %llu",
                    bpf_ntohs(pkt->network_tuple.sport), 
                    bpf_ntohs(pkt->network_tuple.dport),
                    bpf_ntohl(pkt->tcp_seq));

        struct flow_state flow_state = { 0 };
        flow_state.t_start = bpf_ktime_get_ns();
        flow_state.t_last_pkt = flow_state.t_start;


        // network tuple is the flow id
        // bpf_printk("dport133: %d", bpf_ntohs(pkt->network_tuple.dport));
        flow_state.network_tuple.saddr[0] = pkt->network_tuple.saddr[0];
        flow_state.network_tuple.daddr[0] = pkt->network_tuple.daddr[0];
        flow_state.network_tuple.sport = pkt->network_tuple.sport;
        flow_state.network_tuple.dport = pkt->network_tuple.dport;
        flow_state.network_tuple.l4_proto = pkt->network_tuple.l4_proto;
        bpf_printk("|updateFlow|sport: %d|dport: %d",
                    bpf_ntohs(flow_state.network_tuple.sport), 
                    bpf_ntohs(flow_state.network_tuple.dport)
                    );
        // Adding the key in the map is causing the problem. When disabled, program runs as expected
        bpf_map_update_elem(&flow_state_map, &pkt->network_tuple, &flow_state, BPF_NOEXIST);
   }
}

static __always_inline int
output_syn_event(struct pkt_info *pkt)
{
    struct syn_event *syn_event = { 0 };
    syn_event = bpf_ringbuf_reserve(&rb, sizeof(*syn_event), 0);
    if (!syn_event) 
    {
        bpf_printk("ringbuffer not reserved!\n");
        return -1;
    }
    
    syn_event->event_type = EVENT_TYPE_NEW_FLOW_TCP;
   // fill up other members of syn_event struct
    
    bpf_printk("|SYN|sport: %d|dport: %d|seq: %llu",
                    bpf_ntohs(pkt->network_tuple.sport), 
                    bpf_ntohs(pkt->network_tuple.dport),
                    bpf_ntohl(pkt->tcp_seq));

    bpf_ringbuf_submit(syn_event, 0);
    
    return 0;
}

static __always_inline struct pkt_info *
extract_pkt_details(struct sk_buff *skb, __u16 probe_idx)
{
// ... extracting the packet details
}

static __always_inline int 
trace_skb(struct sk_buff *skb)
{
    struct pkt_info *pkt = extract_pkt_details(skb, probe_idx);
    // all the pkt details are received correctly at this point 

    if (pkt->network_tuple.l4_proto == IPPROTO_TCP)
    {
      
        if (!bpf_map_lookup_elem(&flow_state_map, &pkt->network_tuple) && pkt->syn && !pkt->ack)
        {
            update_flow_state(pkt, FLOW_START);
            output_syn_event(pkt);   
        }
    }
    return 0;
}

Console output when the function bpf_map_update_elem() is used in function update_flow_state()

          <idle>-0       [005] dNs.1 4596129.654890: bpf_trace_printk: |updateFlow|sport: 43802|dport: 8080|seq: 3135364954
          <idle>-0       [005] dNs.1 4596129.654891: bpf_trace_printk: |updateFlow|sport: 0|dport: 0
          <idle>-0       [005] dNs.1 4596129.654892: bpf_trace_printk: |SYN|sport: 0|dport: 0|seq: 0

Console output when the function bpf_map_update_elem() is NOT used in function update_flow_state()

          <idle>-0       [005] d.s.1 4596188.487842: bpf_trace_printk: |updateFlow|sport: 49278|dport: 8080|seq: 502719687
          <idle>-0       [005] d.s.1 4596188.487843: bpf_trace_printk: |updateFlow|sport: 49278|dport: 8080
          <idle>-0       [005] d.s.1 4596188.487844: bpf_trace_printk: |SYN|sport: 49278|dport: 8080|seq: 502719687

I am not able to find out where I am going wrong! Any ideas?

0 Answers0