github.com/dylandreimerink/gobpfld@v0.6.1-0.20220205171531-e79c330ad608/cmd/testsuite/integration/ebpf/xdp_stats_test.c (about)

     1  /* SPDX-License-Identifier: GPL-2.0 */
     2  #include <linux/bpf.h>
     3  
     4  /*
     5   * bpf_map_lookup_elem
     6   *
     7   * 	Perform a lookup in *map* for an entry associated to *key*.
     8   *
     9   * Returns
    10   * 	Map value associated to *key*, or **NULL** if no entry was
    11   * 	found.
    12   */
    13  static void *(*bpf_map_lookup_elem)(void *map, const void *key) = (void *) 1;
    14  
    15  #define SEC(NAME) __attribute__((section(NAME), used))
    16  
    17  struct bpf_map_def {
    18  	unsigned int type;
    19  	unsigned int key_size;
    20  	unsigned int value_size;
    21  	unsigned int max_entries;
    22  	unsigned int map_flags;
    23  };
    24  
    25  
    26  /* This is the data record stored in the map */
    27  struct datarec {
    28  	__u64 rx_packets;
    29  	/* Assignment#1: Add byte counters */
    30  };
    31  
    32  /* Lesson#1: See how a map is defined.
    33   * - Here an array with XDP_ACTION_MAX (max_)entries are created.
    34   * - The idea is to keep stats per (enum) xdp_action
    35   */
    36  struct bpf_map_def SEC("maps") xdp_stats_map = {
    37  	.type        = BPF_MAP_TYPE_ARRAY,
    38  	.key_size    = sizeof(__u32),
    39  	.value_size  = sizeof(struct datarec),
    40  	.max_entries = XDP_REDIRECT+1,
    41  };
    42  
    43  /* LLVM maps __sync_fetch_and_add() as a built-in function to the BPF atomic add
    44   * instruction (that is BPF_STX | BPF_XADD | BPF_W for word sizes)
    45   */
    46  #ifndef lock_xadd
    47  #define lock_xadd(ptr, val)	((void) __sync_fetch_and_add(ptr, val))
    48  #endif
    49  
    50  SEC("xdp")
    51  int  xdp_stats1_func(struct xdp_md *ctx)
    52  {
    53  	// void *data_end = (void *)(long)ctx->data_end;
    54  	// void *data     = (void *)(long)ctx->data;
    55  	struct datarec *rec;
    56  	__u32 key = XDP_PASS; /* XDP_PASS = 2 */
    57  
    58  	/* Lookup in kernel BPF-side return pointer to actual data record */
    59  	rec = bpf_map_lookup_elem(&xdp_stats_map, &key);
    60  	/* BPF kernel-side verifier will reject program if the NULL pointer
    61  	 * check isn't performed here. Even-though this is a static array where
    62  	 * we know key lookup XDP_PASS always will succeed.
    63  	 */
    64  	if (!rec)
    65  		return XDP_ABORTED;
    66  
    67  	/* Multiple CPUs can access data record. Thus, the accounting needs to
    68  	 * use an atomic operation.
    69  	 */
    70  	lock_xadd(&rec->rx_packets, 1);
    71          /* Assignment#1: Add byte counters
    72           * - Hint look at struct xdp_md *ctx (copied below)
    73           *
    74           * Assignment#3: Avoid the atomic operation
    75           * - Hint there is a map type named BPF_MAP_TYPE_PERCPU_ARRAY
    76           */
    77  
    78  	return XDP_PASS;
    79  }
    80  
    81  char _license[] SEC("license") = "GPL";
    82  
    83  /* Copied from: $KERNEL/include/uapi/linux/bpf.h
    84   *
    85   * User return codes for XDP prog type.
    86   * A valid XDP program must return one of these defined values. All other
    87   * return codes are reserved for future use. Unknown return codes will
    88   * result in packet drops and a warning via bpf_warn_invalid_xdp_action().
    89   *
    90  enum xdp_action {
    91  	XDP_ABORTED = 0,
    92  	XDP_DROP,
    93  	XDP_PASS,
    94  	XDP_TX,
    95  	XDP_REDIRECT,
    96  };
    97  
    98   * user accessible metadata for XDP packet hook
    99   * new fields must be added to the end of this structure
   100   *
   101  struct xdp_md {
   102  	// (Note: type __u32 is NOT the real-type)
   103  	__u32 data;
   104  	__u32 data_end;
   105  	__u32 data_meta;
   106  	// Below access go through struct xdp_rxq_info
   107  	__u32 ingress_ifindex; // rxq->dev->ifindex
   108  	__u32 rx_queue_index;  // rxq->queue_index
   109  };
   110  */