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