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