1169689Skan#include <uapi/linux/bpf.h>
2169689Skan#include <uapi/linux/in.h>
3169689Skan#include <uapi/linux/if.h>
4169689Skan#include <uapi/linux/if_ether.h>
5169689Skan#include <uapi/linux/ip.h>
6169689Skan#include <uapi/linux/ipv6.h>
7169689Skan#include <uapi/linux/if_tunnel.h>
8169689Skan#include <bpf/bpf_helpers.h>
9169689Skan#include "bpf_legacy.h"
10169689Skan#define IP_MF		0x2000
11169689Skan#define IP_OFFSET	0x1FFF
12169689Skan
13169689Skanstruct vlan_hdr {
14169689Skan	__be16 h_vlan_TCI;
15169689Skan	__be16 h_vlan_encapsulated_proto;
16169689Skan};
17169689Skan
18169689Skanstruct flow_key_record {
19169689Skan	__be32 src;
20169689Skan	__be32 dst;
21169689Skan	union {
22169689Skan		__be32 ports;
23169689Skan		__be16 port16[2];
24169689Skan	};
25169689Skan	__u16 thoff;
26169689Skan	__u8 ip_proto;
27169689Skan};
28169689Skan
29169689Skanstatic inline int proto_ports_offset(__u64 proto)
30169689Skan{
31169689Skan	switch (proto) {
32169689Skan	case IPPROTO_TCP:
33169689Skan	case IPPROTO_UDP:
34169689Skan	case IPPROTO_DCCP:
35169689Skan	case IPPROTO_ESP:
36169689Skan	case IPPROTO_SCTP:
37169689Skan	case IPPROTO_UDPLITE:
38169689Skan		return 0;
39169689Skan	case IPPROTO_AH:
40169689Skan		return 4;
41169689Skan	default:
42169689Skan		return 0;
43169689Skan	}
44169689Skan}
45169689Skan
46169689Skanstatic inline int ip_is_fragment(struct __sk_buff *ctx, __u64 nhoff)
47169689Skan{
48169689Skan	return load_half(ctx, nhoff + offsetof(struct iphdr, frag_off))
49169689Skan		& (IP_MF | IP_OFFSET);
50169689Skan}
51169689Skan
52169689Skanstatic inline __u32 ipv6_addr_hash(struct __sk_buff *ctx, __u64 off)
53169689Skan{
54169689Skan	__u64 w0 = load_word(ctx, off);
55169689Skan	__u64 w1 = load_word(ctx, off + 4);
56169689Skan	__u64 w2 = load_word(ctx, off + 8);
57169689Skan	__u64 w3 = load_word(ctx, off + 12);
58169689Skan
59169689Skan	return (__u32)(w0 ^ w1 ^ w2 ^ w3);
60169689Skan}
61169689Skan
62169689Skanstatic inline __u64 parse_ip(struct __sk_buff *skb, __u64 nhoff, __u64 *ip_proto,
63169689Skan			     struct flow_key_record *flow)
64169689Skan{
65169689Skan	__u64 verlen;
66169689Skan
67169689Skan	if (unlikely(ip_is_fragment(skb, nhoff)))
68169689Skan		*ip_proto = 0;
69169689Skan	else
70169689Skan		*ip_proto = load_byte(skb, nhoff + offsetof(struct iphdr, protocol));
71169689Skan
72169689Skan	if (*ip_proto != IPPROTO_GRE) {
73169689Skan		flow->src = load_word(skb, nhoff + offsetof(struct iphdr, saddr));
74169689Skan		flow->dst = load_word(skb, nhoff + offsetof(struct iphdr, daddr));
75169689Skan	}
76169689Skan
77169689Skan	verlen = load_byte(skb, nhoff + 0/*offsetof(struct iphdr, ihl)*/);
78169689Skan	if (likely(verlen == 0x45))
79169689Skan		nhoff += 20;
80169689Skan	else
81169689Skan		nhoff += (verlen & 0xF) << 2;
82169689Skan
83169689Skan	return nhoff;
84169689Skan}
85169689Skan
86169689Skanstatic inline __u64 parse_ipv6(struct __sk_buff *skb, __u64 nhoff, __u64 *ip_proto,
87169689Skan			       struct flow_key_record *flow)
88169689Skan{
89169689Skan	*ip_proto = load_byte(skb,
90169689Skan			      nhoff + offsetof(struct ipv6hdr, nexthdr));
91169689Skan	flow->src = ipv6_addr_hash(skb,
92169689Skan				   nhoff + offsetof(struct ipv6hdr, saddr));
93169689Skan	flow->dst = ipv6_addr_hash(skb,
94169689Skan				   nhoff + offsetof(struct ipv6hdr, daddr));
95169689Skan	nhoff += sizeof(struct ipv6hdr);
96169689Skan
97169689Skan	return nhoff;
98169689Skan}
99169689Skan
100169689Skanstatic inline bool flow_dissector(struct __sk_buff *skb,
101169689Skan				  struct flow_key_record *flow)
102169689Skan{
103169689Skan	__u64 nhoff = ETH_HLEN;
104169689Skan	__u64 ip_proto;
105169689Skan	__u64 proto = load_half(skb, 12);
106169689Skan	int poff;
107169689Skan
108169689Skan	if (proto == ETH_P_8021AD) {
109169689Skan		proto = load_half(skb, nhoff + offsetof(struct vlan_hdr,
110169689Skan							h_vlan_encapsulated_proto));
111169689Skan		nhoff += sizeof(struct vlan_hdr);
112169689Skan	}
113169689Skan
114169689Skan	if (proto == ETH_P_8021Q) {
115169689Skan		proto = load_half(skb, nhoff + offsetof(struct vlan_hdr,
116169689Skan							h_vlan_encapsulated_proto));
117169689Skan		nhoff += sizeof(struct vlan_hdr);
118169689Skan	}
119169689Skan
120169689Skan	if (likely(proto == ETH_P_IP))
121169689Skan		nhoff = parse_ip(skb, nhoff, &ip_proto, flow);
122169689Skan	else if (proto == ETH_P_IPV6)
123169689Skan		nhoff = parse_ipv6(skb, nhoff, &ip_proto, flow);
124169689Skan	else
125169689Skan		return false;
126169689Skan
127169689Skan	switch (ip_proto) {
128169689Skan	case IPPROTO_GRE: {
129169689Skan		struct gre_hdr {
130169689Skan			__be16 flags;
131169689Skan			__be16 proto;
132169689Skan		};
133169689Skan
134169689Skan		__u64 gre_flags = load_half(skb,
135169689Skan					    nhoff + offsetof(struct gre_hdr, flags));
136169689Skan		__u64 gre_proto = load_half(skb,
137169689Skan					    nhoff + offsetof(struct gre_hdr, proto));
138169689Skan
139169689Skan		if (gre_flags & (GRE_VERSION|GRE_ROUTING))
140169689Skan			break;
141169689Skan
142169689Skan		proto = gre_proto;
143169689Skan		nhoff += 4;
144169689Skan		if (gre_flags & GRE_CSUM)
145169689Skan			nhoff += 4;
146169689Skan		if (gre_flags & GRE_KEY)
147169689Skan			nhoff += 4;
148169689Skan		if (gre_flags & GRE_SEQ)
149169689Skan			nhoff += 4;
150169689Skan
151169689Skan		if (proto == ETH_P_8021Q) {
152169689Skan			proto = load_half(skb,
153169689Skan					  nhoff + offsetof(struct vlan_hdr,
154169689Skan							   h_vlan_encapsulated_proto));
155169689Skan			nhoff += sizeof(struct vlan_hdr);
156169689Skan		}
157169689Skan
158169689Skan		if (proto == ETH_P_IP)
159169689Skan			nhoff = parse_ip(skb, nhoff, &ip_proto, flow);
160169689Skan		else if (proto == ETH_P_IPV6)
161169689Skan			nhoff = parse_ipv6(skb, nhoff, &ip_proto, flow);
162169689Skan		else
163169689Skan			return false;
164169689Skan		break;
165169689Skan	}
166169689Skan	case IPPROTO_IPIP:
167169689Skan		nhoff = parse_ip(skb, nhoff, &ip_proto, flow);
168169689Skan		break;
169169689Skan	case IPPROTO_IPV6:
170169689Skan		nhoff = parse_ipv6(skb, nhoff, &ip_proto, flow);
171169689Skan		break;
172169689Skan	default:
173169689Skan		break;
174169689Skan	}
175169689Skan
176169689Skan	flow->ip_proto = ip_proto;
177169689Skan	poff = proto_ports_offset(ip_proto);
178169689Skan	if (poff >= 0) {
179169689Skan		nhoff += poff;
180169689Skan		flow->ports = load_word(skb, nhoff);
181169689Skan	}
182169689Skan
183169689Skan	flow->thoff = (__u16) nhoff;
184169689Skan
185169689Skan	return true;
186169689Skan}
187169689Skan
188169689Skanstruct pair {
189169689Skan	long packets;
190169689Skan	long bytes;
191169689Skan};
192169689Skan
193169689Skanstruct {
194169689Skan	__uint(type, BPF_MAP_TYPE_HASH);
195169689Skan	__type(key, __be32);
196169689Skan	__type(value, struct pair);
197169689Skan	__uint(max_entries, 1024);
198169689Skan} hash_map SEC(".maps");
199169689Skan
200169689SkanSEC("socket2")
201169689Skanint bpf_prog2(struct __sk_buff *skb)
202169689Skan{
203169689Skan	struct flow_key_record flow = {};
204169689Skan	struct pair *value;
205169689Skan	u32 key;
206169689Skan
207169689Skan	if (!flow_dissector(skb, &flow))
208169689Skan		return 0;
209169689Skan
210169689Skan	key = flow.dst;
211169689Skan	value = bpf_map_lookup_elem(&hash_map, &key);
212169689Skan	if (value) {
213169689Skan		__sync_fetch_and_add(&value->packets, 1);
214169689Skan		__sync_fetch_and_add(&value->bytes, skb->len);
215169689Skan	} else {
216169689Skan		struct pair val = {1, skb->len};
217169689Skan
218169689Skan		bpf_map_update_elem(&hash_map, &key, &val, BPF_ANY);
219169689Skan	}
220169689Skan	return 0;
221169689Skan}
222169689Skan
223169689Skanchar _license[] SEC("license") = "GPL";
224169689Skan