blob: 7c2d899c8f4372b0e69518347c67ba81851f972e [file] [log] [blame]
Alexei Starovoitov68828042017-03-30 21:45:41 -07001/* Copyright (c) 2017 Facebook
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#include <stdio.h>
8#include <unistd.h>
9#include <errno.h>
10#include <string.h>
11#include <assert.h>
12#include <stdlib.h>
13
14#include <linux/types.h>
15typedef __u16 __sum16;
16#include <arpa/inet.h>
17#include <linux/if_ether.h>
18#include <linux/if_packet.h>
19#include <linux/ip.h>
20#include <linux/ipv6.h>
21#include <linux/tcp.h>
22
23#include <sys/wait.h>
24#include <sys/resource.h>
25
26#include <linux/bpf.h>
27#include <linux/err.h>
28#include <bpf/bpf.h>
29#include <bpf/libbpf.h>
Alexei Starovoitov8d48f5e2017-03-30 21:45:42 -070030#include "test_iptunnel_common.h"
Alexei Starovoitov37821612017-03-30 21:45:43 -070031#include "bpf_util.h"
Alexei Starovoitov68828042017-03-30 21:45:41 -070032
Alexei Starovoitov68828042017-03-30 21:45:41 -070033static int error_cnt, pass_cnt;
34
Alexei Starovoitov37821612017-03-30 21:45:43 -070035#define MAGIC_BYTES 123
36
Alexei Starovoitov68828042017-03-30 21:45:41 -070037/* ipv4 test vector */
38static struct {
39 struct ethhdr eth;
40 struct iphdr iph;
41 struct tcphdr tcp;
42} __packed pkt_v4 = {
Daniel Borkmann43bcf702017-04-27 01:39:34 +020043 .eth.h_proto = bpf_htons(ETH_P_IP),
Alexei Starovoitov68828042017-03-30 21:45:41 -070044 .iph.ihl = 5,
45 .iph.protocol = 6,
Daniel Borkmann43bcf702017-04-27 01:39:34 +020046 .iph.tot_len = bpf_htons(MAGIC_BYTES),
Alexei Starovoitov68828042017-03-30 21:45:41 -070047 .tcp.urg_ptr = 123,
48};
49
50/* ipv6 test vector */
51static struct {
52 struct ethhdr eth;
53 struct ipv6hdr iph;
54 struct tcphdr tcp;
55} __packed pkt_v6 = {
Daniel Borkmann43bcf702017-04-27 01:39:34 +020056 .eth.h_proto = bpf_htons(ETH_P_IPV6),
Alexei Starovoitov68828042017-03-30 21:45:41 -070057 .iph.nexthdr = 6,
Daniel Borkmann43bcf702017-04-27 01:39:34 +020058 .iph.payload_len = bpf_htons(MAGIC_BYTES),
Alexei Starovoitov68828042017-03-30 21:45:41 -070059 .tcp.urg_ptr = 123,
60};
61
62#define CHECK(condition, tag, format...) ({ \
63 int __ret = !!(condition); \
64 if (__ret) { \
65 error_cnt++; \
66 printf("%s:FAIL:%s ", __func__, tag); \
67 printf(format); \
68 } else { \
69 pass_cnt++; \
70 printf("%s:PASS:%s %d nsec\n", __func__, tag, duration);\
71 } \
72})
73
74static int bpf_prog_load(const char *file, enum bpf_prog_type type,
75 struct bpf_object **pobj, int *prog_fd)
76{
77 struct bpf_program *prog;
78 struct bpf_object *obj;
79 int err;
80
81 obj = bpf_object__open(file);
82 if (IS_ERR(obj)) {
83 error_cnt++;
84 return -ENOENT;
85 }
86
87 prog = bpf_program__next(NULL, obj);
88 if (!prog) {
89 bpf_object__close(obj);
90 error_cnt++;
91 return -ENOENT;
92 }
93
94 bpf_program__set_type(prog, type);
95 err = bpf_object__load(obj);
96 if (err) {
97 bpf_object__close(obj);
98 error_cnt++;
99 return -EINVAL;
100 }
101
102 *pobj = obj;
103 *prog_fd = bpf_program__fd(prog);
104 return 0;
105}
106
Alexei Starovoitov8d48f5e2017-03-30 21:45:42 -0700107static int bpf_find_map(const char *test, struct bpf_object *obj,
108 const char *name)
109{
110 struct bpf_map *map;
111
112 map = bpf_object__find_map_by_name(obj, name);
113 if (!map) {
114 printf("%s:FAIL:map '%s' not found\n", test, name);
115 error_cnt++;
116 return -1;
117 }
118 return bpf_map__fd(map);
119}
120
Alexei Starovoitov68828042017-03-30 21:45:41 -0700121static void test_pkt_access(void)
122{
123 const char *file = "./test_pkt_access.o";
124 struct bpf_object *obj;
125 __u32 duration, retval;
126 int err, prog_fd;
127
128 err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
129 if (err)
130 return;
131
132 err = bpf_prog_test_run(prog_fd, 100000, &pkt_v4, sizeof(pkt_v4),
133 NULL, NULL, &retval, &duration);
134 CHECK(err || errno || retval, "ipv4",
135 "err %d errno %d retval %d duration %d\n",
136 err, errno, retval, duration);
137
138 err = bpf_prog_test_run(prog_fd, 100000, &pkt_v6, sizeof(pkt_v6),
139 NULL, NULL, &retval, &duration);
140 CHECK(err || errno || retval, "ipv6",
141 "err %d errno %d retval %d duration %d\n",
142 err, errno, retval, duration);
143 bpf_object__close(obj);
144}
145
Alexei Starovoitov8d48f5e2017-03-30 21:45:42 -0700146static void test_xdp(void)
147{
148 struct vip key4 = {.protocol = 6, .family = AF_INET};
149 struct vip key6 = {.protocol = 6, .family = AF_INET6};
150 struct iptnl_info value4 = {.family = AF_INET};
151 struct iptnl_info value6 = {.family = AF_INET6};
152 const char *file = "./test_xdp.o";
153 struct bpf_object *obj;
154 char buf[128];
155 struct ipv6hdr *iph6 = (void *)buf + sizeof(struct ethhdr);
156 struct iphdr *iph = (void *)buf + sizeof(struct ethhdr);
157 __u32 duration, retval, size;
158 int err, prog_fd, map_fd;
159
160 err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
161 if (err)
162 return;
163
164 map_fd = bpf_find_map(__func__, obj, "vip2tnl");
165 if (map_fd < 0)
166 goto out;
167 bpf_map_update_elem(map_fd, &key4, &value4, 0);
168 bpf_map_update_elem(map_fd, &key6, &value6, 0);
169
170 err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4),
171 buf, &size, &retval, &duration);
172
173 CHECK(err || errno || retval != XDP_TX || size != 74 ||
174 iph->protocol != IPPROTO_IPIP, "ipv4",
175 "err %d errno %d retval %d size %d\n",
176 err, errno, retval, size);
177
178 err = bpf_prog_test_run(prog_fd, 1, &pkt_v6, sizeof(pkt_v6),
179 buf, &size, &retval, &duration);
180 CHECK(err || errno || retval != XDP_TX || size != 114 ||
181 iph6->nexthdr != IPPROTO_IPV6, "ipv6",
182 "err %d errno %d retval %d size %d\n",
183 err, errno, retval, size);
184out:
185 bpf_object__close(obj);
186}
187
Alexei Starovoitov37821612017-03-30 21:45:43 -0700188#define MAGIC_VAL 0x1234
189#define NUM_ITER 100000
190#define VIP_NUM 5
191
192static void test_l4lb(void)
193{
194 unsigned int nr_cpus = bpf_num_possible_cpus();
195 const char *file = "./test_l4lb.o";
196 struct vip key = {.protocol = 6};
197 struct vip_meta {
198 __u32 flags;
199 __u32 vip_num;
200 } value = {.vip_num = VIP_NUM};
201 __u32 stats_key = VIP_NUM;
202 struct vip_stats {
203 __u64 bytes;
204 __u64 pkts;
205 } stats[nr_cpus];
206 struct real_definition {
207 union {
208 __be32 dst;
209 __be32 dstv6[4];
210 };
211 __u8 flags;
212 } real_def = {.dst = MAGIC_VAL};
213 __u32 ch_key = 11, real_num = 3;
214 __u32 duration, retval, size;
215 int err, i, prog_fd, map_fd;
216 __u64 bytes = 0, pkts = 0;
217 struct bpf_object *obj;
218 char buf[128];
219 u32 *magic = (u32 *)buf;
220
221 err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
222 if (err)
223 return;
224
225 map_fd = bpf_find_map(__func__, obj, "vip_map");
226 if (map_fd < 0)
227 goto out;
228 bpf_map_update_elem(map_fd, &key, &value, 0);
229
230 map_fd = bpf_find_map(__func__, obj, "ch_rings");
231 if (map_fd < 0)
232 goto out;
233 bpf_map_update_elem(map_fd, &ch_key, &real_num, 0);
234
235 map_fd = bpf_find_map(__func__, obj, "reals");
236 if (map_fd < 0)
237 goto out;
238 bpf_map_update_elem(map_fd, &real_num, &real_def, 0);
239
240 err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v4, sizeof(pkt_v4),
241 buf, &size, &retval, &duration);
242 CHECK(err || errno || retval != 7/*TC_ACT_REDIRECT*/ || size != 54 ||
243 *magic != MAGIC_VAL, "ipv4",
244 "err %d errno %d retval %d size %d magic %x\n",
245 err, errno, retval, size, *magic);
246
247 err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v6, sizeof(pkt_v6),
248 buf, &size, &retval, &duration);
249 CHECK(err || errno || retval != 7/*TC_ACT_REDIRECT*/ || size != 74 ||
250 *magic != MAGIC_VAL, "ipv6",
251 "err %d errno %d retval %d size %d magic %x\n",
252 err, errno, retval, size, *magic);
253
254 map_fd = bpf_find_map(__func__, obj, "stats");
255 if (map_fd < 0)
256 goto out;
257 bpf_map_lookup_elem(map_fd, &stats_key, stats);
258 for (i = 0; i < nr_cpus; i++) {
259 bytes += stats[i].bytes;
260 pkts += stats[i].pkts;
261 }
262 if (bytes != MAGIC_BYTES * NUM_ITER * 2 || pkts != NUM_ITER * 2) {
263 error_cnt++;
264 printf("test_l4lb:FAIL:stats %lld %lld\n", bytes, pkts);
265 }
266out:
267 bpf_object__close(obj);
268}
269
Alexei Starovoitov68828042017-03-30 21:45:41 -0700270int main(void)
271{
272 struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
273
274 setrlimit(RLIMIT_MEMLOCK, &rinf);
275
276 test_pkt_access();
Alexei Starovoitov8d48f5e2017-03-30 21:45:42 -0700277 test_xdp();
Alexei Starovoitov37821612017-03-30 21:45:43 -0700278 test_l4lb();
Alexei Starovoitov68828042017-03-30 21:45:41 -0700279
280 printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt);
281 return 0;
282}