blob: b59f5ed4ae40d36bf9755fa844e63597c2a6f2c1 [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"
David S. Millere06422c2017-05-01 12:58:21 -070032#include "bpf_endian.h"
Alexei Starovoitov68828042017-03-30 21:45:41 -070033
Alexei Starovoitov68828042017-03-30 21:45:41 -070034static int error_cnt, pass_cnt;
35
Alexei Starovoitov37821612017-03-30 21:45:43 -070036#define MAGIC_BYTES 123
37
Alexei Starovoitov68828042017-03-30 21:45:41 -070038/* ipv4 test vector */
39static struct {
40 struct ethhdr eth;
41 struct iphdr iph;
42 struct tcphdr tcp;
43} __packed pkt_v4 = {
Daniel Borkmann43bcf702017-04-27 01:39:34 +020044 .eth.h_proto = bpf_htons(ETH_P_IP),
Alexei Starovoitov68828042017-03-30 21:45:41 -070045 .iph.ihl = 5,
46 .iph.protocol = 6,
Daniel Borkmann43bcf702017-04-27 01:39:34 +020047 .iph.tot_len = bpf_htons(MAGIC_BYTES),
Alexei Starovoitov68828042017-03-30 21:45:41 -070048 .tcp.urg_ptr = 123,
49};
50
51/* ipv6 test vector */
52static struct {
53 struct ethhdr eth;
54 struct ipv6hdr iph;
55 struct tcphdr tcp;
56} __packed pkt_v6 = {
Daniel Borkmann43bcf702017-04-27 01:39:34 +020057 .eth.h_proto = bpf_htons(ETH_P_IPV6),
Alexei Starovoitov68828042017-03-30 21:45:41 -070058 .iph.nexthdr = 6,
Daniel Borkmann43bcf702017-04-27 01:39:34 +020059 .iph.payload_len = bpf_htons(MAGIC_BYTES),
Alexei Starovoitov68828042017-03-30 21:45:41 -070060 .tcp.urg_ptr = 123,
61};
62
63#define CHECK(condition, tag, format...) ({ \
64 int __ret = !!(condition); \
65 if (__ret) { \
66 error_cnt++; \
67 printf("%s:FAIL:%s ", __func__, tag); \
68 printf(format); \
69 } else { \
70 pass_cnt++; \
71 printf("%s:PASS:%s %d nsec\n", __func__, tag, duration);\
72 } \
73})
74
75static int bpf_prog_load(const char *file, enum bpf_prog_type type,
76 struct bpf_object **pobj, int *prog_fd)
77{
78 struct bpf_program *prog;
79 struct bpf_object *obj;
80 int err;
81
82 obj = bpf_object__open(file);
83 if (IS_ERR(obj)) {
84 error_cnt++;
85 return -ENOENT;
86 }
87
88 prog = bpf_program__next(NULL, obj);
89 if (!prog) {
90 bpf_object__close(obj);
91 error_cnt++;
92 return -ENOENT;
93 }
94
95 bpf_program__set_type(prog, type);
96 err = bpf_object__load(obj);
97 if (err) {
98 bpf_object__close(obj);
99 error_cnt++;
100 return -EINVAL;
101 }
102
103 *pobj = obj;
104 *prog_fd = bpf_program__fd(prog);
105 return 0;
106}
107
Alexei Starovoitov8d48f5e2017-03-30 21:45:42 -0700108static int bpf_find_map(const char *test, struct bpf_object *obj,
109 const char *name)
110{
111 struct bpf_map *map;
112
113 map = bpf_object__find_map_by_name(obj, name);
114 if (!map) {
115 printf("%s:FAIL:map '%s' not found\n", test, name);
116 error_cnt++;
117 return -1;
118 }
119 return bpf_map__fd(map);
120}
121
Alexei Starovoitov68828042017-03-30 21:45:41 -0700122static void test_pkt_access(void)
123{
124 const char *file = "./test_pkt_access.o";
125 struct bpf_object *obj;
126 __u32 duration, retval;
127 int err, prog_fd;
128
129 err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
130 if (err)
131 return;
132
133 err = bpf_prog_test_run(prog_fd, 100000, &pkt_v4, sizeof(pkt_v4),
134 NULL, NULL, &retval, &duration);
135 CHECK(err || errno || retval, "ipv4",
136 "err %d errno %d retval %d duration %d\n",
137 err, errno, retval, duration);
138
139 err = bpf_prog_test_run(prog_fd, 100000, &pkt_v6, sizeof(pkt_v6),
140 NULL, NULL, &retval, &duration);
141 CHECK(err || errno || retval, "ipv6",
142 "err %d errno %d retval %d duration %d\n",
143 err, errno, retval, duration);
144 bpf_object__close(obj);
145}
146
Alexei Starovoitov8d48f5e2017-03-30 21:45:42 -0700147static void test_xdp(void)
148{
149 struct vip key4 = {.protocol = 6, .family = AF_INET};
150 struct vip key6 = {.protocol = 6, .family = AF_INET6};
151 struct iptnl_info value4 = {.family = AF_INET};
152 struct iptnl_info value6 = {.family = AF_INET6};
153 const char *file = "./test_xdp.o";
154 struct bpf_object *obj;
155 char buf[128];
156 struct ipv6hdr *iph6 = (void *)buf + sizeof(struct ethhdr);
157 struct iphdr *iph = (void *)buf + sizeof(struct ethhdr);
158 __u32 duration, retval, size;
159 int err, prog_fd, map_fd;
160
161 err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
162 if (err)
163 return;
164
165 map_fd = bpf_find_map(__func__, obj, "vip2tnl");
166 if (map_fd < 0)
167 goto out;
168 bpf_map_update_elem(map_fd, &key4, &value4, 0);
169 bpf_map_update_elem(map_fd, &key6, &value6, 0);
170
171 err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4),
172 buf, &size, &retval, &duration);
173
174 CHECK(err || errno || retval != XDP_TX || size != 74 ||
175 iph->protocol != IPPROTO_IPIP, "ipv4",
176 "err %d errno %d retval %d size %d\n",
177 err, errno, retval, size);
178
179 err = bpf_prog_test_run(prog_fd, 1, &pkt_v6, sizeof(pkt_v6),
180 buf, &size, &retval, &duration);
181 CHECK(err || errno || retval != XDP_TX || size != 114 ||
182 iph6->nexthdr != IPPROTO_IPV6, "ipv6",
183 "err %d errno %d retval %d size %d\n",
184 err, errno, retval, size);
185out:
186 bpf_object__close(obj);
187}
188
Alexei Starovoitov37821612017-03-30 21:45:43 -0700189#define MAGIC_VAL 0x1234
190#define NUM_ITER 100000
191#define VIP_NUM 5
192
193static void test_l4lb(void)
194{
195 unsigned int nr_cpus = bpf_num_possible_cpus();
196 const char *file = "./test_l4lb.o";
197 struct vip key = {.protocol = 6};
198 struct vip_meta {
199 __u32 flags;
200 __u32 vip_num;
201 } value = {.vip_num = VIP_NUM};
202 __u32 stats_key = VIP_NUM;
203 struct vip_stats {
204 __u64 bytes;
205 __u64 pkts;
206 } stats[nr_cpus];
207 struct real_definition {
208 union {
209 __be32 dst;
210 __be32 dstv6[4];
211 };
212 __u8 flags;
213 } real_def = {.dst = MAGIC_VAL};
214 __u32 ch_key = 11, real_num = 3;
215 __u32 duration, retval, size;
216 int err, i, prog_fd, map_fd;
217 __u64 bytes = 0, pkts = 0;
218 struct bpf_object *obj;
219 char buf[128];
220 u32 *magic = (u32 *)buf;
221
222 err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
223 if (err)
224 return;
225
226 map_fd = bpf_find_map(__func__, obj, "vip_map");
227 if (map_fd < 0)
228 goto out;
229 bpf_map_update_elem(map_fd, &key, &value, 0);
230
231 map_fd = bpf_find_map(__func__, obj, "ch_rings");
232 if (map_fd < 0)
233 goto out;
234 bpf_map_update_elem(map_fd, &ch_key, &real_num, 0);
235
236 map_fd = bpf_find_map(__func__, obj, "reals");
237 if (map_fd < 0)
238 goto out;
239 bpf_map_update_elem(map_fd, &real_num, &real_def, 0);
240
241 err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v4, sizeof(pkt_v4),
242 buf, &size, &retval, &duration);
243 CHECK(err || errno || retval != 7/*TC_ACT_REDIRECT*/ || size != 54 ||
244 *magic != MAGIC_VAL, "ipv4",
245 "err %d errno %d retval %d size %d magic %x\n",
246 err, errno, retval, size, *magic);
247
248 err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v6, sizeof(pkt_v6),
249 buf, &size, &retval, &duration);
250 CHECK(err || errno || retval != 7/*TC_ACT_REDIRECT*/ || size != 74 ||
251 *magic != MAGIC_VAL, "ipv6",
252 "err %d errno %d retval %d size %d magic %x\n",
253 err, errno, retval, size, *magic);
254
255 map_fd = bpf_find_map(__func__, obj, "stats");
256 if (map_fd < 0)
257 goto out;
258 bpf_map_lookup_elem(map_fd, &stats_key, stats);
259 for (i = 0; i < nr_cpus; i++) {
260 bytes += stats[i].bytes;
261 pkts += stats[i].pkts;
262 }
263 if (bytes != MAGIC_BYTES * NUM_ITER * 2 || pkts != NUM_ITER * 2) {
264 error_cnt++;
265 printf("test_l4lb:FAIL:stats %lld %lld\n", bytes, pkts);
266 }
267out:
268 bpf_object__close(obj);
269}
270
Yonghong Song6ead18f2017-05-02 19:58:14 -0700271static void test_tcp_estats(void)
272{
273 const char *file = "./test_tcp_estats.o";
274 int err, prog_fd;
275 struct bpf_object *obj;
276 __u32 duration = 0;
277
278 err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd);
279 CHECK(err, "", "err %d errno %d\n", err, errno);
280 if (err)
281 return;
282
283 bpf_object__close(obj);
284}
285
Alexei Starovoitov68828042017-03-30 21:45:41 -0700286int main(void)
287{
288 struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
289
290 setrlimit(RLIMIT_MEMLOCK, &rinf);
291
292 test_pkt_access();
Alexei Starovoitov8d48f5e2017-03-30 21:45:42 -0700293 test_xdp();
Alexei Starovoitov37821612017-03-30 21:45:43 -0700294 test_l4lb();
Yonghong Song6ead18f2017-05-02 19:58:14 -0700295 test_tcp_estats();
Alexei Starovoitov68828042017-03-30 21:45:41 -0700296
297 printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt);
298 return 0;
299}