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_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};
  26struct bpf_map_def SEC("maps") config_map = {
  27        .type           = BPF_MAP_TYPE_ARRAY,
  28        .key_size       = sizeof(int),
  29        .value_size     = sizeof(struct config),
  30        .max_entries    = 1,
  31};
  32
  33/* Common stats data record (shared with userspace) */
  34struct datarec {
  35        __u64 processed;
  36        __u64 issue;
  37};
  38
  39struct bpf_map_def SEC("maps") stats_global_map = {
  40        .type           = BPF_MAP_TYPE_PERCPU_ARRAY,
  41        .key_size       = sizeof(u32),
  42        .value_size     = sizeof(struct datarec),
  43        .max_entries    = 1,
  44};
  45
  46#define MAX_RXQs 64
  47
  48/* Stats per rx_queue_index (per CPU) */
  49struct bpf_map_def SEC("maps") rx_queue_index_map = {
  50        .type           = BPF_MAP_TYPE_PERCPU_ARRAY,
  51        .key_size       = sizeof(u32),
  52        .value_size     = sizeof(struct datarec),
  53        .max_entries    = MAX_RXQs + 1,
  54};
  55
  56static __always_inline
  57void swap_src_dst_mac(void *data)
  58{
  59        unsigned short *p = data;
  60        unsigned short dst[3];
  61
  62        dst[0] = p[0];
  63        dst[1] = p[1];
  64        dst[2] = p[2];
  65        p[0] = p[3];
  66        p[1] = p[4];
  67        p[2] = p[5];
  68        p[3] = dst[0];
  69        p[4] = dst[1];
  70        p[5] = dst[2];
  71}
  72
  73SEC("xdp_prog0")
  74int  xdp_prognum0(struct xdp_md *ctx)
  75{
  76        void *data_end = (void *)(long)ctx->data_end;
  77        void *data     = (void *)(long)ctx->data;
  78        struct datarec *rec, *rxq_rec;
  79        int ingress_ifindex;
  80        struct config *config;
  81        u32 key = 0;
  82
  83        /* Global stats record */
  84        rec = bpf_map_lookup_elem(&stats_global_map, &key);
  85        if (!rec)
  86                return XDP_ABORTED;
  87        rec->processed++;
  88
  89        /* Accessing ctx->ingress_ifindex, cause BPF to rewrite BPF
  90         * instructions inside kernel to access xdp_rxq->dev->ifindex
  91         */
  92        ingress_ifindex = ctx->ingress_ifindex;
  93
  94        config = bpf_map_lookup_elem(&config_map, &key);
  95        if (!config)
  96                return XDP_ABORTED;
  97
  98        /* Simple test: check ctx provided ifindex is as expected */
  99        if (ingress_ifindex != config->ifindex) {
 100                /* count this error case */
 101                rec->issue++;
 102                return XDP_ABORTED;
 103        }
 104
 105        /* Update stats per rx_queue_index. Handle if rx_queue_index
 106         * is larger than stats map can contain info for.
 107         */
 108        key = ctx->rx_queue_index;
 109        if (key >= MAX_RXQs)
 110                key = MAX_RXQs;
 111        rxq_rec = bpf_map_lookup_elem(&rx_queue_index_map, &key);
 112        if (!rxq_rec)
 113                return XDP_ABORTED;
 114        rxq_rec->processed++;
 115        if (key == MAX_RXQs)
 116                rxq_rec->issue++;
 117
 118        /* Default: Don't touch packet data, only count packets */
 119        if (unlikely(config->options & (READ_MEM|SWAP_MAC))) {
 120                struct ethhdr *eth = data;
 121
 122                if (eth + 1 > data_end)
 123                        return XDP_ABORTED;
 124
 125                /* Avoid compiler removing this: Drop non 802.3 Ethertypes */
 126                if (ntohs(eth->h_proto) < ETH_P_802_3_MIN)
 127                        return XDP_ABORTED;
 128
 129                /* XDP_TX requires changing MAC-addrs, else HW may drop.
 130                 * Can also be enabled with --swapmac (for test purposes)
 131                 */
 132                if (unlikely(config->options & SWAP_MAC))
 133                        swap_src_dst_mac(data);
 134        }
 135
 136        return config->action;
 137}
 138
 139char _license[] SEC("license") = "GPL";
 140