• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/qosify/bpf_skb_utils.h

  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