| 12
 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
 
 | /* 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_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 bpf_map_def SEC("maps") config_map = {
	.type		= BPF_MAP_TYPE_ARRAY,
	.key_size	= sizeof(int),
	.value_size	= sizeof(struct config),
	.max_entries	= 1,
};
/* Common stats data record (shared with userspace) */
struct datarec {
	__u64 processed;
	__u64 issue;
};
struct bpf_map_def SEC("maps") stats_global_map = {
	.type		= BPF_MAP_TYPE_PERCPU_ARRAY,
	.key_size	= sizeof(u32),
	.value_size	= sizeof(struct datarec),
	.max_entries	= 1,
};
#define MAX_RXQs 64
/* Stats per rx_queue_index (per CPU) */
struct bpf_map_def SEC("maps") rx_queue_index_map = {
	.type		= BPF_MAP_TYPE_PERCPU_ARRAY,
	.key_size	= sizeof(u32),
	.value_size	= sizeof(struct datarec),
	.max_entries	= MAX_RXQs + 1,
};
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";
 |