1fbe33108SAlexei Starovoitov #include <uapi/linux/bpf.h>
2fbe33108SAlexei Starovoitov #include <uapi/linux/in.h>
3fbe33108SAlexei Starovoitov #include <uapi/linux/if.h>
4fbe33108SAlexei Starovoitov #include <uapi/linux/if_ether.h>
5fbe33108SAlexei Starovoitov #include <uapi/linux/ip.h>
6fbe33108SAlexei Starovoitov #include <uapi/linux/ipv6.h>
7fbe33108SAlexei Starovoitov #include <uapi/linux/if_tunnel.h>
8*03421a92SYonghong Song #include <bpf/bpf_helpers.h>
9*03421a92SYonghong Song #include "bpf_legacy.h"
10fbe33108SAlexei Starovoitov #define IP_MF 0x2000
11fbe33108SAlexei Starovoitov #define IP_OFFSET 0x1FFF
12fbe33108SAlexei Starovoitov
13fbe33108SAlexei Starovoitov struct vlan_hdr {
14fbe33108SAlexei Starovoitov __be16 h_vlan_TCI;
15fbe33108SAlexei Starovoitov __be16 h_vlan_encapsulated_proto;
16fbe33108SAlexei Starovoitov };
17fbe33108SAlexei Starovoitov
1832c00979SPrashant Bhole struct flow_key_record {
19fbe33108SAlexei Starovoitov __be32 src;
20fbe33108SAlexei Starovoitov __be32 dst;
21fbe33108SAlexei Starovoitov union {
22fbe33108SAlexei Starovoitov __be32 ports;
23fbe33108SAlexei Starovoitov __be16 port16[2];
24fbe33108SAlexei Starovoitov };
25fbe33108SAlexei Starovoitov __u16 thoff;
26fbe33108SAlexei Starovoitov __u8 ip_proto;
27fbe33108SAlexei Starovoitov };
28fbe33108SAlexei Starovoitov
proto_ports_offset(__u64 proto)29fbe33108SAlexei Starovoitov static inline int proto_ports_offset(__u64 proto)
30fbe33108SAlexei Starovoitov {
31fbe33108SAlexei Starovoitov switch (proto) {
32fbe33108SAlexei Starovoitov case IPPROTO_TCP:
33fbe33108SAlexei Starovoitov case IPPROTO_UDP:
34fbe33108SAlexei Starovoitov case IPPROTO_DCCP:
35fbe33108SAlexei Starovoitov case IPPROTO_ESP:
36fbe33108SAlexei Starovoitov case IPPROTO_SCTP:
37fbe33108SAlexei Starovoitov case IPPROTO_UDPLITE:
38fbe33108SAlexei Starovoitov return 0;
39fbe33108SAlexei Starovoitov case IPPROTO_AH:
40fbe33108SAlexei Starovoitov return 4;
41fbe33108SAlexei Starovoitov default:
42fbe33108SAlexei Starovoitov return 0;
43fbe33108SAlexei Starovoitov }
44fbe33108SAlexei Starovoitov }
45fbe33108SAlexei Starovoitov
ip_is_fragment(struct __sk_buff * ctx,__u64 nhoff)46614cd3bdSAlexei Starovoitov static inline int ip_is_fragment(struct __sk_buff *ctx, __u64 nhoff)
47fbe33108SAlexei Starovoitov {
48fbe33108SAlexei Starovoitov return load_half(ctx, nhoff + offsetof(struct iphdr, frag_off))
49fbe33108SAlexei Starovoitov & (IP_MF | IP_OFFSET);
50fbe33108SAlexei Starovoitov }
51fbe33108SAlexei Starovoitov
ipv6_addr_hash(struct __sk_buff * ctx,__u64 off)52614cd3bdSAlexei Starovoitov static inline __u32 ipv6_addr_hash(struct __sk_buff *ctx, __u64 off)
53fbe33108SAlexei Starovoitov {
54fbe33108SAlexei Starovoitov __u64 w0 = load_word(ctx, off);
55fbe33108SAlexei Starovoitov __u64 w1 = load_word(ctx, off + 4);
56fbe33108SAlexei Starovoitov __u64 w2 = load_word(ctx, off + 8);
57fbe33108SAlexei Starovoitov __u64 w3 = load_word(ctx, off + 12);
58fbe33108SAlexei Starovoitov
59fbe33108SAlexei Starovoitov return (__u32)(w0 ^ w1 ^ w2 ^ w3);
60fbe33108SAlexei Starovoitov }
61fbe33108SAlexei Starovoitov
parse_ip(struct __sk_buff * skb,__u64 nhoff,__u64 * ip_proto,struct flow_key_record * flow)62614cd3bdSAlexei Starovoitov static inline __u64 parse_ip(struct __sk_buff *skb, __u64 nhoff, __u64 *ip_proto,
6332c00979SPrashant Bhole struct flow_key_record *flow)
64fbe33108SAlexei Starovoitov {
65fbe33108SAlexei Starovoitov __u64 verlen;
66fbe33108SAlexei Starovoitov
67fbe33108SAlexei Starovoitov if (unlikely(ip_is_fragment(skb, nhoff)))
68fbe33108SAlexei Starovoitov *ip_proto = 0;
69fbe33108SAlexei Starovoitov else
70fbe33108SAlexei Starovoitov *ip_proto = load_byte(skb, nhoff + offsetof(struct iphdr, protocol));
71fbe33108SAlexei Starovoitov
72fbe33108SAlexei Starovoitov if (*ip_proto != IPPROTO_GRE) {
73fbe33108SAlexei Starovoitov flow->src = load_word(skb, nhoff + offsetof(struct iphdr, saddr));
74fbe33108SAlexei Starovoitov flow->dst = load_word(skb, nhoff + offsetof(struct iphdr, daddr));
75fbe33108SAlexei Starovoitov }
76fbe33108SAlexei Starovoitov
77fbe33108SAlexei Starovoitov verlen = load_byte(skb, nhoff + 0/*offsetof(struct iphdr, ihl)*/);
78fbe33108SAlexei Starovoitov if (likely(verlen == 0x45))
79fbe33108SAlexei Starovoitov nhoff += 20;
80fbe33108SAlexei Starovoitov else
81fbe33108SAlexei Starovoitov nhoff += (verlen & 0xF) << 2;
82fbe33108SAlexei Starovoitov
83fbe33108SAlexei Starovoitov return nhoff;
84fbe33108SAlexei Starovoitov }
85fbe33108SAlexei Starovoitov
parse_ipv6(struct __sk_buff * skb,__u64 nhoff,__u64 * ip_proto,struct flow_key_record * flow)86614cd3bdSAlexei Starovoitov static inline __u64 parse_ipv6(struct __sk_buff *skb, __u64 nhoff, __u64 *ip_proto,
8732c00979SPrashant Bhole struct flow_key_record *flow)
88fbe33108SAlexei Starovoitov {
89fbe33108SAlexei Starovoitov *ip_proto = load_byte(skb,
90fbe33108SAlexei Starovoitov nhoff + offsetof(struct ipv6hdr, nexthdr));
91fbe33108SAlexei Starovoitov flow->src = ipv6_addr_hash(skb,
92fbe33108SAlexei Starovoitov nhoff + offsetof(struct ipv6hdr, saddr));
93fbe33108SAlexei Starovoitov flow->dst = ipv6_addr_hash(skb,
94fbe33108SAlexei Starovoitov nhoff + offsetof(struct ipv6hdr, daddr));
95fbe33108SAlexei Starovoitov nhoff += sizeof(struct ipv6hdr);
96fbe33108SAlexei Starovoitov
97fbe33108SAlexei Starovoitov return nhoff;
98fbe33108SAlexei Starovoitov }
99fbe33108SAlexei Starovoitov
flow_dissector(struct __sk_buff * skb,struct flow_key_record * flow)10032c00979SPrashant Bhole static inline bool flow_dissector(struct __sk_buff *skb,
10132c00979SPrashant Bhole struct flow_key_record *flow)
102fbe33108SAlexei Starovoitov {
103fbe33108SAlexei Starovoitov __u64 nhoff = ETH_HLEN;
104fbe33108SAlexei Starovoitov __u64 ip_proto;
105fbe33108SAlexei Starovoitov __u64 proto = load_half(skb, 12);
106fbe33108SAlexei Starovoitov int poff;
107fbe33108SAlexei Starovoitov
108fbe33108SAlexei Starovoitov if (proto == ETH_P_8021AD) {
109fbe33108SAlexei Starovoitov proto = load_half(skb, nhoff + offsetof(struct vlan_hdr,
110fbe33108SAlexei Starovoitov h_vlan_encapsulated_proto));
111fbe33108SAlexei Starovoitov nhoff += sizeof(struct vlan_hdr);
112fbe33108SAlexei Starovoitov }
113fbe33108SAlexei Starovoitov
114fbe33108SAlexei Starovoitov if (proto == ETH_P_8021Q) {
115fbe33108SAlexei Starovoitov proto = load_half(skb, nhoff + offsetof(struct vlan_hdr,
116fbe33108SAlexei Starovoitov h_vlan_encapsulated_proto));
117fbe33108SAlexei Starovoitov nhoff += sizeof(struct vlan_hdr);
118fbe33108SAlexei Starovoitov }
119fbe33108SAlexei Starovoitov
120fbe33108SAlexei Starovoitov if (likely(proto == ETH_P_IP))
121fbe33108SAlexei Starovoitov nhoff = parse_ip(skb, nhoff, &ip_proto, flow);
122fbe33108SAlexei Starovoitov else if (proto == ETH_P_IPV6)
123fbe33108SAlexei Starovoitov nhoff = parse_ipv6(skb, nhoff, &ip_proto, flow);
124fbe33108SAlexei Starovoitov else
125fbe33108SAlexei Starovoitov return false;
126fbe33108SAlexei Starovoitov
127fbe33108SAlexei Starovoitov switch (ip_proto) {
128fbe33108SAlexei Starovoitov case IPPROTO_GRE: {
129fbe33108SAlexei Starovoitov struct gre_hdr {
130fbe33108SAlexei Starovoitov __be16 flags;
131fbe33108SAlexei Starovoitov __be16 proto;
132fbe33108SAlexei Starovoitov };
133fbe33108SAlexei Starovoitov
134fbe33108SAlexei Starovoitov __u64 gre_flags = load_half(skb,
135fbe33108SAlexei Starovoitov nhoff + offsetof(struct gre_hdr, flags));
136fbe33108SAlexei Starovoitov __u64 gre_proto = load_half(skb,
137fbe33108SAlexei Starovoitov nhoff + offsetof(struct gre_hdr, proto));
138fbe33108SAlexei Starovoitov
139fbe33108SAlexei Starovoitov if (gre_flags & (GRE_VERSION|GRE_ROUTING))
140fbe33108SAlexei Starovoitov break;
141fbe33108SAlexei Starovoitov
142fbe33108SAlexei Starovoitov proto = gre_proto;
143fbe33108SAlexei Starovoitov nhoff += 4;
144fbe33108SAlexei Starovoitov if (gre_flags & GRE_CSUM)
145fbe33108SAlexei Starovoitov nhoff += 4;
146fbe33108SAlexei Starovoitov if (gre_flags & GRE_KEY)
147fbe33108SAlexei Starovoitov nhoff += 4;
148fbe33108SAlexei Starovoitov if (gre_flags & GRE_SEQ)
149fbe33108SAlexei Starovoitov nhoff += 4;
150fbe33108SAlexei Starovoitov
151fbe33108SAlexei Starovoitov if (proto == ETH_P_8021Q) {
152fbe33108SAlexei Starovoitov proto = load_half(skb,
153fbe33108SAlexei Starovoitov nhoff + offsetof(struct vlan_hdr,
154fbe33108SAlexei Starovoitov h_vlan_encapsulated_proto));
155fbe33108SAlexei Starovoitov nhoff += sizeof(struct vlan_hdr);
156fbe33108SAlexei Starovoitov }
157fbe33108SAlexei Starovoitov
158fbe33108SAlexei Starovoitov if (proto == ETH_P_IP)
159fbe33108SAlexei Starovoitov nhoff = parse_ip(skb, nhoff, &ip_proto, flow);
160fbe33108SAlexei Starovoitov else if (proto == ETH_P_IPV6)
161fbe33108SAlexei Starovoitov nhoff = parse_ipv6(skb, nhoff, &ip_proto, flow);
162fbe33108SAlexei Starovoitov else
163fbe33108SAlexei Starovoitov return false;
164fbe33108SAlexei Starovoitov break;
165fbe33108SAlexei Starovoitov }
166fbe33108SAlexei Starovoitov case IPPROTO_IPIP:
167fbe33108SAlexei Starovoitov nhoff = parse_ip(skb, nhoff, &ip_proto, flow);
168fbe33108SAlexei Starovoitov break;
169fbe33108SAlexei Starovoitov case IPPROTO_IPV6:
170fbe33108SAlexei Starovoitov nhoff = parse_ipv6(skb, nhoff, &ip_proto, flow);
171fbe33108SAlexei Starovoitov break;
172fbe33108SAlexei Starovoitov default:
173fbe33108SAlexei Starovoitov break;
174fbe33108SAlexei Starovoitov }
175fbe33108SAlexei Starovoitov
176fbe33108SAlexei Starovoitov flow->ip_proto = ip_proto;
177fbe33108SAlexei Starovoitov poff = proto_ports_offset(ip_proto);
178fbe33108SAlexei Starovoitov if (poff >= 0) {
179fbe33108SAlexei Starovoitov nhoff += poff;
180fbe33108SAlexei Starovoitov flow->ports = load_word(skb, nhoff);
181fbe33108SAlexei Starovoitov }
182fbe33108SAlexei Starovoitov
183fbe33108SAlexei Starovoitov flow->thoff = (__u16) nhoff;
184fbe33108SAlexei Starovoitov
185fbe33108SAlexei Starovoitov return true;
186fbe33108SAlexei Starovoitov }
187fbe33108SAlexei Starovoitov
188614cd3bdSAlexei Starovoitov struct pair {
189614cd3bdSAlexei Starovoitov long packets;
190614cd3bdSAlexei Starovoitov long bytes;
191614cd3bdSAlexei Starovoitov };
192614cd3bdSAlexei Starovoitov
193451d1dc8SDaniel T. Lee struct {
194451d1dc8SDaniel T. Lee __uint(type, BPF_MAP_TYPE_HASH);
195451d1dc8SDaniel T. Lee __type(key, __be32);
196451d1dc8SDaniel T. Lee __type(value, struct pair);
197451d1dc8SDaniel T. Lee __uint(max_entries, 1024);
198451d1dc8SDaniel T. Lee } hash_map SEC(".maps");
199fbe33108SAlexei Starovoitov
200fbe33108SAlexei Starovoitov SEC("socket2")
bpf_prog2(struct __sk_buff * skb)201614cd3bdSAlexei Starovoitov int bpf_prog2(struct __sk_buff *skb)
202fbe33108SAlexei Starovoitov {
20332c00979SPrashant Bhole struct flow_key_record flow = {};
204614cd3bdSAlexei Starovoitov struct pair *value;
205fbe33108SAlexei Starovoitov u32 key;
206fbe33108SAlexei Starovoitov
207fbe33108SAlexei Starovoitov if (!flow_dissector(skb, &flow))
208fbe33108SAlexei Starovoitov return 0;
209fbe33108SAlexei Starovoitov
210fbe33108SAlexei Starovoitov key = flow.dst;
211fbe33108SAlexei Starovoitov value = bpf_map_lookup_elem(&hash_map, &key);
212fbe33108SAlexei Starovoitov if (value) {
213614cd3bdSAlexei Starovoitov __sync_fetch_and_add(&value->packets, 1);
214614cd3bdSAlexei Starovoitov __sync_fetch_and_add(&value->bytes, skb->len);
215fbe33108SAlexei Starovoitov } else {
216614cd3bdSAlexei Starovoitov struct pair val = {1, skb->len};
217fbe33108SAlexei Starovoitov
218fbe33108SAlexei Starovoitov bpf_map_update_elem(&hash_map, &key, &val, BPF_ANY);
219fbe33108SAlexei Starovoitov }
220fbe33108SAlexei Starovoitov return 0;
221fbe33108SAlexei Starovoitov }
222fbe33108SAlexei Starovoitov
223fbe33108SAlexei Starovoitov char _license[] SEC("license") = "GPL";
224