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