cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sk_storage_map.c (15675B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Copyright (c) 2019 Facebook  */
      3#include <linux/compiler.h>
      4#include <linux/err.h>
      5
      6#include <sys/resource.h>
      7#include <sys/socket.h>
      8#include <sys/types.h>
      9#include <linux/btf.h>
     10#include <unistd.h>
     11#include <signal.h>
     12#include <errno.h>
     13#include <string.h>
     14#include <pthread.h>
     15
     16#include <bpf/bpf.h>
     17#include <bpf/libbpf.h>
     18
     19#include <test_btf.h>
     20#include <test_maps.h>
     21
     22static struct bpf_map_create_opts map_opts = {
     23	.sz = sizeof(map_opts),
     24	.btf_key_type_id = 1,
     25	.btf_value_type_id = 3,
     26	.btf_fd = -1,
     27	.map_flags = BPF_F_NO_PREALLOC,
     28};
     29
     30static unsigned int nr_sk_threads_done;
     31static unsigned int nr_sk_threads_err;
     32static unsigned int nr_sk_per_thread = 4096;
     33static unsigned int nr_sk_threads = 4;
     34static int sk_storage_map = -1;
     35static unsigned int stop;
     36static int runtime_s = 5;
     37
     38static bool is_stopped(void)
     39{
     40	return READ_ONCE(stop);
     41}
     42
     43static unsigned int threads_err(void)
     44{
     45	return READ_ONCE(nr_sk_threads_err);
     46}
     47
     48static void notify_thread_err(void)
     49{
     50	__sync_add_and_fetch(&nr_sk_threads_err, 1);
     51}
     52
     53static bool wait_for_threads_err(void)
     54{
     55	while (!is_stopped() && !threads_err())
     56		usleep(500);
     57
     58	return !is_stopped();
     59}
     60
     61static unsigned int threads_done(void)
     62{
     63	return READ_ONCE(nr_sk_threads_done);
     64}
     65
     66static void notify_thread_done(void)
     67{
     68	__sync_add_and_fetch(&nr_sk_threads_done, 1);
     69}
     70
     71static void notify_thread_redo(void)
     72{
     73	__sync_sub_and_fetch(&nr_sk_threads_done, 1);
     74}
     75
     76static bool wait_for_threads_done(void)
     77{
     78	while (threads_done() != nr_sk_threads && !is_stopped() &&
     79	       !threads_err())
     80		usleep(50);
     81
     82	return !is_stopped() && !threads_err();
     83}
     84
     85static bool wait_for_threads_redo(void)
     86{
     87	while (threads_done() && !is_stopped() && !threads_err())
     88		usleep(50);
     89
     90	return !is_stopped() && !threads_err();
     91}
     92
     93static bool wait_for_map(void)
     94{
     95	while (READ_ONCE(sk_storage_map) == -1 && !is_stopped())
     96		usleep(50);
     97
     98	return !is_stopped();
     99}
    100
    101static bool wait_for_map_close(void)
    102{
    103	while (READ_ONCE(sk_storage_map) != -1 && !is_stopped())
    104		;
    105
    106	return !is_stopped();
    107}
    108
    109static int load_btf(void)
    110{
    111	const char btf_str_sec[] = "\0bpf_spin_lock\0val\0cnt\0l";
    112	__u32 btf_raw_types[] = {
    113		/* int */
    114		BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),  /* [1] */
    115		/* struct bpf_spin_lock */                      /* [2] */
    116		BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), 4),
    117		BTF_MEMBER_ENC(15, 1, 0), /* int val; */
    118		/* struct val */                                /* [3] */
    119		BTF_TYPE_ENC(15, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 8),
    120		BTF_MEMBER_ENC(19, 1, 0), /* int cnt; */
    121		BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */
    122	};
    123	struct btf_header btf_hdr = {
    124		.magic = BTF_MAGIC,
    125		.version = BTF_VERSION,
    126		.hdr_len = sizeof(struct btf_header),
    127		.type_len = sizeof(btf_raw_types),
    128		.str_off = sizeof(btf_raw_types),
    129		.str_len = sizeof(btf_str_sec),
    130	};
    131	__u8 raw_btf[sizeof(struct btf_header) + sizeof(btf_raw_types) +
    132		     sizeof(btf_str_sec)];
    133
    134	memcpy(raw_btf, &btf_hdr, sizeof(btf_hdr));
    135	memcpy(raw_btf + sizeof(btf_hdr), btf_raw_types, sizeof(btf_raw_types));
    136	memcpy(raw_btf + sizeof(btf_hdr) + sizeof(btf_raw_types),
    137	       btf_str_sec, sizeof(btf_str_sec));
    138
    139	return bpf_btf_load(raw_btf, sizeof(raw_btf), NULL);
    140}
    141
    142static int create_sk_storage_map(void)
    143{
    144	int btf_fd, map_fd;
    145
    146	btf_fd = load_btf();
    147	CHECK(btf_fd == -1, "bpf_load_btf", "btf_fd:%d errno:%d\n",
    148	      btf_fd, errno);
    149	map_opts.btf_fd = btf_fd;
    150
    151	map_fd = bpf_map_create(BPF_MAP_TYPE_SK_STORAGE, "sk_storage_map", 4, 8, 0, &map_opts);
    152	map_opts.btf_fd = -1;
    153	close(btf_fd);
    154	CHECK(map_fd == -1,
    155	      "bpf_map_create()", "errno:%d\n", errno);
    156
    157	return map_fd;
    158}
    159
    160static void *insert_close_thread(void *arg)
    161{
    162	struct {
    163		int cnt;
    164		int lock;
    165	} value = { .cnt = 0xeB9F, .lock = 0, };
    166	int i, map_fd, err, *sk_fds;
    167
    168	sk_fds = malloc(sizeof(*sk_fds) * nr_sk_per_thread);
    169	if (!sk_fds) {
    170		notify_thread_err();
    171		return ERR_PTR(-ENOMEM);
    172	}
    173
    174	for (i = 0; i < nr_sk_per_thread; i++)
    175		sk_fds[i] = -1;
    176
    177	while (!is_stopped()) {
    178		if (!wait_for_map())
    179			goto close_all;
    180
    181		map_fd = READ_ONCE(sk_storage_map);
    182		for (i = 0; i < nr_sk_per_thread && !is_stopped(); i++) {
    183			sk_fds[i] = socket(AF_INET6, SOCK_STREAM, 0);
    184			if (sk_fds[i] == -1) {
    185				err = -errno;
    186				fprintf(stderr, "socket(): errno:%d\n", errno);
    187				goto errout;
    188			}
    189			err = bpf_map_update_elem(map_fd, &sk_fds[i], &value,
    190						  BPF_NOEXIST);
    191			if (err) {
    192				err = -errno;
    193				fprintf(stderr,
    194					"bpf_map_update_elem(): errno:%d\n",
    195					errno);
    196				goto errout;
    197			}
    198		}
    199
    200		notify_thread_done();
    201		wait_for_map_close();
    202
    203close_all:
    204		for (i = 0; i < nr_sk_per_thread; i++) {
    205			close(sk_fds[i]);
    206			sk_fds[i] = -1;
    207		}
    208
    209		notify_thread_redo();
    210	}
    211
    212	free(sk_fds);
    213	return NULL;
    214
    215errout:
    216	for (i = 0; i < nr_sk_per_thread && sk_fds[i] != -1; i++)
    217		close(sk_fds[i]);
    218	free(sk_fds);
    219	notify_thread_err();
    220	return ERR_PTR(err);
    221}
    222
    223static int do_sk_storage_map_stress_free(void)
    224{
    225	int i, map_fd = -1, err = 0, nr_threads_created = 0;
    226	pthread_t *sk_thread_ids;
    227	void *thread_ret;
    228
    229	sk_thread_ids = malloc(sizeof(pthread_t) * nr_sk_threads);
    230	if (!sk_thread_ids) {
    231		fprintf(stderr, "malloc(sk_threads): NULL\n");
    232		return -ENOMEM;
    233	}
    234
    235	for (i = 0; i < nr_sk_threads; i++) {
    236		err = pthread_create(&sk_thread_ids[i], NULL,
    237				     insert_close_thread, NULL);
    238		if (err) {
    239			err = -errno;
    240			goto done;
    241		}
    242		nr_threads_created++;
    243	}
    244
    245	while (!is_stopped()) {
    246		map_fd = create_sk_storage_map();
    247		WRITE_ONCE(sk_storage_map, map_fd);
    248
    249		if (!wait_for_threads_done())
    250			break;
    251
    252		WRITE_ONCE(sk_storage_map, -1);
    253		close(map_fd);
    254		map_fd = -1;
    255
    256		if (!wait_for_threads_redo())
    257			break;
    258	}
    259
    260done:
    261	WRITE_ONCE(stop, 1);
    262	for (i = 0; i < nr_threads_created; i++) {
    263		pthread_join(sk_thread_ids[i], &thread_ret);
    264		if (IS_ERR(thread_ret) && !err) {
    265			err = PTR_ERR(thread_ret);
    266			fprintf(stderr, "threads#%u: err:%d\n", i, err);
    267		}
    268	}
    269	free(sk_thread_ids);
    270
    271	if (map_fd != -1)
    272		close(map_fd);
    273
    274	return err;
    275}
    276
    277static void *update_thread(void *arg)
    278{
    279	struct {
    280		int cnt;
    281		int lock;
    282	} value = { .cnt = 0xeB9F, .lock = 0, };
    283	int map_fd = READ_ONCE(sk_storage_map);
    284	int sk_fd = *(int *)arg;
    285	int err = 0; /* Suppress compiler false alarm */
    286
    287	while (!is_stopped()) {
    288		err = bpf_map_update_elem(map_fd, &sk_fd, &value, 0);
    289		if (err && errno != EAGAIN) {
    290			err = -errno;
    291			fprintf(stderr, "bpf_map_update_elem: %d %d\n",
    292				err, errno);
    293			break;
    294		}
    295	}
    296
    297	if (!is_stopped()) {
    298		notify_thread_err();
    299		return ERR_PTR(err);
    300	}
    301
    302	return NULL;
    303}
    304
    305static void *delete_thread(void *arg)
    306{
    307	int map_fd = READ_ONCE(sk_storage_map);
    308	int sk_fd = *(int *)arg;
    309	int err = 0; /* Suppress compiler false alarm */
    310
    311	while (!is_stopped()) {
    312		err = bpf_map_delete_elem(map_fd, &sk_fd);
    313		if (err && errno != ENOENT) {
    314			err = -errno;
    315			fprintf(stderr, "bpf_map_delete_elem: %d %d\n",
    316				err, errno);
    317			break;
    318		}
    319	}
    320
    321	if (!is_stopped()) {
    322		notify_thread_err();
    323		return ERR_PTR(err);
    324	}
    325
    326	return NULL;
    327}
    328
    329static int do_sk_storage_map_stress_change(void)
    330{
    331	int i, sk_fd, map_fd = -1, err = 0, nr_threads_created = 0;
    332	pthread_t *sk_thread_ids;
    333	void *thread_ret;
    334
    335	sk_thread_ids = malloc(sizeof(pthread_t) * nr_sk_threads);
    336	if (!sk_thread_ids) {
    337		fprintf(stderr, "malloc(sk_threads): NULL\n");
    338		return -ENOMEM;
    339	}
    340
    341	sk_fd = socket(AF_INET6, SOCK_STREAM, 0);
    342	if (sk_fd == -1) {
    343		err = -errno;
    344		goto done;
    345	}
    346
    347	map_fd = create_sk_storage_map();
    348	WRITE_ONCE(sk_storage_map, map_fd);
    349
    350	for (i = 0; i < nr_sk_threads; i++) {
    351		if (i & 0x1)
    352			err = pthread_create(&sk_thread_ids[i], NULL,
    353					     update_thread, &sk_fd);
    354		else
    355			err = pthread_create(&sk_thread_ids[i], NULL,
    356					     delete_thread, &sk_fd);
    357		if (err) {
    358			err = -errno;
    359			goto done;
    360		}
    361		nr_threads_created++;
    362	}
    363
    364	wait_for_threads_err();
    365
    366done:
    367	WRITE_ONCE(stop, 1);
    368	for (i = 0; i < nr_threads_created; i++) {
    369		pthread_join(sk_thread_ids[i], &thread_ret);
    370		if (IS_ERR(thread_ret) && !err) {
    371			err = PTR_ERR(thread_ret);
    372			fprintf(stderr, "threads#%u: err:%d\n", i, err);
    373		}
    374	}
    375	free(sk_thread_ids);
    376
    377	if (sk_fd != -1)
    378		close(sk_fd);
    379	close(map_fd);
    380
    381	return err;
    382}
    383
    384static void stop_handler(int signum)
    385{
    386	if (signum != SIGALRM)
    387		printf("stopping...\n");
    388	WRITE_ONCE(stop, 1);
    389}
    390
    391#define BPF_SK_STORAGE_MAP_TEST_NR_THREADS "BPF_SK_STORAGE_MAP_TEST_NR_THREADS"
    392#define BPF_SK_STORAGE_MAP_TEST_SK_PER_THREAD "BPF_SK_STORAGE_MAP_TEST_SK_PER_THREAD"
    393#define BPF_SK_STORAGE_MAP_TEST_RUNTIME_S "BPF_SK_STORAGE_MAP_TEST_RUNTIME_S"
    394#define BPF_SK_STORAGE_MAP_TEST_NAME "BPF_SK_STORAGE_MAP_TEST_NAME"
    395
    396static void test_sk_storage_map_stress_free(void)
    397{
    398	struct rlimit rlim_old, rlim_new = {};
    399	int err;
    400
    401	getrlimit(RLIMIT_NOFILE, &rlim_old);
    402
    403	signal(SIGTERM, stop_handler);
    404	signal(SIGINT, stop_handler);
    405	if (runtime_s > 0) {
    406		signal(SIGALRM, stop_handler);
    407		alarm(runtime_s);
    408	}
    409
    410	if (rlim_old.rlim_cur < nr_sk_threads * nr_sk_per_thread) {
    411		rlim_new.rlim_cur = nr_sk_threads * nr_sk_per_thread + 128;
    412		rlim_new.rlim_max = rlim_new.rlim_cur + 128;
    413		err = setrlimit(RLIMIT_NOFILE, &rlim_new);
    414		CHECK(err, "setrlimit(RLIMIT_NOFILE)", "rlim_new:%lu errno:%d",
    415		      rlim_new.rlim_cur, errno);
    416	}
    417
    418	err = do_sk_storage_map_stress_free();
    419
    420	signal(SIGTERM, SIG_DFL);
    421	signal(SIGINT, SIG_DFL);
    422	if (runtime_s > 0) {
    423		signal(SIGALRM, SIG_DFL);
    424		alarm(0);
    425	}
    426
    427	if (rlim_new.rlim_cur)
    428		setrlimit(RLIMIT_NOFILE, &rlim_old);
    429
    430	CHECK(err, "test_sk_storage_map_stress_free", "err:%d\n", err);
    431}
    432
    433static void test_sk_storage_map_stress_change(void)
    434{
    435	int err;
    436
    437	signal(SIGTERM, stop_handler);
    438	signal(SIGINT, stop_handler);
    439	if (runtime_s > 0) {
    440		signal(SIGALRM, stop_handler);
    441		alarm(runtime_s);
    442	}
    443
    444	err = do_sk_storage_map_stress_change();
    445
    446	signal(SIGTERM, SIG_DFL);
    447	signal(SIGINT, SIG_DFL);
    448	if (runtime_s > 0) {
    449		signal(SIGALRM, SIG_DFL);
    450		alarm(0);
    451	}
    452
    453	CHECK(err, "test_sk_storage_map_stress_change", "err:%d\n", err);
    454}
    455
    456static void test_sk_storage_map_basic(void)
    457{
    458	struct {
    459		int cnt;
    460		int lock;
    461	} value = { .cnt = 0xeB9f, .lock = 0, }, lookup_value;
    462	struct bpf_map_create_opts bad_xattr;
    463	int btf_fd, map_fd, sk_fd, err;
    464
    465	btf_fd = load_btf();
    466	CHECK(btf_fd == -1, "bpf_load_btf", "btf_fd:%d errno:%d\n",
    467	      btf_fd, errno);
    468	map_opts.btf_fd = btf_fd;
    469
    470	sk_fd = socket(AF_INET6, SOCK_STREAM, 0);
    471	CHECK(sk_fd == -1, "socket()", "sk_fd:%d errno:%d\n",
    472	      sk_fd, errno);
    473
    474	map_fd = bpf_map_create(BPF_MAP_TYPE_SK_STORAGE, "sk_storage_map", 4, 8, 0, &map_opts);
    475	CHECK(map_fd == -1, "bpf_map_create(good_xattr)",
    476	      "map_fd:%d errno:%d\n", map_fd, errno);
    477
    478	/* Add new elem */
    479	memcpy(&lookup_value, &value, sizeof(value));
    480	err = bpf_map_update_elem(map_fd, &sk_fd, &value,
    481				  BPF_NOEXIST | BPF_F_LOCK);
    482	CHECK(err, "bpf_map_update_elem(BPF_NOEXIST|BPF_F_LOCK)",
    483	      "err:%d errno:%d\n", err, errno);
    484	err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
    485					BPF_F_LOCK);
    486	CHECK(err || lookup_value.cnt != value.cnt,
    487	      "bpf_map_lookup_elem_flags(BPF_F_LOCK)",
    488	      "err:%d errno:%d cnt:%x(%x)\n",
    489	      err, errno, lookup_value.cnt, value.cnt);
    490
    491	/* Bump the cnt and update with BPF_EXIST | BPF_F_LOCK */
    492	value.cnt += 1;
    493	err = bpf_map_update_elem(map_fd, &sk_fd, &value,
    494				  BPF_EXIST | BPF_F_LOCK);
    495	CHECK(err, "bpf_map_update_elem(BPF_EXIST|BPF_F_LOCK)",
    496	      "err:%d errno:%d\n", err, errno);
    497	err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
    498					BPF_F_LOCK);
    499	CHECK(err || lookup_value.cnt != value.cnt,
    500	      "bpf_map_lookup_elem_flags(BPF_F_LOCK)",
    501	      "err:%d errno:%d cnt:%x(%x)\n",
    502	      err, errno, lookup_value.cnt, value.cnt);
    503
    504	/* Bump the cnt and update with BPF_EXIST */
    505	value.cnt += 1;
    506	err = bpf_map_update_elem(map_fd, &sk_fd, &value, BPF_EXIST);
    507	CHECK(err, "bpf_map_update_elem(BPF_EXIST)",
    508	      "err:%d errno:%d\n", err, errno);
    509	err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
    510					BPF_F_LOCK);
    511	CHECK(err || lookup_value.cnt != value.cnt,
    512	      "bpf_map_lookup_elem_flags(BPF_F_LOCK)",
    513	      "err:%d errno:%d cnt:%x(%x)\n",
    514	      err, errno, lookup_value.cnt, value.cnt);
    515
    516	/* Update with BPF_NOEXIST */
    517	value.cnt += 1;
    518	err = bpf_map_update_elem(map_fd, &sk_fd, &value,
    519				  BPF_NOEXIST | BPF_F_LOCK);
    520	CHECK(!err || errno != EEXIST,
    521	      "bpf_map_update_elem(BPF_NOEXIST|BPF_F_LOCK)",
    522	      "err:%d errno:%d\n", err, errno);
    523	err = bpf_map_update_elem(map_fd, &sk_fd, &value, BPF_NOEXIST);
    524	CHECK(!err || errno != EEXIST, "bpf_map_update_elem(BPF_NOEXIST)",
    525	      "err:%d errno:%d\n", err, errno);
    526	value.cnt -= 1;
    527	err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
    528					BPF_F_LOCK);
    529	CHECK(err || lookup_value.cnt != value.cnt,
    530	      "bpf_map_lookup_elem_flags(BPF_F_LOCK)",
    531	      "err:%d errno:%d cnt:%x(%x)\n",
    532	      err, errno, lookup_value.cnt, value.cnt);
    533
    534	/* Bump the cnt again and update with map_flags == 0 */
    535	value.cnt += 1;
    536	err = bpf_map_update_elem(map_fd, &sk_fd, &value, 0);
    537	CHECK(err, "bpf_map_update_elem()", "err:%d errno:%d\n",
    538	      err, errno);
    539	err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
    540					BPF_F_LOCK);
    541	CHECK(err || lookup_value.cnt != value.cnt,
    542	      "bpf_map_lookup_elem_flags(BPF_F_LOCK)",
    543	      "err:%d errno:%d cnt:%x(%x)\n",
    544	      err, errno, lookup_value.cnt, value.cnt);
    545
    546	/* Test delete elem */
    547	err = bpf_map_delete_elem(map_fd, &sk_fd);
    548	CHECK(err, "bpf_map_delete_elem()", "err:%d errno:%d\n",
    549	      err, errno);
    550	err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
    551					BPF_F_LOCK);
    552	CHECK(!err || errno != ENOENT,
    553	      "bpf_map_lookup_elem_flags(BPF_F_LOCK)",
    554	      "err:%d errno:%d\n", err, errno);
    555	err = bpf_map_delete_elem(map_fd, &sk_fd);
    556	CHECK(!err || errno != ENOENT, "bpf_map_delete_elem()",
    557	      "err:%d errno:%d\n", err, errno);
    558
    559	memcpy(&bad_xattr, &map_opts, sizeof(map_opts));
    560	bad_xattr.btf_key_type_id = 0;
    561	err = bpf_map_create(BPF_MAP_TYPE_SK_STORAGE, "sk_storage_map", 4, 8, 0, &bad_xattr);
    562	CHECK(!err || errno != EINVAL, "bpf_map_create(bad_xattr)",
    563	      "err:%d errno:%d\n", err, errno);
    564
    565	memcpy(&bad_xattr, &map_opts, sizeof(map_opts));
    566	bad_xattr.btf_key_type_id = 3;
    567	err = bpf_map_create(BPF_MAP_TYPE_SK_STORAGE, "sk_storage_map", 4, 8, 0, &bad_xattr);
    568	CHECK(!err || errno != EINVAL, "bpf_map_create(bad_xattr)",
    569	      "err:%d errno:%d\n", err, errno);
    570
    571	err = bpf_map_create(BPF_MAP_TYPE_SK_STORAGE, "sk_storage_map", 4, 8, 1, &map_opts);
    572	CHECK(!err || errno != EINVAL, "bpf_map_create(bad_xattr)",
    573	      "err:%d errno:%d\n", err, errno);
    574
    575	memcpy(&bad_xattr, &map_opts, sizeof(map_opts));
    576	bad_xattr.map_flags = 0;
    577	err = bpf_map_create(BPF_MAP_TYPE_SK_STORAGE, "sk_storage_map", 4, 8, 0, &bad_xattr);
    578	CHECK(!err || errno != EINVAL, "bap_create_map_xattr(bad_xattr)",
    579	      "err:%d errno:%d\n", err, errno);
    580
    581	map_opts.btf_fd = -1;
    582	close(btf_fd);
    583	close(map_fd);
    584	close(sk_fd);
    585}
    586
    587void test_sk_storage_map(void)
    588{
    589	const char *test_name, *env_opt;
    590	bool test_ran = false;
    591
    592	test_name = getenv(BPF_SK_STORAGE_MAP_TEST_NAME);
    593
    594	env_opt = getenv(BPF_SK_STORAGE_MAP_TEST_NR_THREADS);
    595	if (env_opt)
    596		nr_sk_threads = atoi(env_opt);
    597
    598	env_opt = getenv(BPF_SK_STORAGE_MAP_TEST_SK_PER_THREAD);
    599	if (env_opt)
    600		nr_sk_per_thread = atoi(env_opt);
    601
    602	env_opt = getenv(BPF_SK_STORAGE_MAP_TEST_RUNTIME_S);
    603	if (env_opt)
    604		runtime_s = atoi(env_opt);
    605
    606	if (!test_name || !strcmp(test_name, "basic")) {
    607		test_sk_storage_map_basic();
    608		test_ran = true;
    609	}
    610	if (!test_name || !strcmp(test_name, "stress_free")) {
    611		test_sk_storage_map_stress_free();
    612		test_ran = true;
    613	}
    614	if (!test_name || !strcmp(test_name, "stress_change")) {
    615		test_sk_storage_map_stress_change();
    616		test_ran = true;
    617	}
    618
    619	if (test_ran)
    620		printf("%s:PASS\n", __func__);
    621	else
    622		CHECK(1, "Invalid test_name", "%s\n", test_name);
    623}