162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <vmlinux.h>
462306a36Sopenharmony_ci#include "xdp_metadata.h"
562306a36Sopenharmony_ci#include <bpf/bpf_helpers.h>
662306a36Sopenharmony_ci#include <bpf/bpf_endian.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_cistruct {
962306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_XSKMAP);
1062306a36Sopenharmony_ci	__uint(max_entries, 4);
1162306a36Sopenharmony_ci	__type(key, __u32);
1262306a36Sopenharmony_ci	__type(value, __u32);
1362306a36Sopenharmony_ci} xsk SEC(".maps");
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistruct {
1662306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
1762306a36Sopenharmony_ci	__uint(max_entries, 1);
1862306a36Sopenharmony_ci	__type(key, __u32);
1962306a36Sopenharmony_ci	__type(value, __u32);
2062306a36Sopenharmony_ci} prog_arr SEC(".maps");
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciextern int bpf_xdp_metadata_rx_timestamp(const struct xdp_md *ctx,
2362306a36Sopenharmony_ci					 __u64 *timestamp) __ksym;
2462306a36Sopenharmony_ciextern int bpf_xdp_metadata_rx_hash(const struct xdp_md *ctx, __u32 *hash,
2562306a36Sopenharmony_ci				    enum xdp_rss_hash_type *rss_type) __ksym;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciSEC("xdp")
2862306a36Sopenharmony_ciint rx(struct xdp_md *ctx)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	void *data, *data_meta;
3162306a36Sopenharmony_ci	struct xdp_meta *meta;
3262306a36Sopenharmony_ci	u64 timestamp = -1;
3362306a36Sopenharmony_ci	int ret;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/* Reserve enough for all custom metadata. */
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	ret = bpf_xdp_adjust_meta(ctx, -(int)sizeof(struct xdp_meta));
3862306a36Sopenharmony_ci	if (ret != 0)
3962306a36Sopenharmony_ci		return XDP_DROP;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	data = (void *)(long)ctx->data;
4262306a36Sopenharmony_ci	data_meta = (void *)(long)ctx->data_meta;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	if (data_meta + sizeof(struct xdp_meta) > data)
4562306a36Sopenharmony_ci		return XDP_DROP;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	meta = data_meta;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/* Export metadata. */
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/* We expect veth bpf_xdp_metadata_rx_timestamp to return 0 HW
5262306a36Sopenharmony_ci	 * timestamp, so put some non-zero value into AF_XDP frame for
5362306a36Sopenharmony_ci	 * the userspace.
5462306a36Sopenharmony_ci	 */
5562306a36Sopenharmony_ci	bpf_xdp_metadata_rx_timestamp(ctx, &timestamp);
5662306a36Sopenharmony_ci	if (timestamp == 0)
5762306a36Sopenharmony_ci		meta->rx_timestamp = 1;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	bpf_xdp_metadata_rx_hash(ctx, &meta->rx_hash, &meta->rx_hash_type);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	return bpf_redirect_map(&xsk, ctx->rx_queue_index, XDP_PASS);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cichar _license[] SEC("license") = "GPL";
65