Home | History | Annotate | Line # | Download | only in npftest
npftest.c revision 1.6.2.2
      1  1.6.2.2    tls /*	$NetBSD: npftest.c,v 1.6.2.2 2014/08/20 00:05:11 tls Exp $	*/
      2      1.1  rmind 
      3      1.1  rmind /*
      4      1.1  rmind  * NPF testing framework.
      5      1.1  rmind  *
      6      1.1  rmind  * Public Domain.
      7      1.1  rmind  */
      8      1.1  rmind 
      9      1.1  rmind #include <stdio.h>
     10      1.1  rmind #include <stdlib.h>
     11      1.1  rmind #include <stdbool.h>
     12      1.2  rmind #include <string.h>
     13      1.1  rmind #include <unistd.h>
     14      1.1  rmind #include <assert.h>
     15      1.2  rmind #include <fcntl.h>
     16      1.2  rmind #include <err.h>
     17      1.2  rmind 
     18  1.6.2.2    tls #include <sys/mman.h>
     19      1.2  rmind #include <sys/ioctl.h>
     20      1.2  rmind #include <net/if.h>
     21      1.2  rmind #include <arpa/inet.h>
     22      1.1  rmind 
     23      1.1  rmind #include <rump/rump.h>
     24      1.2  rmind #include <rump/rump_syscalls.h>
     25      1.1  rmind 
     26  1.6.2.2    tls #include <cdbw.h>
     27  1.6.2.2    tls 
     28      1.1  rmind #include "npftest.h"
     29      1.1  rmind 
     30      1.2  rmind static bool verbose, quiet;
     31      1.1  rmind 
     32  1.6.2.1    tls __dead static void
     33      1.1  rmind usage(void)
     34      1.1  rmind {
     35  1.6.2.1    tls 	printf("usage:\n"
     36  1.6.2.1    tls 	    "  %s [ -q | -v ] [ -c <config> ] "
     37  1.6.2.1    tls 	        "[ -i <interface> ] < -b | -t | -s file >\n"
     38  1.6.2.1    tls 	    "  %s -T <testname> -c <config>\n"
     39  1.6.2.1    tls 	    "  %s -L\n"
     40  1.6.2.1    tls 	    "where:\n"
     41      1.2  rmind 	    "\t-b: benchmark\n"
     42      1.2  rmind 	    "\t-t: regression test\n"
     43  1.6.2.1    tls 	    "\t-T <testname>: specific test\n"
     44      1.4  rmind 	    "\t-s <file>: pcap stream\n"
     45      1.2  rmind 	    "\t-c <config>: NPF configuration file\n"
     46      1.4  rmind 	    "\t-i <interface>: primary interface\n"
     47  1.6.2.1    tls 	    "\t-L: list testnames and description for -T\n"
     48      1.2  rmind 	    "\t-q: quiet mode\n"
     49      1.2  rmind 	    "\t-v: verbose mode\n",
     50  1.6.2.1    tls 	    getprogname(), getprogname(), getprogname());
     51      1.2  rmind 	exit(EXIT_FAILURE);
     52      1.1  rmind }
     53      1.1  rmind 
     54  1.6.2.1    tls __dead static void
     55  1.6.2.1    tls describe_tests(void)
     56  1.6.2.1    tls {
     57  1.6.2.1    tls 	printf(	"nbuf\tbasic npf mbuf handling\n"
     58  1.6.2.2    tls 		"bpf\tBPF coprocessor\n"
     59  1.6.2.1    tls 		"table\ttable handling\n"
     60  1.6.2.1    tls 		"state\tstate handling and processing\n"
     61  1.6.2.1    tls 		"rule\trule processing\n"
     62  1.6.2.1    tls 		"nat\tNAT rule processing\n");
     63  1.6.2.1    tls 	exit(EXIT_SUCCESS);
     64  1.6.2.1    tls }
     65  1.6.2.1    tls 
     66      1.6  rmind static bool
     67      1.2  rmind result(const char *testcase, bool ok)
     68      1.1  rmind {
     69      1.1  rmind 	if (!quiet) {
     70      1.2  rmind 		printf("NPF %-10s\t%s\n", testcase, ok ? "OK" : "fail");
     71      1.1  rmind 	}
     72      1.1  rmind 	if (verbose) {
     73      1.1  rmind 		puts("-----");
     74      1.1  rmind 	}
     75      1.6  rmind 	return !ok;
     76      1.1  rmind }
     77      1.1  rmind 
     78      1.2  rmind static void
     79      1.4  rmind load_npf_config_ifs(prop_dictionary_t dbg_dict)
     80      1.2  rmind {
     81  1.6.2.2    tls 	prop_array_t iflist = prop_dictionary_get(dbg_dict, "interfaces");
     82  1.6.2.2    tls 	prop_object_iterator_t it = prop_array_iterator(iflist);
     83      1.4  rmind 	prop_dictionary_t ifdict;
     84      1.4  rmind 
     85      1.4  rmind 	while ((ifdict = prop_object_iterator_next(it)) != NULL) {
     86  1.6.2.2    tls 		const char *ifname = NULL;
     87      1.4  rmind 
     88      1.4  rmind 		prop_dictionary_get_cstring_nocopy(ifdict, "name", &ifname);
     89  1.6.2.2    tls 		(void)rumpns_npf_test_addif(ifname, true, verbose);
     90      1.2  rmind 	}
     91      1.4  rmind 	prop_object_iterator_release(it);
     92      1.2  rmind }
     93      1.2  rmind 
     94      1.2  rmind static void
     95      1.2  rmind load_npf_config(const char *config)
     96      1.2  rmind {
     97      1.4  rmind 	prop_dictionary_t npf_dict, dbg_dict;
     98      1.2  rmind 	void *xml;
     99      1.2  rmind 	int error;
    100      1.2  rmind 
    101      1.4  rmind 	/* Read the configuration from the specified file. */
    102      1.2  rmind 	npf_dict = prop_dictionary_internalize_from_file(config);
    103      1.2  rmind 	if (!npf_dict) {
    104      1.2  rmind 		err(EXIT_FAILURE, "prop_dictionary_internalize_from_file");
    105      1.2  rmind 	}
    106      1.2  rmind 	xml = prop_dictionary_externalize(npf_dict);
    107      1.4  rmind 
    108      1.4  rmind 	/* Inspect the debug data.  Create the interfaces, if any. */
    109      1.4  rmind 	dbg_dict = prop_dictionary_get(npf_dict, "debug");
    110      1.4  rmind 	if (dbg_dict) {
    111      1.4  rmind 		load_npf_config_ifs(dbg_dict);
    112      1.4  rmind 	}
    113      1.2  rmind 	prop_object_release(npf_dict);
    114      1.2  rmind 
    115      1.4  rmind 	/* Pass the XML configuration for NPF kernel component to load. */
    116      1.2  rmind 	error = rumpns_npf_test_load(xml);
    117      1.2  rmind 	if (error) {
    118      1.2  rmind 		errx(EXIT_FAILURE, "npf_test_load: %s\n", strerror(error));
    119      1.2  rmind 	}
    120      1.2  rmind 	free(xml);
    121      1.2  rmind 
    122      1.2  rmind 	if (verbose) {
    123      1.2  rmind 		printf("Loaded NPF config at '%s'\n", config);
    124      1.2  rmind 	}
    125      1.2  rmind }
    126      1.2  rmind 
    127  1.6.2.2    tls static void *
    128  1.6.2.2    tls generate_test_cdb(size_t *size)
    129      1.4  rmind {
    130  1.6.2.2    tls 	in_addr_t addr;
    131  1.6.2.2    tls 	struct cdbw *cdbw;
    132  1.6.2.2    tls 	struct stat sb;
    133  1.6.2.2    tls 	char sfn[32];
    134  1.6.2.2    tls 	int alen, fd;
    135  1.6.2.2    tls 	void *cdb;
    136  1.6.2.2    tls 
    137  1.6.2.2    tls 	if ((cdbw = cdbw_open()) == NULL) {
    138  1.6.2.2    tls 		err(EXIT_FAILURE, "cdbw_open");
    139  1.6.2.2    tls 	}
    140  1.6.2.2    tls 	strlcpy(sfn, "/tmp/npftest_cdb.XXXXXX", sizeof(sfn));
    141  1.6.2.2    tls 	if ((fd = mkstemp(sfn)) == -1) {
    142  1.6.2.2    tls 		err(EXIT_FAILURE, "mkstemp");
    143  1.6.2.2    tls 	}
    144  1.6.2.2    tls 	unlink(sfn);
    145  1.6.2.2    tls 
    146  1.6.2.2    tls 	addr = inet_addr("192.168.1.1"), alen = sizeof(struct in_addr);
    147  1.6.2.2    tls 	if (cdbw_put(cdbw, &addr, alen, &addr, alen) == -1)
    148  1.6.2.2    tls 		err(EXIT_FAILURE, "cdbw_put");
    149  1.6.2.2    tls 
    150  1.6.2.2    tls 	addr = inet_addr("10.0.0.2"), alen = sizeof(struct in_addr);
    151  1.6.2.2    tls 	if (cdbw_put(cdbw, &addr, alen, &addr, alen) == -1)
    152  1.6.2.2    tls 		err(EXIT_FAILURE, "cdbw_put");
    153  1.6.2.2    tls 
    154  1.6.2.2    tls 	if (cdbw_output(cdbw, fd, "npf-table-cdb", NULL) == -1) {
    155  1.6.2.2    tls 		err(EXIT_FAILURE, "cdbw_output");
    156  1.6.2.2    tls 	}
    157  1.6.2.2    tls 	cdbw_close(cdbw);
    158  1.6.2.2    tls 
    159  1.6.2.2    tls 	if (fstat(fd, &sb) == -1) {
    160  1.6.2.2    tls 		err(EXIT_FAILURE, "fstat");
    161  1.6.2.2    tls 	}
    162  1.6.2.2    tls 	if ((cdb = mmap(NULL, sb.st_size, PROT_READ,
    163  1.6.2.2    tls 	    MAP_FILE | MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
    164  1.6.2.2    tls 		err(EXIT_FAILURE, "mmap");
    165  1.6.2.2    tls 	}
    166  1.6.2.2    tls 	close(fd);
    167  1.6.2.2    tls 
    168  1.6.2.2    tls 	*size = sb.st_size;
    169  1.6.2.2    tls 	return cdb;
    170      1.4  rmind }
    171      1.4  rmind 
    172      1.1  rmind int
    173      1.1  rmind main(int argc, char **argv)
    174      1.1  rmind {
    175  1.6.2.2    tls 	bool test, ok, fail, tname_matched;
    176  1.6.2.2    tls 	char *benchmark, *config, *interface, *stream, *testname;
    177  1.6.2.2    tls 	unsigned nthreads = 0;
    178  1.6.2.2    tls 	ifnet_t *ifp = NULL;
    179  1.6.2.2    tls 	int ch;
    180      1.1  rmind 
    181  1.6.2.2    tls 	benchmark = NULL;
    182      1.2  rmind 	test = false;
    183      1.2  rmind 
    184  1.6.2.1    tls 	tname_matched = false;
    185  1.6.2.1    tls 	testname = NULL;
    186      1.2  rmind 	config = NULL;
    187      1.4  rmind 	interface = NULL;
    188      1.2  rmind 	stream = NULL;
    189      1.2  rmind 
    190      1.1  rmind 	verbose = false;
    191      1.1  rmind 	quiet = false;
    192      1.1  rmind 
    193  1.6.2.2    tls 	while ((ch = getopt(argc, argv, "b:qvc:i:s:tT:Lp:")) != -1) {
    194      1.1  rmind 		switch (ch) {
    195      1.1  rmind 		case 'b':
    196  1.6.2.2    tls 			benchmark = optarg;
    197      1.1  rmind 			break;
    198      1.1  rmind 		case 'q':
    199      1.1  rmind 			quiet = true;
    200      1.1  rmind 			break;
    201      1.1  rmind 		case 'v':
    202      1.1  rmind 			verbose = true;
    203      1.1  rmind 			break;
    204      1.2  rmind 		case 'c':
    205      1.2  rmind 			config = optarg;
    206      1.2  rmind 			break;
    207      1.2  rmind 		case 'i':
    208      1.4  rmind 			interface = optarg;
    209      1.2  rmind 			break;
    210      1.2  rmind 		case 's':
    211      1.2  rmind 			stream = optarg;
    212      1.2  rmind 			break;
    213      1.2  rmind 		case 't':
    214      1.2  rmind 			test = true;
    215      1.2  rmind 			break;
    216  1.6.2.1    tls 		case 'T':
    217  1.6.2.1    tls 			test = true;
    218  1.6.2.1    tls 			testname = optarg;
    219  1.6.2.1    tls 			break;
    220  1.6.2.1    tls 		case 'L':
    221  1.6.2.1    tls 			describe_tests();
    222  1.6.2.2    tls 			break;
    223  1.6.2.2    tls 		case 'p':
    224  1.6.2.2    tls 			/* Note: RUMP_NCPU must be high enough. */
    225  1.6.2.2    tls 			if ((nthreads = atoi(optarg)) > 0 &&
    226  1.6.2.2    tls 			    getenv("RUMP_NCPU") == NULL) {
    227  1.6.2.2    tls 				char *val;
    228  1.6.2.2    tls 				asprintf(&val, "%u", nthreads + 1);
    229  1.6.2.2    tls 				setenv("RUMP_NCPU", val, 1);
    230  1.6.2.2    tls 				free(val);
    231  1.6.2.2    tls 			}
    232  1.6.2.2    tls 			break;
    233      1.1  rmind 		default:
    234      1.1  rmind 			usage();
    235      1.1  rmind 		}
    236      1.1  rmind 	}
    237      1.1  rmind 
    238      1.4  rmind 	/*
    239  1.6.2.2    tls 	 * Either benchmark or test.  If stream analysis, then the
    240  1.6.2.2    tls 	 * interface should be specified.  If benchmark, then the
    241  1.6.2.2    tls 	 * config should be loaded.
    242      1.4  rmind 	 */
    243  1.6.2.2    tls 	if ((benchmark != NULL) == test && (stream && !interface)) {
    244      1.2  rmind 		usage();
    245      1.2  rmind 	}
    246  1.6.2.2    tls 	if (benchmark && (!config || !nthreads)) {
    247  1.6.2.2    tls 		errx(EXIT_FAILURE, "missing config for the benchmark or "
    248  1.6.2.2    tls 		    "invalid thread count");
    249  1.6.2.2    tls 	}
    250      1.2  rmind 
    251      1.1  rmind 	/* XXX rn_init */
    252      1.1  rmind 	extern int rumpns_max_keylen;
    253      1.1  rmind 	rumpns_max_keylen = 1;
    254      1.1  rmind 
    255      1.1  rmind 	rump_init();
    256      1.1  rmind 	rump_schedule();
    257      1.1  rmind 
    258  1.6.2.2    tls 	rumpns_npf_test_init(inet_pton, inet_ntop, random);
    259      1.5  rmind 
    260      1.2  rmind 	if (config) {
    261      1.2  rmind 		load_npf_config(config);
    262      1.2  rmind 	}
    263  1.6.2.2    tls 	if (interface && (ifp = rumpns_npf_test_getif(interface)) == 0) {
    264      1.4  rmind 		errx(EXIT_FAILURE, "failed to find the interface");
    265      1.4  rmind 	}
    266      1.4  rmind 
    267      1.4  rmind 	srandom(1);
    268      1.6  rmind 	fail = false;
    269      1.2  rmind 
    270      1.2  rmind 	if (test) {
    271  1.6.2.1    tls 		if (!testname || strcmp("nbuf", testname) == 0) {
    272  1.6.2.1    tls 			ok = rumpns_npf_nbuf_test(verbose);
    273  1.6.2.1    tls 			fail |= result("nbuf", ok);
    274  1.6.2.1    tls 			tname_matched = true;
    275  1.6.2.1    tls 		}
    276      1.1  rmind 
    277  1.6.2.2    tls 		if (!testname || strcmp("bpf", testname) == 0) {
    278  1.6.2.2    tls 			ok = rumpns_npf_bpf_test(verbose);
    279  1.6.2.2    tls 			fail |= result("bpf", ok);
    280  1.6.2.1    tls 			tname_matched = true;
    281  1.6.2.1    tls 		}
    282      1.1  rmind 
    283  1.6.2.1    tls 		if (!testname || strcmp("table", testname) == 0) {
    284  1.6.2.2    tls 			void *cdb;
    285  1.6.2.2    tls 			size_t len;
    286  1.6.2.2    tls 
    287  1.6.2.2    tls 			cdb = generate_test_cdb(&len);
    288  1.6.2.2    tls 			ok = rumpns_npf_table_test(verbose, cdb, len);
    289  1.6.2.1    tls 			fail |= result("table", ok);
    290  1.6.2.1    tls 			tname_matched = true;
    291  1.6.2.2    tls 			munmap(cdb, len);
    292  1.6.2.1    tls 		}
    293      1.3  rmind 
    294  1.6.2.1    tls 		if (!testname || strcmp("state", testname) == 0) {
    295  1.6.2.1    tls 			ok = rumpns_npf_state_test(verbose);
    296  1.6.2.1    tls 			fail |= result("state", ok);
    297  1.6.2.1    tls 			tname_matched = true;
    298  1.6.2.1    tls 		}
    299      1.2  rmind 	}
    300      1.2  rmind 
    301      1.4  rmind 	if (test && config) {
    302  1.6.2.1    tls 		if (!testname || strcmp("rule", testname) == 0) {
    303  1.6.2.1    tls 			ok = rumpns_npf_rule_test(verbose);
    304  1.6.2.1    tls 			fail |= result("rule", ok);
    305  1.6.2.1    tls 			tname_matched = true;
    306  1.6.2.1    tls 		}
    307      1.4  rmind 
    308  1.6.2.1    tls 		if (!testname || strcmp("nat", testname) == 0) {
    309  1.6.2.1    tls 			ok = rumpns_npf_nat_test(verbose);
    310  1.6.2.1    tls 			fail |= result("nat", ok);
    311  1.6.2.1    tls 			tname_matched = true;
    312  1.6.2.1    tls 		}
    313      1.4  rmind 	}
    314      1.4  rmind 
    315      1.2  rmind 	if (stream) {
    316  1.6.2.2    tls 		process_stream(stream, NULL, ifp);
    317  1.6.2.2    tls 	}
    318  1.6.2.2    tls 
    319  1.6.2.2    tls 	if (benchmark) {
    320  1.6.2.2    tls 		if (strcmp("rule", benchmark) == 0) {
    321  1.6.2.2    tls 			rumpns_npf_test_conc(false, nthreads);
    322  1.6.2.2    tls 		}
    323  1.6.2.2    tls 		if (strcmp("state", benchmark) == 0) {
    324  1.6.2.2    tls 			rumpns_npf_test_conc(true, nthreads);
    325  1.6.2.2    tls 		}
    326      1.2  rmind 	}
    327      1.1  rmind 
    328      1.1  rmind 	rump_unschedule();
    329      1.1  rmind 
    330  1.6.2.1    tls 	if (testname && !tname_matched)
    331  1.6.2.1    tls 		errx(EXIT_FAILURE, "test \"%s\" unknown", testname);
    332  1.6.2.1    tls 
    333      1.6  rmind 	return fail ? EXIT_FAILURE : EXIT_SUCCESS;
    334      1.1  rmind }
    335