1 /* Copyright (c) 2016 Facebook
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.
7 #include <linux/if_ether.h>
9 #include <linux/ipv6.h>
11 #include <linux/tcp.h>
12 #include <linux/udp.h>
13 #include <uapi/linux/bpf.h>
15 #include "bpf_helpers.h"
17 #define DEFAULT_PKTGEN_UDP_PORT 9
20 static int tcp(void *data
, uint64_t tp_off
, void *data_end
)
22 struct tcphdr
*tcp
= data
+ tp_off
;
24 if (tcp
+ 1 > data_end
)
26 if (tcp
->dest
== htons(80) || tcp
->source
== htons(80))
31 static int udp(void *data
, uint64_t tp_off
, void *data_end
)
33 struct udphdr
*udp
= data
+ tp_off
;
35 if (udp
+ 1 > data_end
)
37 if (udp
->dest
== htons(DEFAULT_PKTGEN_UDP_PORT
) ||
38 udp
->source
== htons(DEFAULT_PKTGEN_UDP_PORT
)) {
40 char fmt
[] = "udp port 9 indeed\n";
42 bpf_trace_printk(fmt
, sizeof(fmt
));
49 static int parse_ipv4(void *data
, uint64_t nh_off
, void *data_end
)
55 if (iph
+ 1 > data_end
)
58 if (ip_is_fragment(iph
))
60 ihl_len
= iph
->ihl
* 4;
62 if (iph
->protocol
== IPPROTO_IPIP
) {
63 iph
= data
+ nh_off
+ ihl_len
;
64 if (iph
+ 1 > data_end
)
66 ihl_len
+= iph
->ihl
* 4;
69 if (iph
->protocol
== IPPROTO_TCP
)
70 return tcp(data
, nh_off
+ ihl_len
, data_end
);
71 else if (iph
->protocol
== IPPROTO_UDP
)
72 return udp(data
, nh_off
+ ihl_len
, data_end
);
76 static int parse_ipv6(void *data
, uint64_t nh_off
, void *data_end
)
80 uint64_t ihl_len
= sizeof(struct ipv6hdr
);
84 if (ip6h
+ 1 > data_end
)
87 nexthdr
= ip6h
->nexthdr
;
89 if (nexthdr
== IPPROTO_IPIP
) {
90 iph
= data
+ nh_off
+ ihl_len
;
91 if (iph
+ 1 > data_end
)
93 ihl_len
+= iph
->ihl
* 4;
94 nexthdr
= iph
->protocol
;
95 } else if (nexthdr
== IPPROTO_IPV6
) {
96 ip6h
= data
+ nh_off
+ ihl_len
;
97 if (ip6h
+ 1 > data_end
)
99 ihl_len
+= sizeof(struct ipv6hdr
);
100 nexthdr
= ip6h
->nexthdr
;
103 if (nexthdr
== IPPROTO_TCP
)
104 return tcp(data
, nh_off
+ ihl_len
, data_end
);
105 else if (nexthdr
== IPPROTO_UDP
)
106 return udp(data
, nh_off
+ ihl_len
, data_end
);
112 uint16_t h_vlan_encapsulated_proto
;
116 int handle_ingress(struct __sk_buff
*skb
)
118 void *data
= (void *)(long)skb
->data
;
119 struct ethhdr
*eth
= data
;
120 void *data_end
= (void *)(long)skb
->data_end
;
121 uint64_t h_proto
, nh_off
;
123 nh_off
= sizeof(*eth
);
124 if (data
+ nh_off
> data_end
)
127 h_proto
= eth
->h_proto
;
129 if (h_proto
== ETH_P_8021Q
|| h_proto
== ETH_P_8021AD
) {
130 struct vlan_hdr
*vhdr
;
132 vhdr
= data
+ nh_off
;
133 nh_off
+= sizeof(struct vlan_hdr
);
134 if (data
+ nh_off
> data_end
)
136 h_proto
= vhdr
->h_vlan_encapsulated_proto
;
138 if (h_proto
== ETH_P_8021Q
|| h_proto
== ETH_P_8021AD
) {
139 struct vlan_hdr
*vhdr
;
141 vhdr
= data
+ nh_off
;
142 nh_off
+= sizeof(struct vlan_hdr
);
143 if (data
+ nh_off
> data_end
)
145 h_proto
= vhdr
->h_vlan_encapsulated_proto
;
147 if (h_proto
== htons(ETH_P_IP
))
148 return parse_ipv4(data
, nh_off
, data_end
);
149 else if (h_proto
== htons(ETH_P_IPV6
))
150 return parse_ipv6(data
, nh_off
, data_end
);
153 char _license
[] SEC("license") = "GPL";