On Thu, 16 Jan 2020, Toke Høiland-Jørgensen wrote: Hi Toke, > > You could also try the xdp-loader in xdp-tools: > https://github.com/xdp-project/xdp-tools > > It's somewhat basic still, but should be able to at least load a basic > program - please file a bug report if it fails. I tried the xdp-tools xdp-loader, when the optlen is global variable, I got: # xdp-loader load enp3s0 tcp_option.o Couldn't load BPF program: Relocation failed if I move the optlen, i variable to local variable, I got: # xdp-loader load enp3s0 tcp_option.o Couldn't load eBPF object: Invalid argument(-22) Here is the complete code: #include <stdint.h> #include <arpa/inet.h> #include <asm/byteorder.h> #include <linux/bpf.h> #include <linux/if_ether.h> #include <linux/ip.h> #include <linux/tcp.h> #include <linux/pkt_cls.h> /* * Sample XDP to parse tcp option. * compile it with: * clang -O2 -emit-llvm -c tcp_option.c -o - |llc -march=bpf -filetype=obj -o tcp_option.o * attach it to a device with XDP as: * ip link set dev lo xdp object tcp_option.o verbose */ #define SEC(NAME) __attribute__((section(NAME), used)) #define TCPOPT_EOL 0 /* End of options (1) */ #define TCPOPT_NOP 1 /* No-op (1) */ #define TCPOPT_MAXSEG 2 /* Maximum segment size (4) */ #define TCPOPT_WSCALE 3 /* Window scaling (3) */ #define TCPOPT_SACKOK 4 /* Selective ACK permitted (2) */ #define TCPOPT_SACK 5 /* Actual selective ACK (10-34) */ #define TCPOPT_TSTAMP 8 /* Timestamp (10) */ /* from bpf_helpers.h */ static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = (void *) BPF_FUNC_trace_printk; static unsigned long long (*bpf_get_prandom_u32)(void) = (void *) BPF_FUNC_get_prandom_u32; static int tcp_option(void *data, void *data_end) { struct ethhdr *eth = (struct ethhdr *)data; struct iphdr *iph = (struct iphdr *)(eth + 1); struct tcphdr *tcphdr = (struct tcphdr *)(iph + 1); const __u8 *op; int i, optlen; /* sanity check needed by the eBPF verifier */ if ((void *)(tcphdr + 1) > data_end) return 0; /* skip non TCP packets */ if (eth->h_proto != __constant_htons(ETH_P_IP) || iph->protocol != IPPROTO_TCP) return 0; /* incompatible flags, or PSH already set */ if (tcphdr->ack || tcphdr->fin || tcphdr->rst || tcphdr->psh) return 0; if (tcphdr->syn) { if (((void *)(tcphdr + 1) + tcphdr->doff*4) > data_end) return 0; optlen = tcphdr->doff*4 - sizeof(*tcphdr); for (i = 0; i < optlen; ) { if (op[i] == TCPOPT_EOL ) { char fmt[] = "XDP: tcp source : %d tcp option eol\n"; bpf_trace_printk(fmt, sizeof(fmt), (int)tcphdr->source); return 1; } if (op[i] < 2) i++; else i += op[i+1] ? : 1; } #if 0 if (tcphdr->doff*4 == 44 || tcphdr->doff*4 == 28) { char fmt[] = "XDP: tcp source : %d data offset :%d\n"; bpf_trace_printk(fmt, sizeof(fmt), (int)tcphdr->source, (int)tcphdr->doff*4); return 1; } #endif } return 0; } SEC("prog") int xdp_main(struct xdp_md *ctx) { void *data_end = (void *)(uintptr_t)ctx->data_end; void *data = (void *)(uintptr_t)ctx->data; if (tcp_option(data, data_end)) return XDP_DROP; return XDP_PASS; } char _license[] SEC("license") = "GPL";