npftest.c revision 1.6.2.1 1 1.6.2.1 tls /* $NetBSD: npftest.c,v 1.6.2.1 2012/11/20 03:03:03 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.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.6.2.1 tls __dead static void
30 1.1 rmind usage(void)
31 1.1 rmind {
32 1.6.2.1 tls printf("usage:\n"
33 1.6.2.1 tls " %s [ -q | -v ] [ -c <config> ] "
34 1.6.2.1 tls "[ -i <interface> ] < -b | -t | -s file >\n"
35 1.6.2.1 tls " %s -T <testname> -c <config>\n"
36 1.6.2.1 tls " %s -L\n"
37 1.6.2.1 tls "where:\n"
38 1.2 rmind "\t-b: benchmark\n"
39 1.2 rmind "\t-t: regression test\n"
40 1.6.2.1 tls "\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.6.2.1 tls "\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.6.2.1 tls getprogname(), getprogname(), getprogname());
48 1.2 rmind exit(EXIT_FAILURE);
49 1.1 rmind }
50 1.1 rmind
51 1.6.2.1 tls __dead static void
52 1.6.2.1 tls describe_tests(void)
53 1.6.2.1 tls {
54 1.6.2.1 tls printf( "nbuf\tbasic npf mbuf handling\n"
55 1.6.2.1 tls "processor\tncode processing\n"
56 1.6.2.1 tls "table\ttable handling\n"
57 1.6.2.1 tls "state\tstate handling and processing\n"
58 1.6.2.1 tls "rule\trule processing\n"
59 1.6.2.1 tls "nat\tNAT rule processing\n");
60 1.6.2.1 tls exit(EXIT_SUCCESS);
61 1.6.2.1 tls }
62 1.6.2.1 tls
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.6.2.1 tls bool benchmark, test, ok, fail, tname_matched;
141 1.6.2.1 tls 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.6.2.1 tls tname_matched = false;
148 1.6.2.1 tls 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.6.2.1 tls 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.6.2.1 tls case 'T':
180 1.6.2.1 tls test = true;
181 1.6.2.1 tls testname = optarg;
182 1.6.2.1 tls break;
183 1.6.2.1 tls case 'L':
184 1.6.2.1 tls 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.6.2.1 tls if (!testname || strcmp("nbuf", testname) == 0) {
219 1.6.2.1 tls ok = rumpns_npf_nbuf_test(verbose);
220 1.6.2.1 tls fail |= result("nbuf", ok);
221 1.6.2.1 tls tname_matched = true;
222 1.6.2.1 tls }
223 1.1 rmind
224 1.6.2.1 tls if (!testname || strcmp("processor", testname) == 0) {
225 1.6.2.1 tls ok = rumpns_npf_processor_test(verbose);
226 1.6.2.1 tls fail |= result("processor", ok);
227 1.6.2.1 tls tname_matched = true;
228 1.6.2.1 tls }
229 1.1 rmind
230 1.6.2.1 tls if (!testname || strcmp("table", testname) == 0) {
231 1.6.2.1 tls ok = rumpns_npf_table_test(verbose);
232 1.6.2.1 tls fail |= result("table", ok);
233 1.6.2.1 tls tname_matched = true;
234 1.6.2.1 tls }
235 1.3 rmind
236 1.6.2.1 tls if (!testname || strcmp("state", testname) == 0) {
237 1.6.2.1 tls ok = rumpns_npf_state_test(verbose);
238 1.6.2.1 tls fail |= result("state", ok);
239 1.6.2.1 tls tname_matched = true;
240 1.6.2.1 tls }
241 1.2 rmind }
242 1.2 rmind
243 1.4 rmind if (test && config) {
244 1.6.2.1 tls if (!testname || strcmp("rule", testname) == 0) {
245 1.6.2.1 tls ok = rumpns_npf_rule_test(verbose);
246 1.6.2.1 tls fail |= result("rule", ok);
247 1.6.2.1 tls tname_matched = true;
248 1.6.2.1 tls }
249 1.4 rmind
250 1.6.2.1 tls if (!testname || strcmp("nat", testname) == 0) {
251 1.6.2.1 tls ok = rumpns_npf_nat_test(verbose);
252 1.6.2.1 tls fail |= result("nat", ok);
253 1.6.2.1 tls tname_matched = true;
254 1.6.2.1 tls }
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.6.2.1 tls if (testname && !tname_matched)
264 1.6.2.1 tls errx(EXIT_FAILURE, "test \"%s\" unknown", testname);
265 1.6.2.1 tls
266 1.6 rmind return fail ? EXIT_FAILURE : EXIT_SUCCESS;
267 1.1 rmind }
268