Home | History | Annotate | Line # | Download | only in npftest
npftest.c revision 1.7
      1  1.7  martin /*	$NetBSD: npftest.c,v 1.7 2012/09/12 08:47:14 martin 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.2   rmind #include <sys/ioctl.h>
     19  1.2   rmind #include <net/if.h>
     20  1.2   rmind #include <arpa/inet.h>
     21  1.1   rmind 
     22  1.1   rmind #include <rump/rump.h>
     23  1.2   rmind #include <rump/rump_syscalls.h>
     24  1.1   rmind 
     25  1.1   rmind #include "npftest.h"
     26  1.1   rmind 
     27  1.2   rmind static bool verbose, quiet;
     28  1.1   rmind 
     29  1.1   rmind static void
     30  1.1   rmind usage(void)
     31  1.1   rmind {
     32  1.7  martin 	printf("usage:\n"
     33  1.7  martin 	    "  %s [ -q | -v ] [ -c <config> ] "
     34  1.7  martin 	        "[ -i <interface> ] < -b | -t | -s file >\n"
     35  1.7  martin 	    "  %s -T <testname> -c <config>\n"
     36  1.7  martin 	    "  %s -L\n"
     37  1.7  martin 	    "where:\n"
     38  1.2   rmind 	    "\t-b: benchmark\n"
     39  1.2   rmind 	    "\t-t: regression test\n"
     40  1.7  martin 	    "\t-T <testname>: specific test\n"
     41  1.4   rmind 	    "\t-s <file>: pcap stream\n"
     42  1.2   rmind 	    "\t-c <config>: NPF configuration file\n"
     43  1.4   rmind 	    "\t-i <interface>: primary interface\n"
     44  1.7  martin 	    "\t-L: list testnames and description for -T\n"
     45  1.2   rmind 	    "\t-q: quiet mode\n"
     46  1.2   rmind 	    "\t-v: verbose mode\n",
     47  1.7  martin 	    getprogname(), getprogname(), getprogname());
     48  1.2   rmind 	exit(EXIT_FAILURE);
     49  1.1   rmind }
     50  1.1   rmind 
     51  1.7  martin static void
     52  1.7  martin describe_tests(void)
     53  1.7  martin {
     54  1.7  martin 	printf(	"nbuf\tbasic npf mbuf handling\n"
     55  1.7  martin 		"processor\tncode processing\n"
     56  1.7  martin 		"table\ttable handling\n"
     57  1.7  martin 		"state\tstate handling and processing\n"
     58  1.7  martin 		"rule\trule processing\n"
     59  1.7  martin 		"nat\tNAT rule processing\n");
     60  1.7  martin 	exit(EXIT_SUCCESS);
     61  1.7  martin }
     62  1.7  martin 
     63  1.6   rmind static bool
     64  1.2   rmind result(const char *testcase, bool ok)
     65  1.1   rmind {
     66  1.1   rmind 	if (!quiet) {
     67  1.2   rmind 		printf("NPF %-10s\t%s\n", testcase, ok ? "OK" : "fail");
     68  1.1   rmind 	}
     69  1.1   rmind 	if (verbose) {
     70  1.1   rmind 		puts("-----");
     71  1.1   rmind 	}
     72  1.6   rmind 	return !ok;
     73  1.1   rmind }
     74  1.1   rmind 
     75  1.2   rmind static void
     76  1.4   rmind load_npf_config_ifs(prop_dictionary_t dbg_dict)
     77  1.2   rmind {
     78  1.4   rmind 	prop_dictionary_t ifdict;
     79  1.4   rmind 	prop_object_iterator_t it;
     80  1.4   rmind 	prop_array_t iflist;
     81  1.4   rmind 
     82  1.4   rmind 	iflist = prop_dictionary_get(dbg_dict, "interfaces");
     83  1.4   rmind 	it = prop_array_iterator(iflist);
     84  1.4   rmind 	while ((ifdict = prop_object_iterator_next(it)) != NULL) {
     85  1.4   rmind 		const char *ifname;
     86  1.4   rmind 		unsigned if_idx;
     87  1.4   rmind 
     88  1.4   rmind 		prop_dictionary_get_cstring_nocopy(ifdict, "name", &ifname);
     89  1.4   rmind 		prop_dictionary_get_uint32(ifdict, "idx", &if_idx);
     90  1.4   rmind 		(void)rumpns_npf_test_addif(ifname, if_idx, verbose);
     91  1.2   rmind 	}
     92  1.4   rmind 	prop_object_iterator_release(it);
     93  1.2   rmind }
     94  1.2   rmind 
     95  1.2   rmind static void
     96  1.2   rmind load_npf_config(const char *config)
     97  1.2   rmind {
     98  1.4   rmind 	prop_dictionary_t npf_dict, dbg_dict;
     99  1.2   rmind 	void *xml;
    100  1.2   rmind 	int error;
    101  1.2   rmind 
    102  1.4   rmind 	/* Read the configuration from the specified file. */
    103  1.2   rmind 	npf_dict = prop_dictionary_internalize_from_file(config);
    104  1.2   rmind 	if (!npf_dict) {
    105  1.2   rmind 		err(EXIT_FAILURE, "prop_dictionary_internalize_from_file");
    106  1.2   rmind 	}
    107  1.2   rmind 	xml = prop_dictionary_externalize(npf_dict);
    108  1.4   rmind 
    109  1.4   rmind 	/* Inspect the debug data.  Create the interfaces, if any. */
    110  1.4   rmind 	dbg_dict = prop_dictionary_get(npf_dict, "debug");
    111  1.4   rmind 	if (dbg_dict) {
    112  1.4   rmind 		load_npf_config_ifs(dbg_dict);
    113  1.4   rmind 	}
    114  1.2   rmind 	prop_object_release(npf_dict);
    115  1.2   rmind 
    116  1.4   rmind 	/* Pass the XML configuration for NPF kernel component to load. */
    117  1.2   rmind 	error = rumpns_npf_test_load(xml);
    118  1.2   rmind 	if (error) {
    119  1.2   rmind 		errx(EXIT_FAILURE, "npf_test_load: %s\n", strerror(error));
    120  1.2   rmind 	}
    121  1.2   rmind 	free(xml);
    122  1.2   rmind 
    123  1.2   rmind 	if (verbose) {
    124  1.2   rmind 		printf("Loaded NPF config at '%s'\n", config);
    125  1.2   rmind 	}
    126  1.2   rmind }
    127  1.2   rmind 
    128  1.4   rmind /*
    129  1.4   rmind  * Need to override for cprng_fast32(), since RUMP uses arc4random() for it.
    130  1.4   rmind  */
    131  1.4   rmind uint32_t
    132  1.4   rmind arc4random(void)
    133  1.4   rmind {
    134  1.4   rmind 	return random();
    135  1.4   rmind }
    136  1.4   rmind 
    137  1.1   rmind int
    138  1.1   rmind main(int argc, char **argv)
    139  1.1   rmind {
    140  1.7  martin 	bool benchmark, test, ok, fail, tname_matched;
    141  1.7  martin 	char *config, *interface, *stream, *testname;
    142  1.4   rmind 	int idx = -1, ch;
    143  1.1   rmind 
    144  1.1   rmind 	benchmark = false;
    145  1.2   rmind 	test = false;
    146  1.2   rmind 
    147  1.7  martin 	tname_matched = false;
    148  1.7  martin 	testname = NULL;
    149  1.2   rmind 	config = NULL;
    150  1.4   rmind 	interface = NULL;
    151  1.2   rmind 	stream = NULL;
    152  1.2   rmind 
    153  1.1   rmind 	verbose = false;
    154  1.1   rmind 	quiet = false;
    155  1.1   rmind 
    156  1.7  martin 	while ((ch = getopt(argc, argv, "bqvc:i:s:tT:L")) != -1) {
    157  1.1   rmind 		switch (ch) {
    158  1.1   rmind 		case 'b':
    159  1.1   rmind 			benchmark = true;
    160  1.1   rmind 			break;
    161  1.1   rmind 		case 'q':
    162  1.1   rmind 			quiet = true;
    163  1.1   rmind 			break;
    164  1.1   rmind 		case 'v':
    165  1.1   rmind 			verbose = true;
    166  1.1   rmind 			break;
    167  1.2   rmind 		case 'c':
    168  1.2   rmind 			config = optarg;
    169  1.2   rmind 			break;
    170  1.2   rmind 		case 'i':
    171  1.4   rmind 			interface = optarg;
    172  1.2   rmind 			break;
    173  1.2   rmind 		case 's':
    174  1.2   rmind 			stream = optarg;
    175  1.2   rmind 			break;
    176  1.2   rmind 		case 't':
    177  1.2   rmind 			test = true;
    178  1.2   rmind 			break;
    179  1.7  martin 		case 'T':
    180  1.7  martin 			test = true;
    181  1.7  martin 			testname = optarg;
    182  1.7  martin 			break;
    183  1.7  martin 		case 'L':
    184  1.7  martin 			describe_tests();
    185  1.1   rmind 		default:
    186  1.1   rmind 			usage();
    187  1.1   rmind 		}
    188  1.1   rmind 	}
    189  1.1   rmind 
    190  1.4   rmind 	/*
    191  1.4   rmind 	 * Either benchmark or test.  If stream analysis, then the interface
    192  1.4   rmind 	 * is needed as well.
    193  1.4   rmind 	 */
    194  1.4   rmind 	if (benchmark == test && (stream && !interface)) {
    195  1.2   rmind 		usage();
    196  1.2   rmind 	}
    197  1.2   rmind 
    198  1.1   rmind 	/* XXX rn_init */
    199  1.1   rmind 	extern int rumpns_max_keylen;
    200  1.1   rmind 	rumpns_max_keylen = 1;
    201  1.1   rmind 
    202  1.1   rmind 	rump_init();
    203  1.1   rmind 	rump_schedule();
    204  1.1   rmind 
    205  1.5   rmind 	rumpns_npf_test_init();
    206  1.5   rmind 
    207  1.2   rmind 	if (config) {
    208  1.2   rmind 		load_npf_config(config);
    209  1.2   rmind 	}
    210  1.4   rmind 	if (interface && (idx = rumpns_npf_test_getif(interface)) == 0) {
    211  1.4   rmind 		errx(EXIT_FAILURE, "failed to find the interface");
    212  1.4   rmind 	}
    213  1.4   rmind 
    214  1.4   rmind 	srandom(1);
    215  1.6   rmind 	fail = false;
    216  1.2   rmind 
    217  1.2   rmind 	if (test) {
    218  1.7  martin 		if (!testname || strcmp("nbuf", testname) == 0) {
    219  1.7  martin 			ok = rumpns_npf_nbuf_test(verbose);
    220  1.7  martin 			fail |= result("nbuf", ok);
    221  1.7  martin 			tname_matched = true;
    222  1.7  martin 		}
    223  1.1   rmind 
    224  1.7  martin 		if (!testname || strcmp("processor", testname) == 0) {
    225  1.7  martin 			ok = rumpns_npf_processor_test(verbose);
    226  1.7  martin 			fail |= result("processor", ok);
    227  1.7  martin 			tname_matched = true;
    228  1.7  martin 		}
    229  1.1   rmind 
    230  1.7  martin 		if (!testname || strcmp("table", testname) == 0) {
    231  1.7  martin 			ok = rumpns_npf_table_test(verbose);
    232  1.7  martin 			fail |= result("table", ok);
    233  1.7  martin 			tname_matched = true;
    234  1.7  martin 		}
    235  1.3   rmind 
    236  1.7  martin 		if (!testname || strcmp("state", testname) == 0) {
    237  1.7  martin 			ok = rumpns_npf_state_test(verbose);
    238  1.7  martin 			fail |= result("state", ok);
    239  1.7  martin 			tname_matched = true;
    240  1.7  martin 		}
    241  1.2   rmind 	}
    242  1.2   rmind 
    243  1.4   rmind 	if (test && config) {
    244  1.7  martin 		if (!testname || strcmp("rule", testname) == 0) {
    245  1.7  martin 			ok = rumpns_npf_rule_test(verbose);
    246  1.7  martin 			fail |= result("rule", ok);
    247  1.7  martin 			tname_matched = true;
    248  1.7  martin 		}
    249  1.4   rmind 
    250  1.7  martin 		if (!testname || strcmp("nat", testname) == 0) {
    251  1.7  martin 			ok = rumpns_npf_nat_test(verbose);
    252  1.7  martin 			fail |= result("nat", ok);
    253  1.7  martin 			tname_matched = true;
    254  1.7  martin 		}
    255  1.4   rmind 	}
    256  1.4   rmind 
    257  1.2   rmind 	if (stream) {
    258  1.2   rmind 		process_stream(stream, NULL, idx);
    259  1.2   rmind 	}
    260  1.1   rmind 
    261  1.1   rmind 	rump_unschedule();
    262  1.1   rmind 
    263  1.7  martin 	if (testname && !tname_matched)
    264  1.7  martin 		errx(EXIT_FAILURE, "test \"%s\" unknown", testname);
    265  1.7  martin 
    266  1.6   rmind 	return fail ? EXIT_FAILURE : EXIT_SUCCESS;
    267  1.1   rmind }
    268