• 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/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