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