xdp_rxq_info_kern.c (3231B)
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";