1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name> 4 * Version: 2022-09-21 5 */ 6 #ifndef __BPF_SKB_UTILS_H 7 #define __BPF_SKB_UTILS_H 8 9 #include <uapi/linux/bpf.h> 10 #include <uapi/linux/if_ether.h> 11 #include <uapi/linux/ip.h> 12 #include <uapi/linux/ipv6.h> 13 #include <linux/ip.h> 14 #include <net/ipv6.h> 15 #include <bpf/bpf_helpers.h> 16 #include <bpf/bpf_endian.h> 17 18 struct skb_parser_info { 19 struct __sk_buff *skb; 20 __u32 offset; 21 int proto; 22 }; 23 24 static __always_inline void *__skb_data(struct __sk_buff *skb) 25 { 26 return (void *)(long)READ_ONCE(skb->data); 27 } 28 29 static __always_inline void * 30 skb_ptr(struct __sk_buff *skb, __u32 offset, __u32 len) 31 { 32 void *ptr = __skb_data(skb) + offset; 33 void *end = (void *)(long)(skb->data_end); 34 35 if (ptr + len >= end) 36 return NULL; 37 38 return ptr; 39 } 40 41 static __always_inline void * 42 skb_info_ptr(struct skb_parser_info *info, __u32 len) 43 { 44 __u32 offset = info->offset; 45 return skb_ptr(info->skb, offset, len); 46 } 47 48 static __always_inline void 49 skb_parse_init(struct skb_parser_info *info, struct __sk_buff *skb) 50 { 51 *info = (struct skb_parser_info){ 52 .skb = skb 53 }; 54 } 55 56 static __always_inline struct ethhdr * 57 skb_parse_ethernet(struct skb_parser_info *info) 58 { 59 struct ethhdr *eth; 60 int len; 61 62 len = sizeof(*eth) + 2 * sizeof(struct vlan_hdr) + sizeof(struct ipv6hdr); 63 if (len > info->skb->len) 64 len = info->skb->len; 65 bpf_skb_pull_data(info->skb, len); 66 67 eth = skb_info_ptr(info, sizeof(*eth)); 68 if (!eth) 69 return NULL; 70 71 info->proto = eth->h_proto; 72 info->offset += sizeof(*eth); 73 74 return eth; 75 } 76 77 static __always_inline struct vlan_hdr * 78 skb_parse_vlan(struct skb_parser_info *info) 79 { 80 struct vlan_hdr *vlh; 81 82 if (info->proto != bpf_htons(ETH_P_8021Q) && 83 info->proto != bpf_htons(ETH_P_8021AD)) 84 return NULL; 85 86 vlh = skb_info_ptr(info, sizeof(*vlh)); 87 if (!vlh) 88 return NULL; 89 90 info->proto = vlh->h_vlan_encapsulated_proto; 91 info->offset += sizeof(*vlh); 92 93 return vlh; 94 } 95 96 static __always_inline struct iphdr * 97 skb_parse_ipv4(struct skb_parser_info *info, int min_l4_bytes) 98 { 99 struct iphdr *iph; 100 int proto, hdr_len; 101 __u32 pull_len; 102 103 if (info->proto != bpf_htons(ETH_P_IP)) 104 return NULL; 105 106 iph = skb_info_ptr(info, sizeof(*iph)); 107 if (!iph) 108 return NULL; 109 110 hdr_len = iph->ihl * 4; 111 hdr_len = READ_ONCE(hdr_len) & 0xff; 112 if (hdr_len < sizeof(*iph)) 113 return NULL; 114 115 pull_len = info->offset + hdr_len + min_l4_bytes; 116 if (pull_len > info->skb->len) 117 pull_len = info->skb->len; 118 119 if (bpf_skb_pull_data(info->skb, pull_len)) 120 return NULL; 121 122 iph = skb_info_ptr(info, sizeof(*iph)); 123 if (!iph) 124 return NULL; 125 126 info->proto = iph->protocol; 127 info->offset += hdr_len; 128 129 return iph; 130 } 131 132 static __always_inline struct ipv6hdr * 133 skb_parse_ipv6(struct skb_parser_info *info, int max_l4_bytes) 134 { 135 struct ipv6hdr *ip6h; 136 __u32 pull_len; 137 138 if (info->proto != bpf_htons(ETH_P_IPV6)) 139 return NULL; 140 141 pull_len = info->offset + sizeof(*ip6h) + max_l4_bytes; 142 if (pull_len > info->skb->len) 143 pull_len = info->skb->len; 144 145 if (bpf_skb_pull_data(info->skb, pull_len)) 146 return NULL; 147 148 ip6h = skb_info_ptr(info, sizeof(*ip6h)); 149 if (!ip6h) 150 return NULL; 151 152 info->proto = READ_ONCE(ip6h->nexthdr); 153 info->offset += sizeof(*ip6h); 154 155 return ip6h; 156 } 157 158 static __always_inline struct tcphdr * 159 skb_parse_tcp(struct skb_parser_info *info) 160 { 161 struct tcphdr *tcph; 162 163 if (info->proto != IPPROTO_TCP) 164 return NULL; 165 166 tcph = skb_info_ptr(info, sizeof(*tcph)); 167 if (!tcph) 168 return NULL; 169 170 info->offset += tcph->doff * 4; 171 172 return tcph; 173 } 174 175 #endif 176
This page was automatically generated by LXR 0.3.1. • OpenWrt