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