brintos

brintos / linux-shallow public Read only

0
0
Text · 7.6 KiB · 5da493b Raw
279 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2019 Facebook  */3#include <stdio.h>4#include <errno.h>5#include <string.h>6#include <unistd.h>7 8#include <bpf/bpf.h>9#include <bpf/libbpf.h>10 11#include <bpf_util.h>12#include <test_maps.h>13 14static void map_batch_update(int map_fd, __u32 max_entries, int *keys,15			     void *values, bool is_pcpu)16{17	typedef BPF_DECLARE_PERCPU(int, value);18	value *v = NULL;19	int i, j, err;20	DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts,21		.elem_flags = 0,22		.flags = 0,23	);24 25	if (is_pcpu)26		v = (value *)values;27 28	for (i = 0; i < max_entries; i++) {29		keys[i] = i + 1;30		if (is_pcpu)31			for (j = 0; j < bpf_num_possible_cpus(); j++)32				bpf_percpu(v[i], j) = i + 2 + j;33		else34			((int *)values)[i] = i + 2;35	}36 37	err = bpf_map_update_batch(map_fd, keys, values, &max_entries, &opts);38	CHECK(err, "bpf_map_update_batch()", "error:%s\n", strerror(errno));39}40 41static void map_batch_verify(int *visited, __u32 max_entries,42			     int *keys, void *values, bool is_pcpu)43{44	typedef BPF_DECLARE_PERCPU(int, value);45	value *v = NULL;46	int i, j;47 48	if (is_pcpu)49		v = (value *)values;50 51	memset(visited, 0, max_entries * sizeof(*visited));52	for (i = 0; i < max_entries; i++) {53 54		if (is_pcpu) {55			for (j = 0; j < bpf_num_possible_cpus(); j++) {56				CHECK(keys[i] + 1 + j != bpf_percpu(v[i], j),57				      "key/value checking",58				      "error: i %d j %d key %d value %d\n",59				      i, j, keys[i], bpf_percpu(v[i],  j));60			}61		} else {62			CHECK(keys[i] + 1 != ((int *)values)[i],63			      "key/value checking",64			      "error: i %d key %d value %d\n", i, keys[i],65			      ((int *)values)[i]);66		}67 68		visited[i] = 1;69 70	}71	for (i = 0; i < max_entries; i++) {72		CHECK(visited[i] != 1, "visited checking",73		      "error: keys array at index %d missing\n", i);74	}75}76 77void __test_map_lookup_and_delete_batch(bool is_pcpu)78{79	__u32 batch, count, total, total_success;80	typedef BPF_DECLARE_PERCPU(int, value);81	int map_fd, *keys, *visited, key;82	const __u32 max_entries = 10;83	value pcpu_values[max_entries];84	int err, step, value_size;85	bool nospace_err;86	void *values;87	DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts,88		.elem_flags = 0,89		.flags = 0,90	);91 92	map_fd = bpf_map_create(is_pcpu ? BPF_MAP_TYPE_PERCPU_HASH : BPF_MAP_TYPE_HASH,93				"hash_map", sizeof(int), sizeof(int), max_entries, NULL);94	CHECK(map_fd == -1,95	      "bpf_map_create()", "error:%s\n", strerror(errno));96 97	value_size = is_pcpu ? sizeof(value) : sizeof(int);98	keys = malloc(max_entries * sizeof(int));99	if (is_pcpu)100		values = pcpu_values;101	else102		values = malloc(max_entries * sizeof(int));103	visited = malloc(max_entries * sizeof(int));104	CHECK(!keys || !values || !visited, "malloc()",105	      "error:%s\n", strerror(errno));106 107	/* test 1: lookup/delete an empty hash table, -ENOENT */108	count = max_entries;109	err = bpf_map_lookup_and_delete_batch(map_fd, NULL, &batch, keys,110					      values, &count, &opts);111	CHECK((err && errno != ENOENT), "empty map",112	      "error: %s\n", strerror(errno));113 114	/* populate elements to the map */115	map_batch_update(map_fd, max_entries, keys, values, is_pcpu);116 117	/* test 2: lookup/delete with count = 0, success */118	count = 0;119	err = bpf_map_lookup_and_delete_batch(map_fd, NULL, &batch, keys,120					      values, &count, &opts);121	CHECK(err, "count = 0", "error: %s\n", strerror(errno));122 123	/* test 3: lookup/delete with count = max_entries, success */124	memset(keys, 0, max_entries * sizeof(*keys));125	memset(values, 0, max_entries * value_size);126	count = max_entries;127	err = bpf_map_lookup_and_delete_batch(map_fd, NULL, &batch, keys,128					      values, &count, &opts);129	CHECK((err && errno != ENOENT), "count = max_entries",130	       "error: %s\n", strerror(errno));131	CHECK(count != max_entries, "count = max_entries",132	      "count = %u, max_entries = %u\n", count, max_entries);133	map_batch_verify(visited, max_entries, keys, values, is_pcpu);134 135	/* bpf_map_get_next_key() should return -ENOENT for an empty map. */136	err = bpf_map_get_next_key(map_fd, NULL, &key);137	CHECK(!err, "bpf_map_get_next_key()", "error: %s\n", strerror(errno));138 139	/* test 4: lookup/delete in a loop with various steps. */140	total_success = 0;141	for (step = 1; step < max_entries; step++) {142		map_batch_update(map_fd, max_entries, keys, values, is_pcpu);143		memset(keys, 0, max_entries * sizeof(*keys));144		memset(values, 0, max_entries * value_size);145		total = 0;146		/* iteratively lookup/delete elements with 'step'147		 * elements each148		 */149		count = step;150		nospace_err = false;151		while (true) {152			err = bpf_map_lookup_batch(map_fd,153						   total ? &batch : NULL,154						   &batch, keys + total,155						   values +156						   total * value_size,157						   &count, &opts);158			/* It is possible that we are failing due to buffer size159			 * not big enough. In such cases, let us just exit and160			 * go with large steps. Not that a buffer size with161			 * max_entries should always work.162			 */163			if (err && errno == ENOSPC) {164				nospace_err = true;165				break;166			}167 168			CHECK((err && errno != ENOENT), "lookup with steps",169			      "error: %s\n", strerror(errno));170 171			total += count;172			if (err)173				break;174 175		}176		if (nospace_err == true)177			continue;178 179		CHECK(total != max_entries, "lookup with steps",180		      "total = %u, max_entries = %u\n", total, max_entries);181		map_batch_verify(visited, max_entries, keys, values, is_pcpu);182 183		total = 0;184		count = step;185		while (total < max_entries) {186			if (max_entries - total < step)187				count = max_entries - total;188			err = bpf_map_delete_batch(map_fd,189						   keys + total,190						   &count, &opts);191			CHECK((err && errno != ENOENT), "delete batch",192			      "error: %s\n", strerror(errno));193			total += count;194			if (err)195				break;196		}197		CHECK(total != max_entries, "delete with steps",198		      "total = %u, max_entries = %u\n", total, max_entries);199 200		/* check map is empty, errno == ENOENT */201		err = bpf_map_get_next_key(map_fd, NULL, &key);202		CHECK(!err || errno != ENOENT, "bpf_map_get_next_key()",203		      "error: %s\n", strerror(errno));204 205		/* iteratively lookup/delete elements with 'step'206		 * elements each207		 */208		map_batch_update(map_fd, max_entries, keys, values, is_pcpu);209		memset(keys, 0, max_entries * sizeof(*keys));210		memset(values, 0, max_entries * value_size);211		total = 0;212		count = step;213		nospace_err = false;214		while (true) {215			err = bpf_map_lookup_and_delete_batch(map_fd,216							total ? &batch : NULL,217							&batch, keys + total,218							values +219							total * value_size,220							&count, &opts);221			/* It is possible that we are failing due to buffer size222			 * not big enough. In such cases, let us just exit and223			 * go with large steps. Not that a buffer size with224			 * max_entries should always work.225			 */226			if (err && errno == ENOSPC) {227				nospace_err = true;228				break;229			}230 231			CHECK((err && errno != ENOENT), "lookup with steps",232			      "error: %s\n", strerror(errno));233 234			total += count;235			if (err)236				break;237		}238 239		if (nospace_err == true)240			continue;241 242		CHECK(total != max_entries, "lookup/delete with steps",243		      "total = %u, max_entries = %u\n", total, max_entries);244 245		map_batch_verify(visited, max_entries, keys, values, is_pcpu);246		err = bpf_map_get_next_key(map_fd, NULL, &key);247		CHECK(!err, "bpf_map_get_next_key()", "error: %s\n",248		      strerror(errno));249 250		total_success++;251	}252 253	CHECK(total_success == 0, "check total_success",254	      "unexpected failure\n");255	free(keys);256	free(visited);257	if (!is_pcpu)258		free(values);259	close(map_fd);260}261 262void htab_map_batch_ops(void)263{264	__test_map_lookup_and_delete_batch(false);265	printf("test_%s:PASS\n", __func__);266}267 268void htab_percpu_map_batch_ops(void)269{270	__test_map_lookup_and_delete_batch(true);271	printf("test_%s:PASS\n", __func__);272}273 274void test_htab_map_batch_ops(void)275{276	htab_map_batch_ops();277	htab_percpu_map_batch_ops();278}279