Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0
0002  * Copyright (c) 2018 Jesper Dangaard Brouer, Red Hat Inc.
0003  *
0004  * Example howto transfer info from XDP to SKB, e.g. skb->mark
0005  * -----------------------------------------------------------
0006  * This uses the XDP data_meta infrastructure, and is a cooperation
0007  * between two bpf-programs (1) XDP and (2) clsact at TC-ingress hook.
0008  *
0009  * Notice: This example does not use the BPF C-loader,
0010  * but instead rely on the iproute2 TC tool for loading BPF-objects.
0011  */
0012 #include <uapi/linux/bpf.h>
0013 #include <uapi/linux/pkt_cls.h>
0014 
0015 #include <bpf/bpf_helpers.h>
0016 
0017 /*
0018  * This struct is stored in the XDP 'data_meta' area, which is located
0019  * just in-front-of the raw packet payload data.  The meaning is
0020  * specific to these two BPF programs that use it as a communication
0021  * channel.  XDP adjust/increase the area via a bpf-helper, and TC use
0022  * boundary checks to see if data have been provided.
0023  *
0024  * The struct must be 4 byte aligned, which here is enforced by the
0025  * struct __attribute__((aligned(4))).
0026  */
0027 struct meta_info {
0028     __u32 mark;
0029 } __attribute__((aligned(4)));
0030 
0031 SEC("xdp_mark")
0032 int _xdp_mark(struct xdp_md *ctx)
0033 {
0034     struct meta_info *meta;
0035     void *data, *data_end;
0036     int ret;
0037 
0038     /* Reserve space in-front of data pointer for our meta info.
0039      * (Notice drivers not supporting data_meta will fail here!)
0040      */
0041     ret = bpf_xdp_adjust_meta(ctx, -(int)sizeof(*meta));
0042     if (ret < 0)
0043         return XDP_ABORTED;
0044 
0045     /* Notice: Kernel-side verifier requires that loading of
0046      * ctx->data MUST happen _after_ helper bpf_xdp_adjust_meta(),
0047      * as pkt-data pointers are invalidated.  Helpers that require
0048      * this are determined/marked by bpf_helper_changes_pkt_data()
0049      */
0050     data = (void *)(unsigned long)ctx->data;
0051 
0052     /* Check data_meta have room for meta_info struct */
0053     meta = (void *)(unsigned long)ctx->data_meta;
0054     if (meta + 1 > data)
0055         return XDP_ABORTED;
0056 
0057     meta->mark = 42;
0058 
0059     return XDP_PASS;
0060 }
0061 
0062 SEC("tc_mark")
0063 int _tc_mark(struct __sk_buff *ctx)
0064 {
0065     void *data      = (void *)(unsigned long)ctx->data;
0066     void *data_end  = (void *)(unsigned long)ctx->data_end;
0067     void *data_meta = (void *)(unsigned long)ctx->data_meta;
0068     struct meta_info *meta = data_meta;
0069 
0070     /* Check XDP gave us some data_meta */
0071     if (meta + 1 > data) {
0072         ctx->mark = 41;
0073          /* Skip "accept" if no data_meta is avail */
0074         return TC_ACT_OK;
0075     }
0076 
0077     /* Hint: See func tc_cls_act_is_valid_access() for BPF_WRITE access */
0078     ctx->mark = meta->mark; /* Transfer XDP-mark to SKB-mark */
0079 
0080     return TC_ACT_OK;
0081 }
0082 
0083 /* Manually attaching these programs:
0084 export DEV=ixgbe2
0085 export FILE=xdp2skb_meta_kern.o
0086 
0087 # via TC command
0088 tc qdisc del dev $DEV clsact 2> /dev/null
0089 tc qdisc add dev $DEV clsact
0090 tc filter  add dev $DEV ingress prio 1 handle 1 bpf da obj $FILE sec tc_mark
0091 tc filter show dev $DEV ingress
0092 
0093 # XDP via IP command:
0094 ip link set dev $DEV xdp off
0095 ip link set dev $DEV xdp obj $FILE sec xdp_mark
0096 
0097 # Use iptable to "see" if SKBs are marked
0098 iptables -I INPUT -p icmp -m mark --mark 41  # == 0x29
0099 iptables -I INPUT -p icmp -m mark --mark 42  # == 0x2a
0100 
0101 # Hint: catch XDP_ABORTED errors via
0102 perf record -e xdp:*
0103 perf script
0104 
0105 */