xref: /OK3568_Linux_fs/kernel/samples/bpf/xdp2_kern.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* Copyright (c) 2016 PLUMgrid
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or
4*4882a593Smuzhiyun  * modify it under the terms of version 2 of the GNU General Public
5*4882a593Smuzhiyun  * License as published by the Free Software Foundation.
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun #define KBUILD_MODNAME "foo"
8*4882a593Smuzhiyun #include <uapi/linux/bpf.h>
9*4882a593Smuzhiyun #include <linux/in.h>
10*4882a593Smuzhiyun #include <linux/if_ether.h>
11*4882a593Smuzhiyun #include <linux/if_packet.h>
12*4882a593Smuzhiyun #include <linux/if_vlan.h>
13*4882a593Smuzhiyun #include <linux/ip.h>
14*4882a593Smuzhiyun #include <linux/ipv6.h>
15*4882a593Smuzhiyun #include <bpf/bpf_helpers.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun struct {
18*4882a593Smuzhiyun 	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
19*4882a593Smuzhiyun 	__type(key, u32);
20*4882a593Smuzhiyun 	__type(value, long);
21*4882a593Smuzhiyun 	__uint(max_entries, 256);
22*4882a593Smuzhiyun } rxcnt SEC(".maps");
23*4882a593Smuzhiyun 
swap_src_dst_mac(void * data)24*4882a593Smuzhiyun static void swap_src_dst_mac(void *data)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	unsigned short *p = data;
27*4882a593Smuzhiyun 	unsigned short dst[3];
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun 	dst[0] = p[0];
30*4882a593Smuzhiyun 	dst[1] = p[1];
31*4882a593Smuzhiyun 	dst[2] = p[2];
32*4882a593Smuzhiyun 	p[0] = p[3];
33*4882a593Smuzhiyun 	p[1] = p[4];
34*4882a593Smuzhiyun 	p[2] = p[5];
35*4882a593Smuzhiyun 	p[3] = dst[0];
36*4882a593Smuzhiyun 	p[4] = dst[1];
37*4882a593Smuzhiyun 	p[5] = dst[2];
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun 
parse_ipv4(void * data,u64 nh_off,void * data_end)40*4882a593Smuzhiyun static int parse_ipv4(void *data, u64 nh_off, void *data_end)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	struct iphdr *iph = data + nh_off;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	if (iph + 1 > data_end)
45*4882a593Smuzhiyun 		return 0;
46*4882a593Smuzhiyun 	return iph->protocol;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun 
parse_ipv6(void * data,u64 nh_off,void * data_end)49*4882a593Smuzhiyun static int parse_ipv6(void *data, u64 nh_off, void *data_end)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	struct ipv6hdr *ip6h = data + nh_off;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	if (ip6h + 1 > data_end)
54*4882a593Smuzhiyun 		return 0;
55*4882a593Smuzhiyun 	return ip6h->nexthdr;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun SEC("xdp1")
xdp_prog1(struct xdp_md * ctx)59*4882a593Smuzhiyun int xdp_prog1(struct xdp_md *ctx)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun 	void *data_end = (void *)(long)ctx->data_end;
62*4882a593Smuzhiyun 	void *data = (void *)(long)ctx->data;
63*4882a593Smuzhiyun 	struct ethhdr *eth = data;
64*4882a593Smuzhiyun 	int rc = XDP_DROP;
65*4882a593Smuzhiyun 	long *value;
66*4882a593Smuzhiyun 	u16 h_proto;
67*4882a593Smuzhiyun 	u64 nh_off;
68*4882a593Smuzhiyun 	u32 ipproto;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	nh_off = sizeof(*eth);
71*4882a593Smuzhiyun 	if (data + nh_off > data_end)
72*4882a593Smuzhiyun 		return rc;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	h_proto = eth->h_proto;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
77*4882a593Smuzhiyun 		struct vlan_hdr *vhdr;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 		vhdr = data + nh_off;
80*4882a593Smuzhiyun 		nh_off += sizeof(struct vlan_hdr);
81*4882a593Smuzhiyun 		if (data + nh_off > data_end)
82*4882a593Smuzhiyun 			return rc;
83*4882a593Smuzhiyun 		h_proto = vhdr->h_vlan_encapsulated_proto;
84*4882a593Smuzhiyun 	}
85*4882a593Smuzhiyun 	if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
86*4882a593Smuzhiyun 		struct vlan_hdr *vhdr;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 		vhdr = data + nh_off;
89*4882a593Smuzhiyun 		nh_off += sizeof(struct vlan_hdr);
90*4882a593Smuzhiyun 		if (data + nh_off > data_end)
91*4882a593Smuzhiyun 			return rc;
92*4882a593Smuzhiyun 		h_proto = vhdr->h_vlan_encapsulated_proto;
93*4882a593Smuzhiyun 	}
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	if (h_proto == htons(ETH_P_IP))
96*4882a593Smuzhiyun 		ipproto = parse_ipv4(data, nh_off, data_end);
97*4882a593Smuzhiyun 	else if (h_proto == htons(ETH_P_IPV6))
98*4882a593Smuzhiyun 		ipproto = parse_ipv6(data, nh_off, data_end);
99*4882a593Smuzhiyun 	else
100*4882a593Smuzhiyun 		ipproto = 0;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	value = bpf_map_lookup_elem(&rxcnt, &ipproto);
103*4882a593Smuzhiyun 	if (value)
104*4882a593Smuzhiyun 		*value += 1;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	if (ipproto == IPPROTO_UDP) {
107*4882a593Smuzhiyun 		swap_src_dst_mac(data);
108*4882a593Smuzhiyun 		rc = XDP_TX;
109*4882a593Smuzhiyun 	}
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	return rc;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun char _license[] SEC("license") = "GPL";
115