linux/samples/bpf/xdp_rxq_info_kern.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0
   2 * Copyright (c) 2017 Jesper Dangaard Brouer, Red Hat Inc.
   3 *
   4 *  Example howto extract XDP RX-queue info
   5 */
   6#include <uapi/linux/bpf.h>
   7#include <uapi/linux/if_ether.h>
   8#include <uapi/linux/in.h>
   9#include <bpf/bpf_helpers.h>
  10
  11/* Config setup from with userspace
  12 *
  13 * User-side setup ifindex in config_map, to verify that
  14 * ctx->ingress_ifindex is correct (against configured ifindex)
  15 */
  16struct config {
  17        __u32 action;
  18        int ifindex;
  19        __u32 options;
  20};
  21enum cfg_options_flags {
  22        NO_TOUCH = 0x0U,
  23        READ_MEM = 0x1U,
  24        SWAP_MAC = 0x2U,
  25};
  26
  27struct {
  28        __uint(type, BPF_MAP_TYPE_ARRAY);
  29        __type(key, int);
  30        __type(value, struct config);
  31        __uint(max_entries, 1);
  32} config_map SEC(".maps");
  33
  34/* Common stats data record (shared with userspace) */
  35struct datarec {
  36        __u64 processed;
  37        __u64 issue;
  38};
  39
  40struct {
  41        __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
  42        __type(key, u32);
  43        __type(value, struct datarec);
  44        __uint(max_entries, 1);
  45} stats_global_map SEC(".maps");
  46
  47#define MAX_RXQs 64
  48
  49/* Stats per rx_queue_index (per CPU) */
  50struct {
  51        __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
  52        __type(key, u32);
  53        __type(value, struct datarec);
  54        __uint(max_entries, MAX_RXQs + 1);
  55} rx_queue_index_map SEC(".maps");
  56
  57static __always_inline
  58void swap_src_dst_mac(void *data)
  59{
  60        unsigned short *p = data;
  61        unsigned short dst[3];
  62
  63        dst[0] = p[0];
  64        dst[1] = p[1];
  65        dst[2] = p[2];
  66        p[0] = p[3];
  67        p[1] = p[4];
  68        p[2] = p[5];
  69        p[3] = dst[0];
  70        p[4] = dst[1];
  71        p[5] = dst[2];
  72}
  73
  74SEC("xdp_prog0")
  75int  xdp_prognum0(struct xdp_md *ctx)
  76{
  77        void *data_end = (void *)(long)ctx->data_end;
  78        void *data     = (void *)(long)ctx->data;
  79        struct datarec *rec, *rxq_rec;
  80        int ingress_ifindex;
  81        struct config *config;
  82        u32 key = 0;
  83
  84        /* Global stats record */
  85        rec = bpf_map_lookup_elem(&stats_global_map, &key);
  86        if (!rec)
  87                return XDP_ABORTED;
  88        rec->processed++;
  89
  90        /* Accessing ctx->ingress_ifindex, cause BPF to rewrite BPF
  91         * instructions inside kernel to access xdp_rxq->dev->ifindex
  92         */
  93        ingress_ifindex = ctx->ingress_ifindex;
  94
  95        config = bpf_map_lookup_elem(&config_map, &key);
  96        if (!config)
  97                return XDP_ABORTED;
  98
  99        /* Simple test: check ctx provided ifindex is as expected */
 100        if (ingress_ifindex != config->ifindex) {
 101                /* count this error case */
 102                rec->issue++;
 103                return XDP_ABORTED;
 104        }
 105
 106        /* Update stats per rx_queue_index. Handle if rx_queue_index
 107         * is larger than stats map can contain info for.
 108         */
 109        key = ctx->rx_queue_index;
 110        if (key >= MAX_RXQs)
 111                key = MAX_RXQs;
 112        rxq_rec = bpf_map_lookup_elem(&rx_queue_index_map, &key);
 113        if (!rxq_rec)
 114                return XDP_ABORTED;
 115        rxq_rec->processed++;
 116        if (key == MAX_RXQs)
 117                rxq_rec->issue++;
 118
 119        /* Default: Don't touch packet data, only count packets */
 120        if (unlikely(config->options & (READ_MEM|SWAP_MAC))) {
 121                struct ethhdr *eth = data;
 122
 123                if (eth + 1 > data_end)
 124                        return XDP_ABORTED;
 125
 126                /* Avoid compiler removing this: Drop non 802.3 Ethertypes */
 127                if (ntohs(eth->h_proto) < ETH_P_802_3_MIN)
 128                        return XDP_ABORTED;
 129
 130                /* XDP_TX requires changing MAC-addrs, else HW may drop.
 131                 * Can also be enabled with --swapmac (for test purposes)
 132                 */
 133                if (unlikely(config->options & SWAP_MAC))
 134                        swap_src_dst_mac(data);
 135        }
 136
 137        return config->action;
 138}
 139
 140char _license[] SEC("license") = "GPL";
 141