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