18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci * Copyright (c) 2018 Jesper Dangaard Brouer, Red Hat Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Example howto transfer info from XDP to SKB, e.g. skb->mark 58c2ecf20Sopenharmony_ci * ----------------------------------------------------------- 68c2ecf20Sopenharmony_ci * This uses the XDP data_meta infrastructure, and is a cooperation 78c2ecf20Sopenharmony_ci * between two bpf-programs (1) XDP and (2) clsact at TC-ingress hook. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Notice: This example does not use the BPF C-loader (bpf_load.c), 108c2ecf20Sopenharmony_ci * but instead rely on the iproute2 TC tool for loading BPF-objects. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci#include <uapi/linux/bpf.h> 138c2ecf20Sopenharmony_ci#include <uapi/linux/pkt_cls.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <bpf/bpf_helpers.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * This struct is stored in the XDP 'data_meta' area, which is located 198c2ecf20Sopenharmony_ci * just in-front-of the raw packet payload data. The meaning is 208c2ecf20Sopenharmony_ci * specific to these two BPF programs that use it as a communication 218c2ecf20Sopenharmony_ci * channel. XDP adjust/increase the area via a bpf-helper, and TC use 228c2ecf20Sopenharmony_ci * boundary checks to see if data have been provided. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * The struct must be 4 byte aligned, which here is enforced by the 258c2ecf20Sopenharmony_ci * struct __attribute__((aligned(4))). 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_cistruct meta_info { 288c2ecf20Sopenharmony_ci __u32 mark; 298c2ecf20Sopenharmony_ci} __attribute__((aligned(4))); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ciSEC("xdp_mark") 328c2ecf20Sopenharmony_ciint _xdp_mark(struct xdp_md *ctx) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct meta_info *meta; 358c2ecf20Sopenharmony_ci void *data, *data_end; 368c2ecf20Sopenharmony_ci int ret; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci /* Reserve space in-front of data pointer for our meta info. 398c2ecf20Sopenharmony_ci * (Notice drivers not supporting data_meta will fail here!) 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci ret = bpf_xdp_adjust_meta(ctx, -(int)sizeof(*meta)); 428c2ecf20Sopenharmony_ci if (ret < 0) 438c2ecf20Sopenharmony_ci return XDP_ABORTED; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* Notice: Kernel-side verifier requires that loading of 468c2ecf20Sopenharmony_ci * ctx->data MUST happen _after_ helper bpf_xdp_adjust_meta(), 478c2ecf20Sopenharmony_ci * as pkt-data pointers are invalidated. Helpers that require 488c2ecf20Sopenharmony_ci * this are determined/marked by bpf_helper_changes_pkt_data() 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ci data = (void *)(unsigned long)ctx->data; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* Check data_meta have room for meta_info struct */ 538c2ecf20Sopenharmony_ci meta = (void *)(unsigned long)ctx->data_meta; 548c2ecf20Sopenharmony_ci if (meta + 1 > data) 558c2ecf20Sopenharmony_ci return XDP_ABORTED; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci meta->mark = 42; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return XDP_PASS; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ciSEC("tc_mark") 638c2ecf20Sopenharmony_ciint _tc_mark(struct __sk_buff *ctx) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci void *data = (void *)(unsigned long)ctx->data; 668c2ecf20Sopenharmony_ci void *data_end = (void *)(unsigned long)ctx->data_end; 678c2ecf20Sopenharmony_ci void *data_meta = (void *)(unsigned long)ctx->data_meta; 688c2ecf20Sopenharmony_ci struct meta_info *meta = data_meta; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* Check XDP gave us some data_meta */ 718c2ecf20Sopenharmony_ci if (meta + 1 > data) { 728c2ecf20Sopenharmony_ci ctx->mark = 41; 738c2ecf20Sopenharmony_ci /* Skip "accept" if no data_meta is avail */ 748c2ecf20Sopenharmony_ci return TC_ACT_OK; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* Hint: See func tc_cls_act_is_valid_access() for BPF_WRITE access */ 788c2ecf20Sopenharmony_ci ctx->mark = meta->mark; /* Transfer XDP-mark to SKB-mark */ 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return TC_ACT_OK; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* Manually attaching these programs: 848c2ecf20Sopenharmony_ciexport DEV=ixgbe2 858c2ecf20Sopenharmony_ciexport FILE=xdp2skb_meta_kern.o 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci# via TC command 888c2ecf20Sopenharmony_citc qdisc del dev $DEV clsact 2> /dev/null 898c2ecf20Sopenharmony_citc qdisc add dev $DEV clsact 908c2ecf20Sopenharmony_citc filter add dev $DEV ingress prio 1 handle 1 bpf da obj $FILE sec tc_mark 918c2ecf20Sopenharmony_citc filter show dev $DEV ingress 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci# XDP via IP command: 948c2ecf20Sopenharmony_ciip link set dev $DEV xdp off 958c2ecf20Sopenharmony_ciip link set dev $DEV xdp obj $FILE sec xdp_mark 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci# Use iptable to "see" if SKBs are marked 988c2ecf20Sopenharmony_ciiptables -I INPUT -p icmp -m mark --mark 41 # == 0x29 998c2ecf20Sopenharmony_ciiptables -I INPUT -p icmp -m mark --mark 42 # == 0x2a 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci# Hint: catch XDP_ABORTED errors via 1028c2ecf20Sopenharmony_ciperf record -e xdp:* 1038c2ecf20Sopenharmony_ciperf script 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci*/ 106