18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <limits.h> 38c2ecf20Sopenharmony_ci#include <stddef.h> 48c2ecf20Sopenharmony_ci#include <stdbool.h> 58c2ecf20Sopenharmony_ci#include <string.h> 68c2ecf20Sopenharmony_ci#include <linux/pkt_cls.h> 78c2ecf20Sopenharmony_ci#include <linux/bpf.h> 88c2ecf20Sopenharmony_ci#include <linux/in.h> 98c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 108c2ecf20Sopenharmony_ci#include <linux/icmp.h> 118c2ecf20Sopenharmony_ci#include <linux/ip.h> 128c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 138c2ecf20Sopenharmony_ci#include <linux/tcp.h> 148c2ecf20Sopenharmony_ci#include <linux/udp.h> 158c2ecf20Sopenharmony_ci#include <linux/if_packet.h> 168c2ecf20Sopenharmony_ci#include <sys/socket.h> 178c2ecf20Sopenharmony_ci#include <linux/if_tunnel.h> 188c2ecf20Sopenharmony_ci#include <linux/mpls.h> 198c2ecf20Sopenharmony_ci#include <bpf/bpf_helpers.h> 208c2ecf20Sopenharmony_ci#include <bpf/bpf_endian.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ciint _version SEC("version") = 1; 238c2ecf20Sopenharmony_ci#define PROG(F) PROG_(F, _##F) 248c2ecf20Sopenharmony_ci#define PROG_(NUM, NAME) SEC("flow_dissector/"#NUM) int bpf_func##NAME 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* These are the identifiers of the BPF programs that will be used in tail 278c2ecf20Sopenharmony_ci * calls. Name is limited to 16 characters, with the terminating character and 288c2ecf20Sopenharmony_ci * bpf_func_ above, we have only 6 to work with, anything after will be cropped. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci#define IP 0 318c2ecf20Sopenharmony_ci#define IPV6 1 328c2ecf20Sopenharmony_ci#define IPV6OP 2 /* Destination/Hop-by-Hop Options IPv6 Ext. Header */ 338c2ecf20Sopenharmony_ci#define IPV6FR 3 /* Fragmentation IPv6 Extension Header */ 348c2ecf20Sopenharmony_ci#define MPLS 4 358c2ecf20Sopenharmony_ci#define VLAN 5 368c2ecf20Sopenharmony_ci#define MAX_PROG 6 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define IP_MF 0x2000 398c2ecf20Sopenharmony_ci#define IP_OFFSET 0x1FFF 408c2ecf20Sopenharmony_ci#define IP6_MF 0x0001 418c2ecf20Sopenharmony_ci#define IP6_OFFSET 0xFFF8 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct vlan_hdr { 448c2ecf20Sopenharmony_ci __be16 h_vlan_TCI; 458c2ecf20Sopenharmony_ci __be16 h_vlan_encapsulated_proto; 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistruct gre_hdr { 498c2ecf20Sopenharmony_ci __be16 flags; 508c2ecf20Sopenharmony_ci __be16 proto; 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistruct frag_hdr { 548c2ecf20Sopenharmony_ci __u8 nexthdr; 558c2ecf20Sopenharmony_ci __u8 reserved; 568c2ecf20Sopenharmony_ci __be16 frag_off; 578c2ecf20Sopenharmony_ci __be32 identification; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct { 618c2ecf20Sopenharmony_ci __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 628c2ecf20Sopenharmony_ci __uint(max_entries, MAX_PROG); 638c2ecf20Sopenharmony_ci __uint(key_size, sizeof(__u32)); 648c2ecf20Sopenharmony_ci __uint(value_size, sizeof(__u32)); 658c2ecf20Sopenharmony_ci} jmp_table SEC(".maps"); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistruct { 688c2ecf20Sopenharmony_ci __uint(type, BPF_MAP_TYPE_HASH); 698c2ecf20Sopenharmony_ci __uint(max_entries, 1024); 708c2ecf20Sopenharmony_ci __type(key, __u32); 718c2ecf20Sopenharmony_ci __type(value, struct bpf_flow_keys); 728c2ecf20Sopenharmony_ci} last_dissection SEC(".maps"); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic __always_inline int export_flow_keys(struct bpf_flow_keys *keys, 758c2ecf20Sopenharmony_ci int ret) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci __u32 key = (__u32)(keys->sport) << 16 | keys->dport; 788c2ecf20Sopenharmony_ci struct bpf_flow_keys val; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci memcpy(&val, keys, sizeof(val)); 818c2ecf20Sopenharmony_ci bpf_map_update_elem(&last_dissection, &key, &val, BPF_ANY); 828c2ecf20Sopenharmony_ci return ret; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#define IPV6_FLOWLABEL_MASK __bpf_constant_htonl(0x000FFFFF) 868c2ecf20Sopenharmony_cistatic inline __be32 ip6_flowlabel(const struct ipv6hdr *hdr) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci return *(__be32 *)hdr & IPV6_FLOWLABEL_MASK; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb, 928c2ecf20Sopenharmony_ci __u16 hdr_size, 938c2ecf20Sopenharmony_ci void *buffer) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci void *data_end = (void *)(long)skb->data_end; 968c2ecf20Sopenharmony_ci void *data = (void *)(long)skb->data; 978c2ecf20Sopenharmony_ci __u16 thoff = skb->flow_keys->thoff; 988c2ecf20Sopenharmony_ci __u8 *hdr; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* Verifies this variable offset does not overflow */ 1018c2ecf20Sopenharmony_ci if (thoff > (USHRT_MAX - hdr_size)) 1028c2ecf20Sopenharmony_ci return NULL; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci hdr = data + thoff; 1058c2ecf20Sopenharmony_ci if (hdr + hdr_size <= data_end) 1068c2ecf20Sopenharmony_ci return hdr; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (bpf_skb_load_bytes(skb, thoff, buffer, hdr_size)) 1098c2ecf20Sopenharmony_ci return NULL; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return buffer; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* Dispatches on ETHERTYPE */ 1158c2ecf20Sopenharmony_cistatic __always_inline int parse_eth_proto(struct __sk_buff *skb, __be16 proto) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct bpf_flow_keys *keys = skb->flow_keys; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci switch (proto) { 1208c2ecf20Sopenharmony_ci case bpf_htons(ETH_P_IP): 1218c2ecf20Sopenharmony_ci bpf_tail_call_static(skb, &jmp_table, IP); 1228c2ecf20Sopenharmony_ci break; 1238c2ecf20Sopenharmony_ci case bpf_htons(ETH_P_IPV6): 1248c2ecf20Sopenharmony_ci bpf_tail_call_static(skb, &jmp_table, IPV6); 1258c2ecf20Sopenharmony_ci break; 1268c2ecf20Sopenharmony_ci case bpf_htons(ETH_P_MPLS_MC): 1278c2ecf20Sopenharmony_ci case bpf_htons(ETH_P_MPLS_UC): 1288c2ecf20Sopenharmony_ci bpf_tail_call_static(skb, &jmp_table, MPLS); 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci case bpf_htons(ETH_P_8021Q): 1318c2ecf20Sopenharmony_ci case bpf_htons(ETH_P_8021AD): 1328c2ecf20Sopenharmony_ci bpf_tail_call_static(skb, &jmp_table, VLAN); 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci default: 1358c2ecf20Sopenharmony_ci /* Protocol not supported */ 1368c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ciSEC("flow_dissector") 1438c2ecf20Sopenharmony_ciint _dissect(struct __sk_buff *skb) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct bpf_flow_keys *keys = skb->flow_keys; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return parse_eth_proto(skb, keys->n_proto); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/* Parses on IPPROTO_* */ 1518c2ecf20Sopenharmony_cistatic __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci struct bpf_flow_keys *keys = skb->flow_keys; 1548c2ecf20Sopenharmony_ci void *data_end = (void *)(long)skb->data_end; 1558c2ecf20Sopenharmony_ci struct icmphdr *icmp, _icmp; 1568c2ecf20Sopenharmony_ci struct gre_hdr *gre, _gre; 1578c2ecf20Sopenharmony_ci struct ethhdr *eth, _eth; 1588c2ecf20Sopenharmony_ci struct tcphdr *tcp, _tcp; 1598c2ecf20Sopenharmony_ci struct udphdr *udp, _udp; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci switch (proto) { 1628c2ecf20Sopenharmony_ci case IPPROTO_ICMP: 1638c2ecf20Sopenharmony_ci icmp = bpf_flow_dissect_get_header(skb, sizeof(*icmp), &_icmp); 1648c2ecf20Sopenharmony_ci if (!icmp) 1658c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 1668c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_OK); 1678c2ecf20Sopenharmony_ci case IPPROTO_IPIP: 1688c2ecf20Sopenharmony_ci keys->is_encap = true; 1698c2ecf20Sopenharmony_ci if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP) 1708c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_OK); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return parse_eth_proto(skb, bpf_htons(ETH_P_IP)); 1738c2ecf20Sopenharmony_ci case IPPROTO_IPV6: 1748c2ecf20Sopenharmony_ci keys->is_encap = true; 1758c2ecf20Sopenharmony_ci if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP) 1768c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_OK); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return parse_eth_proto(skb, bpf_htons(ETH_P_IPV6)); 1798c2ecf20Sopenharmony_ci case IPPROTO_GRE: 1808c2ecf20Sopenharmony_ci gre = bpf_flow_dissect_get_header(skb, sizeof(*gre), &_gre); 1818c2ecf20Sopenharmony_ci if (!gre) 1828c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (bpf_htons(gre->flags & GRE_VERSION)) 1858c2ecf20Sopenharmony_ci /* Only inspect standard GRE packets with version 0 */ 1868c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_OK); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci keys->thoff += sizeof(*gre); /* Step over GRE Flags and Proto */ 1898c2ecf20Sopenharmony_ci if (GRE_IS_CSUM(gre->flags)) 1908c2ecf20Sopenharmony_ci keys->thoff += 4; /* Step over chksum and Padding */ 1918c2ecf20Sopenharmony_ci if (GRE_IS_KEY(gre->flags)) 1928c2ecf20Sopenharmony_ci keys->thoff += 4; /* Step over key */ 1938c2ecf20Sopenharmony_ci if (GRE_IS_SEQ(gre->flags)) 1948c2ecf20Sopenharmony_ci keys->thoff += 4; /* Step over sequence number */ 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci keys->is_encap = true; 1978c2ecf20Sopenharmony_ci if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP) 1988c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_OK); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (gre->proto == bpf_htons(ETH_P_TEB)) { 2018c2ecf20Sopenharmony_ci eth = bpf_flow_dissect_get_header(skb, sizeof(*eth), 2028c2ecf20Sopenharmony_ci &_eth); 2038c2ecf20Sopenharmony_ci if (!eth) 2048c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci keys->thoff += sizeof(*eth); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return parse_eth_proto(skb, eth->h_proto); 2098c2ecf20Sopenharmony_ci } else { 2108c2ecf20Sopenharmony_ci return parse_eth_proto(skb, gre->proto); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci case IPPROTO_TCP: 2138c2ecf20Sopenharmony_ci tcp = bpf_flow_dissect_get_header(skb, sizeof(*tcp), &_tcp); 2148c2ecf20Sopenharmony_ci if (!tcp) 2158c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (tcp->doff < 5) 2188c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if ((__u8 *)tcp + (tcp->doff << 2) > data_end) 2218c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci keys->sport = tcp->source; 2248c2ecf20Sopenharmony_ci keys->dport = tcp->dest; 2258c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_OK); 2268c2ecf20Sopenharmony_ci case IPPROTO_UDP: 2278c2ecf20Sopenharmony_ci case IPPROTO_UDPLITE: 2288c2ecf20Sopenharmony_ci udp = bpf_flow_dissect_get_header(skb, sizeof(*udp), &_udp); 2298c2ecf20Sopenharmony_ci if (!udp) 2308c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci keys->sport = udp->source; 2338c2ecf20Sopenharmony_ci keys->dport = udp->dest; 2348c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_OK); 2358c2ecf20Sopenharmony_ci default: 2368c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic __always_inline int parse_ipv6_proto(struct __sk_buff *skb, __u8 nexthdr) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct bpf_flow_keys *keys = skb->flow_keys; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci switch (nexthdr) { 2478c2ecf20Sopenharmony_ci case IPPROTO_HOPOPTS: 2488c2ecf20Sopenharmony_ci case IPPROTO_DSTOPTS: 2498c2ecf20Sopenharmony_ci bpf_tail_call_static(skb, &jmp_table, IPV6OP); 2508c2ecf20Sopenharmony_ci break; 2518c2ecf20Sopenharmony_ci case IPPROTO_FRAGMENT: 2528c2ecf20Sopenharmony_ci bpf_tail_call_static(skb, &jmp_table, IPV6FR); 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci default: 2558c2ecf20Sopenharmony_ci return parse_ip_proto(skb, nexthdr); 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ciPROG(IP)(struct __sk_buff *skb) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci void *data_end = (void *)(long)skb->data_end; 2648c2ecf20Sopenharmony_ci struct bpf_flow_keys *keys = skb->flow_keys; 2658c2ecf20Sopenharmony_ci void *data = (void *)(long)skb->data; 2668c2ecf20Sopenharmony_ci struct iphdr *iph, _iph; 2678c2ecf20Sopenharmony_ci bool done = false; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci iph = bpf_flow_dissect_get_header(skb, sizeof(*iph), &_iph); 2708c2ecf20Sopenharmony_ci if (!iph) 2718c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* IP header cannot be smaller than 20 bytes */ 2748c2ecf20Sopenharmony_ci if (iph->ihl < 5) 2758c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci keys->addr_proto = ETH_P_IP; 2788c2ecf20Sopenharmony_ci keys->ipv4_src = iph->saddr; 2798c2ecf20Sopenharmony_ci keys->ipv4_dst = iph->daddr; 2808c2ecf20Sopenharmony_ci keys->ip_proto = iph->protocol; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci keys->thoff += iph->ihl << 2; 2838c2ecf20Sopenharmony_ci if (data + keys->thoff > data_end) 2848c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (iph->frag_off & bpf_htons(IP_MF | IP_OFFSET)) { 2878c2ecf20Sopenharmony_ci keys->is_frag = true; 2888c2ecf20Sopenharmony_ci if (iph->frag_off & bpf_htons(IP_OFFSET)) { 2898c2ecf20Sopenharmony_ci /* From second fragment on, packets do not have headers 2908c2ecf20Sopenharmony_ci * we can parse. 2918c2ecf20Sopenharmony_ci */ 2928c2ecf20Sopenharmony_ci done = true; 2938c2ecf20Sopenharmony_ci } else { 2948c2ecf20Sopenharmony_ci keys->is_first_frag = true; 2958c2ecf20Sopenharmony_ci /* No need to parse fragmented packet unless 2968c2ecf20Sopenharmony_ci * explicitly asked for. 2978c2ecf20Sopenharmony_ci */ 2988c2ecf20Sopenharmony_ci if (!(keys->flags & 2998c2ecf20Sopenharmony_ci BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG)) 3008c2ecf20Sopenharmony_ci done = true; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (done) 3058c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_OK); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return parse_ip_proto(skb, iph->protocol); 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ciPROG(IPV6)(struct __sk_buff *skb) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct bpf_flow_keys *keys = skb->flow_keys; 3138c2ecf20Sopenharmony_ci struct ipv6hdr *ip6h, _ip6h; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h); 3168c2ecf20Sopenharmony_ci if (!ip6h) 3178c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci keys->addr_proto = ETH_P_IPV6; 3208c2ecf20Sopenharmony_ci memcpy(&keys->ipv6_src, &ip6h->saddr, 2*sizeof(ip6h->saddr)); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci keys->thoff += sizeof(struct ipv6hdr); 3238c2ecf20Sopenharmony_ci keys->ip_proto = ip6h->nexthdr; 3248c2ecf20Sopenharmony_ci keys->flow_label = ip6_flowlabel(ip6h); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL) 3278c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_OK); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return parse_ipv6_proto(skb, ip6h->nexthdr); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ciPROG(IPV6OP)(struct __sk_buff *skb) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct bpf_flow_keys *keys = skb->flow_keys; 3358c2ecf20Sopenharmony_ci struct ipv6_opt_hdr *ip6h, _ip6h; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h); 3388c2ecf20Sopenharmony_ci if (!ip6h) 3398c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* hlen is in 8-octets and does not include the first 8 bytes 3428c2ecf20Sopenharmony_ci * of the header 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_ci keys->thoff += (1 + ip6h->hdrlen) << 3; 3458c2ecf20Sopenharmony_ci keys->ip_proto = ip6h->nexthdr; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci return parse_ipv6_proto(skb, ip6h->nexthdr); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ciPROG(IPV6FR)(struct __sk_buff *skb) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct bpf_flow_keys *keys = skb->flow_keys; 3538c2ecf20Sopenharmony_ci struct frag_hdr *fragh, _fragh; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci fragh = bpf_flow_dissect_get_header(skb, sizeof(*fragh), &_fragh); 3568c2ecf20Sopenharmony_ci if (!fragh) 3578c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci keys->thoff += sizeof(*fragh); 3608c2ecf20Sopenharmony_ci keys->is_frag = true; 3618c2ecf20Sopenharmony_ci keys->ip_proto = fragh->nexthdr; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (!(fragh->frag_off & bpf_htons(IP6_OFFSET))) { 3648c2ecf20Sopenharmony_ci keys->is_first_frag = true; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* No need to parse fragmented packet unless 3678c2ecf20Sopenharmony_ci * explicitly asked for. 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_ci if (!(keys->flags & BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG)) 3708c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_OK); 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return parse_ipv6_proto(skb, fragh->nexthdr); 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ciPROG(MPLS)(struct __sk_buff *skb) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct bpf_flow_keys *keys = skb->flow_keys; 3798c2ecf20Sopenharmony_ci struct mpls_label *mpls, _mpls; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci mpls = bpf_flow_dissect_get_header(skb, sizeof(*mpls), &_mpls); 3828c2ecf20Sopenharmony_ci if (!mpls) 3838c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_OK); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ciPROG(VLAN)(struct __sk_buff *skb) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct bpf_flow_keys *keys = skb->flow_keys; 3918c2ecf20Sopenharmony_ci struct vlan_hdr *vlan, _vlan; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* Account for double-tagging */ 3948c2ecf20Sopenharmony_ci if (keys->n_proto == bpf_htons(ETH_P_8021AD)) { 3958c2ecf20Sopenharmony_ci vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan); 3968c2ecf20Sopenharmony_ci if (!vlan) 3978c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (vlan->h_vlan_encapsulated_proto != bpf_htons(ETH_P_8021Q)) 4008c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci keys->nhoff += sizeof(*vlan); 4038c2ecf20Sopenharmony_ci keys->thoff += sizeof(*vlan); 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan); 4078c2ecf20Sopenharmony_ci if (!vlan) 4088c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci keys->nhoff += sizeof(*vlan); 4118c2ecf20Sopenharmony_ci keys->thoff += sizeof(*vlan); 4128c2ecf20Sopenharmony_ci /* Only allow 8021AD + 8021Q double tagging and no triple tagging.*/ 4138c2ecf20Sopenharmony_ci if (vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021AD) || 4148c2ecf20Sopenharmony_ci vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021Q)) 4158c2ecf20Sopenharmony_ci return export_flow_keys(keys, BPF_DROP); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci keys->n_proto = vlan->h_vlan_encapsulated_proto; 4188c2ecf20Sopenharmony_ci return parse_eth_proto(skb, vlan->h_vlan_encapsulated_proto); 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cichar __license[] SEC("license") = "GPL"; 422