1 // SPDX-License-Identifier: GPL-2.0 2 3 /* This logic is lifted from a real-world use case of packet parsing, used in 4 * the open source library katran, a layer 4 load balancer. 5 * 6 * This test demonstrates how to parse packet contents using dynptrs. The 7 * original code (parsing without dynptrs) can be found in test_parse_tcp_hdr_opt.c 8 */ 9 10 #include <linux/bpf.h> 11 #include <bpf/bpf_helpers.h> 12 #include <linux/tcp.h> 13 #include <stdbool.h> 14 #include <linux/ipv6.h> 15 #include <linux/if_ether.h> 16 #include "test_tcp_hdr_options.h" 17 #include "bpf_kfuncs.h" 18 19 char _license[] SEC("license") = "GPL"; 20 21 /* Kind number used for experiments */ 22 const __u32 tcp_hdr_opt_kind_tpr = 0xFD; 23 /* Length of the tcp header option */ 24 const __u32 tcp_hdr_opt_len_tpr = 6; 25 /* maximum number of header options to check to lookup server_id */ 26 const __u32 tcp_hdr_opt_max_opt_checks = 15; 27 28 __u32 server_id; 29 30 static int parse_hdr_opt(struct bpf_dynptr *ptr, __u32 *off, __u8 *hdr_bytes_remaining, 31 __u32 *server_id) 32 { 33 __u8 kind, hdr_len; 34 __u8 buffer[sizeof(kind) + sizeof(hdr_len) + sizeof(*server_id)]; 35 __u8 *data; 36 37 __builtin_memset(buffer, 0, sizeof(buffer)); 38 39 data = bpf_dynptr_slice(ptr, *off, buffer, sizeof(buffer)); 40 if (!data) 41 return -1; 42 43 kind = data[0]; 44 45 if (kind == TCPOPT_EOL) 46 return -1; 47 48 if (kind == TCPOPT_NOP) { 49 *off += 1; 50 *hdr_bytes_remaining -= 1; 51 return 0; 52 } 53 54 if (*hdr_bytes_remaining < 2) 55 return -1; 56 57 hdr_len = data[1]; 58 if (hdr_len > *hdr_bytes_remaining) 59 return -1; 60 61 if (kind == tcp_hdr_opt_kind_tpr) { 62 if (hdr_len != tcp_hdr_opt_len_tpr) 63 return -1; 64 65 __builtin_memcpy(server_id, (__u32 *)(data + 2), sizeof(*server_id)); 66 return 1; 67 } 68 69 *off += hdr_len; 70 *hdr_bytes_remaining -= hdr_len; 71 return 0; 72 } 73 74 SEC("xdp") 75 int xdp_ingress_v6(struct xdp_md *xdp) 76 { 77 __u8 buffer[sizeof(struct tcphdr)] = {}; 78 __u8 hdr_bytes_remaining; 79 struct tcphdr *tcp_hdr; 80 __u8 tcp_hdr_opt_len; 81 int err = 0; 82 __u32 off; 83 84 struct bpf_dynptr ptr; 85 86 bpf_dynptr_from_xdp(xdp, 0, &ptr); 87 88 off = sizeof(struct ethhdr) + sizeof(struct ipv6hdr); 89 90 tcp_hdr = bpf_dynptr_slice(&ptr, off, buffer, sizeof(buffer)); 91 if (!tcp_hdr) 92 return XDP_DROP; 93 94 tcp_hdr_opt_len = (tcp_hdr->doff * 4) - sizeof(struct tcphdr); 95 if (tcp_hdr_opt_len < tcp_hdr_opt_len_tpr) 96 return XDP_DROP; 97 98 hdr_bytes_remaining = tcp_hdr_opt_len; 99 100 off += sizeof(struct tcphdr); 101 102 /* max number of bytes of options in tcp header is 40 bytes */ 103 for (int i = 0; i < tcp_hdr_opt_max_opt_checks; i++) { 104 err = parse_hdr_opt(&ptr, &off, &hdr_bytes_remaining, &server_id); 105 106 if (err || !hdr_bytes_remaining) 107 break; 108 } 109 110 if (!server_id) 111 return XDP_DROP; 112 113 return XDP_PASS; 114 } 115
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.