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