Home | History | Annotate | Download | only in bpf
      1 /* 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 #include <time.h>
     14 
     15 #include <linux/types.h>
     16 typedef __u16 __sum16;
     17 #include <arpa/inet.h>
     18 #include <linux/if_ether.h>
     19 #include <linux/if_packet.h>
     20 #include <linux/ip.h>
     21 #include <linux/ipv6.h>
     22 #include <linux/tcp.h>
     23 #include <linux/filter.h>
     24 #include <linux/unistd.h>
     25 
     26 #include <sys/wait.h>
     27 #include <sys/resource.h>
     28 #include <sys/types.h>
     29 #include <fcntl.h>
     30 
     31 #include <linux/bpf.h>
     32 #include <linux/err.h>
     33 #include <bpf/bpf.h>
     34 #include <bpf/libbpf.h>
     35 #include "test_iptunnel_common.h"
     36 #include "bpf_util.h"
     37 #include "bpf_endian.h"
     38 
     39 static int error_cnt, pass_cnt;
     40 
     41 #define MAGIC_BYTES 123
     42 
     43 /* ipv4 test vector */
     44 static struct {
     45 	struct ethhdr eth;
     46 	struct iphdr iph;
     47 	struct tcphdr tcp;
     48 } __packed pkt_v4 = {
     49 	.eth.h_proto = bpf_htons(ETH_P_IP),
     50 	.iph.ihl = 5,
     51 	.iph.protocol = 6,
     52 	.iph.tot_len = bpf_htons(MAGIC_BYTES),
     53 	.tcp.urg_ptr = 123,
     54 };
     55 
     56 /* ipv6 test vector */
     57 static struct {
     58 	struct ethhdr eth;
     59 	struct ipv6hdr iph;
     60 	struct tcphdr tcp;
     61 } __packed pkt_v6 = {
     62 	.eth.h_proto = bpf_htons(ETH_P_IPV6),
     63 	.iph.nexthdr = 6,
     64 	.iph.payload_len = bpf_htons(MAGIC_BYTES),
     65 	.tcp.urg_ptr = 123,
     66 };
     67 
     68 #define CHECK(condition, tag, format...) ({				\
     69 	int __ret = !!(condition);					\
     70 	if (__ret) {							\
     71 		error_cnt++;						\
     72 		printf("%s:FAIL:%s ", __func__, tag);			\
     73 		printf(format);						\
     74 	} else {							\
     75 		pass_cnt++;						\
     76 		printf("%s:PASS:%s %d nsec\n", __func__, tag, duration);\
     77 	}								\
     78 	__ret;								\
     79 })
     80 
     81 static int bpf_find_map(const char *test, struct bpf_object *obj,
     82 			const char *name)
     83 {
     84 	struct bpf_map *map;
     85 
     86 	map = bpf_object__find_map_by_name(obj, name);
     87 	if (!map) {
     88 		printf("%s:FAIL:map '%s' not found\n", test, name);
     89 		error_cnt++;
     90 		return -1;
     91 	}
     92 	return bpf_map__fd(map);
     93 }
     94 
     95 static void test_pkt_access(void)
     96 {
     97 	const char *file = "./test_pkt_access.o";
     98 	struct bpf_object *obj;
     99 	__u32 duration, retval;
    100 	int err, prog_fd;
    101 
    102 	err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
    103 	if (err) {
    104 		error_cnt++;
    105 		return;
    106 	}
    107 
    108 	err = bpf_prog_test_run(prog_fd, 100000, &pkt_v4, sizeof(pkt_v4),
    109 				NULL, NULL, &retval, &duration);
    110 	CHECK(err || errno || retval, "ipv4",
    111 	      "err %d errno %d retval %d duration %d\n",
    112 	      err, errno, retval, duration);
    113 
    114 	err = bpf_prog_test_run(prog_fd, 100000, &pkt_v6, sizeof(pkt_v6),
    115 				NULL, NULL, &retval, &duration);
    116 	CHECK(err || errno || retval, "ipv6",
    117 	      "err %d errno %d retval %d duration %d\n",
    118 	      err, errno, retval, duration);
    119 	bpf_object__close(obj);
    120 }
    121 
    122 static void test_xdp(void)
    123 {
    124 	struct vip key4 = {.protocol = 6, .family = AF_INET};
    125 	struct vip key6 = {.protocol = 6, .family = AF_INET6};
    126 	struct iptnl_info value4 = {.family = AF_INET};
    127 	struct iptnl_info value6 = {.family = AF_INET6};
    128 	const char *file = "./test_xdp.o";
    129 	struct bpf_object *obj;
    130 	char buf[128];
    131 	struct ipv6hdr *iph6 = (void *)buf + sizeof(struct ethhdr);
    132 	struct iphdr *iph = (void *)buf + sizeof(struct ethhdr);
    133 	__u32 duration, retval, size;
    134 	int err, prog_fd, map_fd;
    135 
    136 	err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
    137 	if (err) {
    138 		error_cnt++;
    139 		return;
    140 	}
    141 
    142 	map_fd = bpf_find_map(__func__, obj, "vip2tnl");
    143 	if (map_fd < 0)
    144 		goto out;
    145 	bpf_map_update_elem(map_fd, &key4, &value4, 0);
    146 	bpf_map_update_elem(map_fd, &key6, &value6, 0);
    147 
    148 	err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4),
    149 				buf, &size, &retval, &duration);
    150 
    151 	CHECK(err || errno || retval != XDP_TX || size != 74 ||
    152 	      iph->protocol != IPPROTO_IPIP, "ipv4",
    153 	      "err %d errno %d retval %d size %d\n",
    154 	      err, errno, retval, size);
    155 
    156 	err = bpf_prog_test_run(prog_fd, 1, &pkt_v6, sizeof(pkt_v6),
    157 				buf, &size, &retval, &duration);
    158 	CHECK(err || errno || retval != XDP_TX || size != 114 ||
    159 	      iph6->nexthdr != IPPROTO_IPV6, "ipv6",
    160 	      "err %d errno %d retval %d size %d\n",
    161 	      err, errno, retval, size);
    162 out:
    163 	bpf_object__close(obj);
    164 }
    165 
    166 #define MAGIC_VAL 0x1234
    167 #define NUM_ITER 100000
    168 #define VIP_NUM 5
    169 
    170 static void test_l4lb(void)
    171 {
    172 	unsigned int nr_cpus = bpf_num_possible_cpus();
    173 	const char *file = "./test_l4lb.o";
    174 	struct vip key = {.protocol = 6};
    175 	struct vip_meta {
    176 		__u32 flags;
    177 		__u32 vip_num;
    178 	} value = {.vip_num = VIP_NUM};
    179 	__u32 stats_key = VIP_NUM;
    180 	struct vip_stats {
    181 		__u64 bytes;
    182 		__u64 pkts;
    183 	} stats[nr_cpus];
    184 	struct real_definition {
    185 		union {
    186 			__be32 dst;
    187 			__be32 dstv6[4];
    188 		};
    189 		__u8 flags;
    190 	} real_def = {.dst = MAGIC_VAL};
    191 	__u32 ch_key = 11, real_num = 3;
    192 	__u32 duration, retval, size;
    193 	int err, i, prog_fd, map_fd;
    194 	__u64 bytes = 0, pkts = 0;
    195 	struct bpf_object *obj;
    196 	char buf[128];
    197 	u32 *magic = (u32 *)buf;
    198 
    199 	err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
    200 	if (err) {
    201 		error_cnt++;
    202 		return;
    203 	}
    204 
    205 	map_fd = bpf_find_map(__func__, obj, "vip_map");
    206 	if (map_fd < 0)
    207 		goto out;
    208 	bpf_map_update_elem(map_fd, &key, &value, 0);
    209 
    210 	map_fd = bpf_find_map(__func__, obj, "ch_rings");
    211 	if (map_fd < 0)
    212 		goto out;
    213 	bpf_map_update_elem(map_fd, &ch_key, &real_num, 0);
    214 
    215 	map_fd = bpf_find_map(__func__, obj, "reals");
    216 	if (map_fd < 0)
    217 		goto out;
    218 	bpf_map_update_elem(map_fd, &real_num, &real_def, 0);
    219 
    220 	err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v4, sizeof(pkt_v4),
    221 				buf, &size, &retval, &duration);
    222 	CHECK(err || errno || retval != 7/*TC_ACT_REDIRECT*/ || size != 54 ||
    223 	      *magic != MAGIC_VAL, "ipv4",
    224 	      "err %d errno %d retval %d size %d magic %x\n",
    225 	      err, errno, retval, size, *magic);
    226 
    227 	err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v6, sizeof(pkt_v6),
    228 				buf, &size, &retval, &duration);
    229 	CHECK(err || errno || retval != 7/*TC_ACT_REDIRECT*/ || size != 74 ||
    230 	      *magic != MAGIC_VAL, "ipv6",
    231 	      "err %d errno %d retval %d size %d magic %x\n",
    232 	      err, errno, retval, size, *magic);
    233 
    234 	map_fd = bpf_find_map(__func__, obj, "stats");
    235 	if (map_fd < 0)
    236 		goto out;
    237 	bpf_map_lookup_elem(map_fd, &stats_key, stats);
    238 	for (i = 0; i < nr_cpus; i++) {
    239 		bytes += stats[i].bytes;
    240 		pkts += stats[i].pkts;
    241 	}
    242 	if (bytes != MAGIC_BYTES * NUM_ITER * 2 || pkts != NUM_ITER * 2) {
    243 		error_cnt++;
    244 		printf("test_l4lb:FAIL:stats %lld %lld\n", bytes, pkts);
    245 	}
    246 out:
    247 	bpf_object__close(obj);
    248 }
    249 
    250 static void test_tcp_estats(void)
    251 {
    252 	const char *file = "./test_tcp_estats.o";
    253 	int err, prog_fd;
    254 	struct bpf_object *obj;
    255 	__u32 duration = 0;
    256 
    257 	err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd);
    258 	CHECK(err, "", "err %d errno %d\n", err, errno);
    259 	if (err) {
    260 		error_cnt++;
    261 		return;
    262 	}
    263 
    264 	bpf_object__close(obj);
    265 }
    266 
    267 static inline __u64 ptr_to_u64(const void *ptr)
    268 {
    269 	return (__u64) (unsigned long) ptr;
    270 }
    271 
    272 static void test_bpf_obj_id(void)
    273 {
    274 	const __u64 array_magic_value = 0xfaceb00c;
    275 	const __u32 array_key = 0;
    276 	const int nr_iters = 2;
    277 	const char *file = "./test_obj_id.o";
    278 	const char *jit_sysctl = "/proc/sys/net/core/bpf_jit_enable";
    279 	const char *expected_prog_name = "test_obj_id";
    280 	const char *expected_map_name = "test_map_id";
    281 	const __u64 nsec_per_sec = 1000000000;
    282 
    283 	struct bpf_object *objs[nr_iters];
    284 	int prog_fds[nr_iters], map_fds[nr_iters];
    285 	/* +1 to test for the info_len returned by kernel */
    286 	struct bpf_prog_info prog_infos[nr_iters + 1];
    287 	struct bpf_map_info map_infos[nr_iters + 1];
    288 	/* Each prog only uses one map. +1 to test nr_map_ids
    289 	 * returned by kernel.
    290 	 */
    291 	__u32 map_ids[nr_iters + 1];
    292 	char jited_insns[128], xlated_insns[128], zeros[128];
    293 	__u32 i, next_id, info_len, nr_id_found, duration = 0;
    294 	struct timespec real_time_ts, boot_time_ts;
    295 	int sysctl_fd, jit_enabled = 0, err = 0;
    296 	__u64 array_value;
    297 	uid_t my_uid = getuid();
    298 	time_t now, load_time;
    299 
    300 	sysctl_fd = open(jit_sysctl, 0, O_RDONLY);
    301 	if (sysctl_fd != -1) {
    302 		char tmpc;
    303 
    304 		if (read(sysctl_fd, &tmpc, sizeof(tmpc)) == 1)
    305 			jit_enabled = (tmpc != '0');
    306 		close(sysctl_fd);
    307 	}
    308 
    309 	err = bpf_prog_get_fd_by_id(0);
    310 	CHECK(err >= 0 || errno != ENOENT,
    311 	      "get-fd-by-notexist-prog-id", "err %d errno %d\n", err, errno);
    312 
    313 	err = bpf_map_get_fd_by_id(0);
    314 	CHECK(err >= 0 || errno != ENOENT,
    315 	      "get-fd-by-notexist-map-id", "err %d errno %d\n", err, errno);
    316 
    317 	for (i = 0; i < nr_iters; i++)
    318 		objs[i] = NULL;
    319 
    320 	/* Check bpf_obj_get_info_by_fd() */
    321 	bzero(zeros, sizeof(zeros));
    322 	for (i = 0; i < nr_iters; i++) {
    323 		now = time(NULL);
    324 		err = bpf_prog_load(file, BPF_PROG_TYPE_SOCKET_FILTER,
    325 				    &objs[i], &prog_fds[i]);
    326 		/* test_obj_id.o is a dumb prog. It should never fail
    327 		 * to load.
    328 		 */
    329 		if (err)
    330 			error_cnt++;
    331 		assert(!err);
    332 
    333 		/* Insert a magic value to the map */
    334 		map_fds[i] = bpf_find_map(__func__, objs[i], "test_map_id");
    335 		assert(map_fds[i] >= 0);
    336 		err = bpf_map_update_elem(map_fds[i], &array_key,
    337 					  &array_magic_value, 0);
    338 		assert(!err);
    339 
    340 		/* Check getting map info */
    341 		info_len = sizeof(struct bpf_map_info) * 2;
    342 		bzero(&map_infos[i], info_len);
    343 		err = bpf_obj_get_info_by_fd(map_fds[i], &map_infos[i],
    344 					     &info_len);
    345 		if (CHECK(err ||
    346 			  map_infos[i].type != BPF_MAP_TYPE_ARRAY ||
    347 			  map_infos[i].key_size != sizeof(__u32) ||
    348 			  map_infos[i].value_size != sizeof(__u64) ||
    349 			  map_infos[i].max_entries != 1 ||
    350 			  map_infos[i].map_flags != 0 ||
    351 			  info_len != sizeof(struct bpf_map_info) ||
    352 			  strcmp((char *)map_infos[i].name, expected_map_name),
    353 			  "get-map-info(fd)",
    354 			  "err %d errno %d type %d(%d) info_len %u(%Zu) key_size %u value_size %u max_entries %u map_flags %X name %s(%s)\n",
    355 			  err, errno,
    356 			  map_infos[i].type, BPF_MAP_TYPE_ARRAY,
    357 			  info_len, sizeof(struct bpf_map_info),
    358 			  map_infos[i].key_size,
    359 			  map_infos[i].value_size,
    360 			  map_infos[i].max_entries,
    361 			  map_infos[i].map_flags,
    362 			  map_infos[i].name, expected_map_name))
    363 			goto done;
    364 
    365 		/* Check getting prog info */
    366 		info_len = sizeof(struct bpf_prog_info) * 2;
    367 		bzero(&prog_infos[i], info_len);
    368 		bzero(jited_insns, sizeof(jited_insns));
    369 		bzero(xlated_insns, sizeof(xlated_insns));
    370 		prog_infos[i].jited_prog_insns = ptr_to_u64(jited_insns);
    371 		prog_infos[i].jited_prog_len = sizeof(jited_insns);
    372 		prog_infos[i].xlated_prog_insns = ptr_to_u64(xlated_insns);
    373 		prog_infos[i].xlated_prog_len = sizeof(xlated_insns);
    374 		prog_infos[i].map_ids = ptr_to_u64(map_ids + i);
    375 		prog_infos[i].nr_map_ids = 2;
    376 		err = clock_gettime(CLOCK_REALTIME, &real_time_ts);
    377 		assert(!err);
    378 		err = clock_gettime(CLOCK_BOOTTIME, &boot_time_ts);
    379 		assert(!err);
    380 		err = bpf_obj_get_info_by_fd(prog_fds[i], &prog_infos[i],
    381 					     &info_len);
    382 		load_time = (real_time_ts.tv_sec - boot_time_ts.tv_sec)
    383 			+ (prog_infos[i].load_time / nsec_per_sec);
    384 		if (CHECK(err ||
    385 			  prog_infos[i].type != BPF_PROG_TYPE_SOCKET_FILTER ||
    386 			  info_len != sizeof(struct bpf_prog_info) ||
    387 			  (jit_enabled && !prog_infos[i].jited_prog_len) ||
    388 			  (jit_enabled &&
    389 			   !memcmp(jited_insns, zeros, sizeof(zeros))) ||
    390 			  !prog_infos[i].xlated_prog_len ||
    391 			  !memcmp(xlated_insns, zeros, sizeof(zeros)) ||
    392 			  load_time < now - 60 || load_time > now + 60 ||
    393 			  prog_infos[i].created_by_uid != my_uid ||
    394 			  prog_infos[i].nr_map_ids != 1 ||
    395 			  *(int *)prog_infos[i].map_ids != map_infos[i].id ||
    396 			  strcmp((char *)prog_infos[i].name, expected_prog_name),
    397 			  "get-prog-info(fd)",
    398 			  "err %d errno %d i %d type %d(%d) info_len %u(%Zu) jit_enabled %d jited_prog_len %u xlated_prog_len %u jited_prog %d xlated_prog %d load_time %lu(%lu) uid %u(%u) nr_map_ids %u(%u) map_id %u(%u) name %s(%s)\n",
    399 			  err, errno, i,
    400 			  prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER,
    401 			  info_len, sizeof(struct bpf_prog_info),
    402 			  jit_enabled,
    403 			  prog_infos[i].jited_prog_len,
    404 			  prog_infos[i].xlated_prog_len,
    405 			  !!memcmp(jited_insns, zeros, sizeof(zeros)),
    406 			  !!memcmp(xlated_insns, zeros, sizeof(zeros)),
    407 			  load_time, now,
    408 			  prog_infos[i].created_by_uid, my_uid,
    409 			  prog_infos[i].nr_map_ids, 1,
    410 			  *(int *)prog_infos[i].map_ids, map_infos[i].id,
    411 			  prog_infos[i].name, expected_prog_name))
    412 			goto done;
    413 	}
    414 
    415 	/* Check bpf_prog_get_next_id() */
    416 	nr_id_found = 0;
    417 	next_id = 0;
    418 	while (!bpf_prog_get_next_id(next_id, &next_id)) {
    419 		struct bpf_prog_info prog_info = {};
    420 		__u32 saved_map_id;
    421 		int prog_fd;
    422 
    423 		info_len = sizeof(prog_info);
    424 
    425 		prog_fd = bpf_prog_get_fd_by_id(next_id);
    426 		if (prog_fd < 0 && errno == ENOENT)
    427 			/* The bpf_prog is in the dead row */
    428 			continue;
    429 		if (CHECK(prog_fd < 0, "get-prog-fd(next_id)",
    430 			  "prog_fd %d next_id %d errno %d\n",
    431 			  prog_fd, next_id, errno))
    432 			break;
    433 
    434 		for (i = 0; i < nr_iters; i++)
    435 			if (prog_infos[i].id == next_id)
    436 				break;
    437 
    438 		if (i == nr_iters)
    439 			continue;
    440 
    441 		nr_id_found++;
    442 
    443 		/* Negative test:
    444 		 * prog_info.nr_map_ids = 1
    445 		 * prog_info.map_ids = NULL
    446 		 */
    447 		prog_info.nr_map_ids = 1;
    448 		err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len);
    449 		if (CHECK(!err || errno != EFAULT,
    450 			  "get-prog-fd-bad-nr-map-ids", "err %d errno %d(%d)",
    451 			  err, errno, EFAULT))
    452 			break;
    453 		bzero(&prog_info, sizeof(prog_info));
    454 		info_len = sizeof(prog_info);
    455 
    456 		saved_map_id = *(int *)(prog_infos[i].map_ids);
    457 		prog_info.map_ids = prog_infos[i].map_ids;
    458 		prog_info.nr_map_ids = 2;
    459 		err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len);
    460 		prog_infos[i].jited_prog_insns = 0;
    461 		prog_infos[i].xlated_prog_insns = 0;
    462 		CHECK(err || info_len != sizeof(struct bpf_prog_info) ||
    463 		      memcmp(&prog_info, &prog_infos[i], info_len) ||
    464 		      *(int *)prog_info.map_ids != saved_map_id,
    465 		      "get-prog-info(next_id->fd)",
    466 		      "err %d errno %d info_len %u(%Zu) memcmp %d map_id %u(%u)\n",
    467 		      err, errno, info_len, sizeof(struct bpf_prog_info),
    468 		      memcmp(&prog_info, &prog_infos[i], info_len),
    469 		      *(int *)prog_info.map_ids, saved_map_id);
    470 		close(prog_fd);
    471 	}
    472 	CHECK(nr_id_found != nr_iters,
    473 	      "check total prog id found by get_next_id",
    474 	      "nr_id_found %u(%u)\n",
    475 	      nr_id_found, nr_iters);
    476 
    477 	/* Check bpf_map_get_next_id() */
    478 	nr_id_found = 0;
    479 	next_id = 0;
    480 	while (!bpf_map_get_next_id(next_id, &next_id)) {
    481 		struct bpf_map_info map_info = {};
    482 		int map_fd;
    483 
    484 		info_len = sizeof(map_info);
    485 
    486 		map_fd = bpf_map_get_fd_by_id(next_id);
    487 		if (map_fd < 0 && errno == ENOENT)
    488 			/* The bpf_map is in the dead row */
    489 			continue;
    490 		if (CHECK(map_fd < 0, "get-map-fd(next_id)",
    491 			  "map_fd %d next_id %u errno %d\n",
    492 			  map_fd, next_id, errno))
    493 			break;
    494 
    495 		for (i = 0; i < nr_iters; i++)
    496 			if (map_infos[i].id == next_id)
    497 				break;
    498 
    499 		if (i == nr_iters)
    500 			continue;
    501 
    502 		nr_id_found++;
    503 
    504 		err = bpf_map_lookup_elem(map_fd, &array_key, &array_value);
    505 		assert(!err);
    506 
    507 		err = bpf_obj_get_info_by_fd(map_fd, &map_info, &info_len);
    508 		CHECK(err || info_len != sizeof(struct bpf_map_info) ||
    509 		      memcmp(&map_info, &map_infos[i], info_len) ||
    510 		      array_value != array_magic_value,
    511 		      "check get-map-info(next_id->fd)",
    512 		      "err %d errno %d info_len %u(%Zu) memcmp %d array_value %llu(%llu)\n",
    513 		      err, errno, info_len, sizeof(struct bpf_map_info),
    514 		      memcmp(&map_info, &map_infos[i], info_len),
    515 		      array_value, array_magic_value);
    516 
    517 		close(map_fd);
    518 	}
    519 	CHECK(nr_id_found != nr_iters,
    520 	      "check total map id found by get_next_id",
    521 	      "nr_id_found %u(%u)\n",
    522 	      nr_id_found, nr_iters);
    523 
    524 done:
    525 	for (i = 0; i < nr_iters; i++)
    526 		bpf_object__close(objs[i]);
    527 }
    528 
    529 static void test_pkt_md_access(void)
    530 {
    531 	const char *file = "./test_pkt_md_access.o";
    532 	struct bpf_object *obj;
    533 	__u32 duration, retval;
    534 	int err, prog_fd;
    535 
    536 	err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
    537 	if (err) {
    538 		error_cnt++;
    539 		return;
    540 	}
    541 
    542 	err = bpf_prog_test_run(prog_fd, 10, &pkt_v4, sizeof(pkt_v4),
    543 				NULL, NULL, &retval, &duration);
    544 	CHECK(err || retval, "",
    545 	      "err %d errno %d retval %d duration %d\n",
    546 	      err, errno, retval, duration);
    547 
    548 	bpf_object__close(obj);
    549 }
    550 
    551 static void test_obj_name(void)
    552 {
    553 	struct {
    554 		const char *name;
    555 		int success;
    556 		int expected_errno;
    557 	} tests[] = {
    558 		{ "", 1, 0 },
    559 		{ "_123456789ABCDE", 1, 0 },
    560 		{ "_123456789ABCDEF", 0, EINVAL },
    561 		{ "_123456789ABCD\n", 0, EINVAL },
    562 	};
    563 	struct bpf_insn prog[] = {
    564 		BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0),
    565 		BPF_EXIT_INSN(),
    566 	};
    567 	__u32 duration = 0;
    568 	int i;
    569 
    570 	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
    571 		size_t name_len = strlen(tests[i].name) + 1;
    572 		union bpf_attr attr;
    573 		size_t ncopy;
    574 		int fd;
    575 
    576 		/* test different attr.prog_name during BPF_PROG_LOAD */
    577 		ncopy = name_len < sizeof(attr.prog_name) ?
    578 			name_len : sizeof(attr.prog_name);
    579 		bzero(&attr, sizeof(attr));
    580 		attr.prog_type = BPF_PROG_TYPE_SCHED_CLS;
    581 		attr.insn_cnt = 2;
    582 		attr.insns = ptr_to_u64(prog);
    583 		attr.license = ptr_to_u64("");
    584 		memcpy(attr.prog_name, tests[i].name, ncopy);
    585 
    586 		fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
    587 		CHECK((tests[i].success && fd < 0) ||
    588 		      (!tests[i].success && fd != -1) ||
    589 		      (!tests[i].success && errno != tests[i].expected_errno),
    590 		      "check-bpf-prog-name",
    591 		      "fd %d(%d) errno %d(%d)\n",
    592 		       fd, tests[i].success, errno, tests[i].expected_errno);
    593 
    594 		if (fd != -1)
    595 			close(fd);
    596 
    597 		/* test different attr.map_name during BPF_MAP_CREATE */
    598 		ncopy = name_len < sizeof(attr.map_name) ?
    599 			name_len : sizeof(attr.map_name);
    600 		bzero(&attr, sizeof(attr));
    601 		attr.map_type = BPF_MAP_TYPE_ARRAY;
    602 		attr.key_size = 4;
    603 		attr.value_size = 4;
    604 		attr.max_entries = 1;
    605 		attr.map_flags = 0;
    606 		memcpy(attr.map_name, tests[i].name, ncopy);
    607 		fd = syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
    608 		CHECK((tests[i].success && fd < 0) ||
    609 		      (!tests[i].success && fd != -1) ||
    610 		      (!tests[i].success && errno != tests[i].expected_errno),
    611 		      "check-bpf-map-name",
    612 		      "fd %d(%d) errno %d(%d)\n",
    613 		      fd, tests[i].success, errno, tests[i].expected_errno);
    614 
    615 		if (fd != -1)
    616 			close(fd);
    617 	}
    618 }
    619 
    620 int main(void)
    621 {
    622 	struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
    623 
    624 	setrlimit(RLIMIT_MEMLOCK, &rinf);
    625 
    626 	test_pkt_access();
    627 	test_xdp();
    628 	test_l4lb();
    629 	test_tcp_estats();
    630 	test_bpf_obj_id();
    631 	test_pkt_md_access();
    632 	test_obj_name();
    633 
    634 	printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt);
    635 	return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS;
    636 }
    637