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