bpf: fix samples to add fake KBUILD_MODNAME
[cascardo/linux.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";