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