291 lines · 7.5 KB · C
RawDownload
/* * Testsuite for eBPF maps * * Copyright (c) 2014 PLUMgrid, http://plumgrid.com * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */#include <stdio.h>#include <unistd.h>#include <linux/bpf.h>#include <errno.h>#include <string.h>#include <assert.h>#include <sys/wait.h>#include <stdlib.h>#include "libbpf.h" /* sanity tests for map API */static void test_hashmap_sanity(int i, void *data){	long long key, next_key, value;	int map_fd; 	map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 2);	if (map_fd < 0) {		printf("failed to create hashmap '%s'\n", strerror(errno));		exit(1);	} 	key = 1;	value = 1234;	/* insert key=1 element */	assert(bpf_update_elem(map_fd, &key, &value, BPF_ANY) == 0); 	value = 0;	/* BPF_NOEXIST means: add new element if it doesn't exist */	assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&	       /* key=1 already exists */	       errno == EEXIST); 	assert(bpf_update_elem(map_fd, &key, &value, -1) == -1 && errno == EINVAL); 	/* check that key=1 can be found */	assert(bpf_lookup_elem(map_fd, &key, &value) == 0 && value == 1234); 	key = 2;	/* check that key=2 is not found */	assert(bpf_lookup_elem(map_fd, &key, &value) == -1 && errno == ENOENT); 	/* BPF_EXIST means: update existing element */	assert(bpf_update_elem(map_fd, &key, &value, BPF_EXIST) == -1 &&	       /* key=2 is not there */	       errno == ENOENT); 	/* insert key=2 element */	assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == 0); 	/* key=1 and key=2 were inserted, check that key=0 cannot be inserted	 * due to max_entries limit	 */	key = 0;	assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&	       errno == E2BIG); 	/* check that key = 0 doesn't exist */	assert(bpf_delete_elem(map_fd, &key) == -1 && errno == ENOENT); 	/* iterate over two elements */	assert(bpf_get_next_key(map_fd, &key, &next_key) == 0 &&	       (next_key == 1 || next_key == 2));	assert(bpf_get_next_key(map_fd, &next_key, &next_key) == 0 &&	       (next_key == 1 || next_key == 2));	assert(bpf_get_next_key(map_fd, &next_key, &next_key) == -1 &&	       errno == ENOENT); 	/* delete both elements */	key = 1;	assert(bpf_delete_elem(map_fd, &key) == 0);	key = 2;	assert(bpf_delete_elem(map_fd, &key) == 0);	assert(bpf_delete_elem(map_fd, &key) == -1 && errno == ENOENT); 	key = 0;	/* check that map is empty */	assert(bpf_get_next_key(map_fd, &key, &next_key) == -1 &&	       errno == ENOENT);	close(map_fd);} static void test_arraymap_sanity(int i, void *data){	int key, next_key, map_fd;	long long value; 	map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), 2);	if (map_fd < 0) {		printf("failed to create arraymap '%s'\n", strerror(errno));		exit(1);	} 	key = 1;	value = 1234;	/* insert key=1 element */	assert(bpf_update_elem(map_fd, &key, &value, BPF_ANY) == 0); 	value = 0;	assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&	       errno == EEXIST); 	/* check that key=1 can be found */	assert(bpf_lookup_elem(map_fd, &key, &value) == 0 && value == 1234); 	key = 0;	/* check that key=0 is also found and zero initialized */	assert(bpf_lookup_elem(map_fd, &key, &value) == 0 && value == 0);  	/* key=0 and key=1 were inserted, check that key=2 cannot be inserted	 * due to max_entries limit	 */	key = 2;	assert(bpf_update_elem(map_fd, &key, &value, BPF_EXIST) == -1 &&	       errno == E2BIG); 	/* check that key = 2 doesn't exist */	assert(bpf_lookup_elem(map_fd, &key, &value) == -1 && errno == ENOENT); 	/* iterate over two elements */	assert(bpf_get_next_key(map_fd, &key, &next_key) == 0 &&	       next_key == 0);	assert(bpf_get_next_key(map_fd, &next_key, &next_key) == 0 &&	       next_key == 1);	assert(bpf_get_next_key(map_fd, &next_key, &next_key) == -1 &&	       errno == ENOENT); 	/* delete shouldn't succeed */	key = 1;	assert(bpf_delete_elem(map_fd, &key) == -1 && errno == EINVAL); 	close(map_fd);} #define MAP_SIZE (32 * 1024)static void test_map_large(void){	struct bigkey {		int a;		char b[116];		long long c;	} key;	int map_fd, i, value; 	/* allocate 4Mbyte of memory */	map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),				MAP_SIZE);	if (map_fd < 0) {		printf("failed to create large map '%s'\n", strerror(errno));		exit(1);	} 	for (i = 0; i < MAP_SIZE; i++) {		key = (struct bigkey) {.c = i};		value = i;		assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == 0);	}	key.c = -1;	assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&	       errno == E2BIG); 	/* iterate through all elements */	for (i = 0; i < MAP_SIZE; i++)		assert(bpf_get_next_key(map_fd, &key, &key) == 0);	assert(bpf_get_next_key(map_fd, &key, &key) == -1 && errno == ENOENT); 	key.c = 0;	assert(bpf_lookup_elem(map_fd, &key, &value) == 0 && value == 0);	key.a = 1;	assert(bpf_lookup_elem(map_fd, &key, &value) == -1 && errno == ENOENT); 	close(map_fd);} /* fork N children and wait for them to complete */static void run_parallel(int tasks, void (*fn)(int i, void *data), void *data){	pid_t pid[tasks];	int i; 	for (i = 0; i < tasks; i++) {		pid[i] = fork();		if (pid[i] == 0) {			fn(i, data);			exit(0);		} else if (pid[i] == -1) {			printf("couldn't spawn #%d process\n", i);			exit(1);		}	}	for (i = 0; i < tasks; i++) {		int status; 		assert(waitpid(pid[i], &status, 0) == pid[i]);		assert(status == 0);	}} static void test_map_stress(void){	run_parallel(100, test_hashmap_sanity, NULL);	run_parallel(100, test_arraymap_sanity, NULL);} #define TASKS 1024#define DO_UPDATE 1#define DO_DELETE 0static void do_work(int fn, void *data){	int map_fd = ((int *)data)[0];	int do_update = ((int *)data)[1];	int i;	int key, value; 	for (i = fn; i < MAP_SIZE; i += TASKS) {		key = value = i;		if (do_update)			assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == 0);		else			assert(bpf_delete_elem(map_fd, &key) == 0);	}} static void test_map_parallel(void){	int i, map_fd, key = 0, value = 0;	int data[2]; 	map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),				MAP_SIZE);	if (map_fd < 0) {		printf("failed to create map for parallel test '%s'\n",		       strerror(errno));		exit(1);	} 	data[0] = map_fd;	data[1] = DO_UPDATE;	/* use the same map_fd in children to add elements to this map	 * child_0 adds key=0, key=1024, key=2048, ...	 * child_1 adds key=1, key=1025, key=2049, ...	 * child_1023 adds key=1023, ...	 */	run_parallel(TASKS, do_work, data); 	/* check that key=0 is already there */	assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&	       errno == EEXIST); 	/* check that all elements were inserted */	key = -1;	for (i = 0; i < MAP_SIZE; i++)		assert(bpf_get_next_key(map_fd, &key, &key) == 0);	assert(bpf_get_next_key(map_fd, &key, &key) == -1 && errno == ENOENT); 	/* another check for all elements */	for (i = 0; i < MAP_SIZE; i++) {		key = MAP_SIZE - i - 1;		assert(bpf_lookup_elem(map_fd, &key, &value) == 0 &&		       value == key);	} 	/* now let's delete all elemenets in parallel */	data[1] = DO_DELETE;	run_parallel(TASKS, do_work, data); 	/* nothing should be left */	key = -1;	assert(bpf_get_next_key(map_fd, &key, &key) == -1 && errno == ENOENT);} int main(void){	test_hashmap_sanity(0, NULL);	test_arraymap_sanity(0, NULL);	test_map_large();	test_map_parallel();	test_map_stress();	printf("test_maps: OK\n");	return 0;}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t