]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - samples/bpf/parse_varlen.c
hinic: fix a bug in set rx mode
[mirror_ubuntu-bionic-kernel.git] / samples / bpf / parse_varlen.c
1 /* Copyright (c) 2016 Facebook
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7 #define KBUILD_MODNAME "foo"
8 #include <linux/if_ether.h>
9 #include <linux/ip.h>
10 #include <linux/ipv6.h>
11 #include <linux/in.h>
12 #include <linux/tcp.h>
13 #include <linux/udp.h>
14 #include <uapi/linux/bpf.h>
15 #include <net/ip.h>
16 #include "bpf_helpers.h"
17
18 #define DEFAULT_PKTGEN_UDP_PORT 9
19 #define DEBUG 0
20
21 static int tcp(void *data, uint64_t tp_off, void *data_end)
22 {
23 struct tcphdr *tcp = data + tp_off;
24
25 if (tcp + 1 > data_end)
26 return 0;
27 if (tcp->dest == htons(80) || tcp->source == htons(80))
28 return TC_ACT_SHOT;
29 return 0;
30 }
31
32 static int udp(void *data, uint64_t tp_off, void *data_end)
33 {
34 struct udphdr *udp = data + tp_off;
35
36 if (udp + 1 > data_end)
37 return 0;
38 if (udp->dest == htons(DEFAULT_PKTGEN_UDP_PORT) ||
39 udp->source == htons(DEFAULT_PKTGEN_UDP_PORT)) {
40 if (DEBUG) {
41 char fmt[] = "udp port 9 indeed\n";
42
43 bpf_trace_printk(fmt, sizeof(fmt));
44 }
45 return TC_ACT_SHOT;
46 }
47 return 0;
48 }
49
50 static int parse_ipv4(void *data, uint64_t nh_off, void *data_end)
51 {
52 struct iphdr *iph;
53 uint64_t ihl_len;
54
55 iph = data + nh_off;
56 if (iph + 1 > data_end)
57 return 0;
58
59 if (ip_is_fragment(iph))
60 return 0;
61 ihl_len = iph->ihl * 4;
62
63 if (iph->protocol == IPPROTO_IPIP) {
64 iph = data + nh_off + ihl_len;
65 if (iph + 1 > data_end)
66 return 0;
67 ihl_len += iph->ihl * 4;
68 }
69
70 if (iph->protocol == IPPROTO_TCP)
71 return tcp(data, nh_off + ihl_len, data_end);
72 else if (iph->protocol == IPPROTO_UDP)
73 return udp(data, nh_off + ihl_len, data_end);
74 return 0;
75 }
76
77 static int parse_ipv6(void *data, uint64_t nh_off, void *data_end)
78 {
79 struct ipv6hdr *ip6h;
80 struct iphdr *iph;
81 uint64_t ihl_len = sizeof(struct ipv6hdr);
82 uint64_t nexthdr;
83
84 ip6h = data + nh_off;
85 if (ip6h + 1 > data_end)
86 return 0;
87
88 nexthdr = ip6h->nexthdr;
89
90 if (nexthdr == IPPROTO_IPIP) {
91 iph = data + nh_off + ihl_len;
92 if (iph + 1 > data_end)
93 return 0;
94 ihl_len += iph->ihl * 4;
95 nexthdr = iph->protocol;
96 } else if (nexthdr == IPPROTO_IPV6) {
97 ip6h = data + nh_off + ihl_len;
98 if (ip6h + 1 > data_end)
99 return 0;
100 ihl_len += sizeof(struct ipv6hdr);
101 nexthdr = ip6h->nexthdr;
102 }
103
104 if (nexthdr == IPPROTO_TCP)
105 return tcp(data, nh_off + ihl_len, data_end);
106 else if (nexthdr == IPPROTO_UDP)
107 return udp(data, nh_off + ihl_len, data_end);
108 return 0;
109 }
110
111 struct vlan_hdr {
112 uint16_t h_vlan_TCI;
113 uint16_t h_vlan_encapsulated_proto;
114 };
115
116 SEC("varlen")
117 int handle_ingress(struct __sk_buff *skb)
118 {
119 void *data = (void *)(long)skb->data;
120 struct ethhdr *eth = data;
121 void *data_end = (void *)(long)skb->data_end;
122 uint64_t h_proto, nh_off;
123
124 nh_off = sizeof(*eth);
125 if (data + nh_off > data_end)
126 return 0;
127
128 h_proto = eth->h_proto;
129
130 if (h_proto == ETH_P_8021Q || h_proto == ETH_P_8021AD) {
131 struct vlan_hdr *vhdr;
132
133 vhdr = data + nh_off;
134 nh_off += sizeof(struct vlan_hdr);
135 if (data + nh_off > data_end)
136 return 0;
137 h_proto = vhdr->h_vlan_encapsulated_proto;
138 }
139 if (h_proto == ETH_P_8021Q || h_proto == ETH_P_8021AD) {
140 struct vlan_hdr *vhdr;
141
142 vhdr = data + nh_off;
143 nh_off += sizeof(struct vlan_hdr);
144 if (data + nh_off > data_end)
145 return 0;
146 h_proto = vhdr->h_vlan_encapsulated_proto;
147 }
148 if (h_proto == htons(ETH_P_IP))
149 return parse_ipv4(data, nh_off, data_end);
150 else if (h_proto == htons(ETH_P_IPV6))
151 return parse_ipv6(data, nh_off, data_end);
152 return 0;
153 }
154 char _license[] SEC("license") = "GPL";