github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/examples/xdp/xdp.c (about)

     1  //go:build ignore
     2  
     3  #include "bpf_endian.h"
     4  #include "common.h"
     5  
     6  char __license[] SEC("license") = "Dual MIT/GPL";
     7  
     8  #define MAX_MAP_ENTRIES 16
     9  
    10  /* Define an LRU hash map for storing packet count by source IPv4 address */
    11  struct {
    12  	__uint(type, BPF_MAP_TYPE_LRU_HASH);
    13  	__uint(max_entries, MAX_MAP_ENTRIES);
    14  	__type(key, __u32); // source IPv4 address
    15  	__type(value, __u32); // packet count
    16  } xdp_stats_map SEC(".maps");
    17  
    18  /*
    19  Attempt to parse the IPv4 source address from the packet.
    20  Returns 0 if there is no IPv4 header field; otherwise returns non-zero.
    21  */
    22  static __always_inline int parse_ip_src_addr(struct xdp_md *ctx, __u32 *ip_src_addr) {
    23  	void *data_end = (void *)(long)ctx->data_end;
    24  	void *data     = (void *)(long)ctx->data;
    25  
    26  	// First, parse the ethernet header.
    27  	struct ethhdr *eth = data;
    28  	if ((void *)(eth + 1) > data_end) {
    29  		return 0;
    30  	}
    31  
    32  	if (eth->h_proto != bpf_htons(ETH_P_IP)) {
    33  		// The protocol is not IPv4, so we can't parse an IPv4 source address.
    34  		return 0;
    35  	}
    36  
    37  	// Then parse the IP header.
    38  	struct iphdr *ip = (void *)(eth + 1);
    39  	if ((void *)(ip + 1) > data_end) {
    40  		return 0;
    41  	}
    42  
    43  	// Return the source IP address in network byte order.
    44  	*ip_src_addr = (__u32)(ip->saddr);
    45  	return 1;
    46  }
    47  
    48  SEC("xdp")
    49  int xdp_prog_func(struct xdp_md *ctx) {
    50  	__u32 ip;
    51  	if (!parse_ip_src_addr(ctx, &ip)) {
    52  		// Not an IPv4 packet, so don't count it.
    53  		goto done;
    54  	}
    55  
    56  	__u32 *pkt_count = bpf_map_lookup_elem(&xdp_stats_map, &ip);
    57  	if (!pkt_count) {
    58  		// No entry in the map for this IP address yet, so set the initial value to 1.
    59  		__u32 init_pkt_count = 1;
    60  		bpf_map_update_elem(&xdp_stats_map, &ip, &init_pkt_count, BPF_ANY);
    61  	} else {
    62  		// Entry already exists for this IP address,
    63  		// so increment it atomically using an LLVM built-in.
    64  		__sync_fetch_and_add(pkt_count, 1);
    65  	}
    66  
    67  done:
    68  	// Try changing this to XDP_DROP and see what happens!
    69  	return XDP_PASS;
    70  }