]> git.proxmox.com Git - mirror_ovs.git/blob - tests/test-netflow.c
packets: Change IP_ARGS interface to take an ovs_be32 instead of a pointer.
[mirror_ovs.git] / tests / test-netflow.c
1 /*
2 * Copyright (c) 2011, 2012 Nicira, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <config.h>
18
19 #include <errno.h>
20 #include <getopt.h>
21 #include <signal.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24
25 #include "command-line.h"
26 #include "daemon.h"
27 #include "dynamic-string.h"
28 #include "netflow.h"
29 #include "ofpbuf.h"
30 #include "packets.h"
31 #include "poll-loop.h"
32 #include "socket-util.h"
33 #include "unixctl.h"
34 #include "util.h"
35 #include "vlog.h"
36
37 static void usage(void) NO_RETURN;
38 static void parse_options(int argc, char *argv[]);
39
40 static unixctl_cb_func test_netflow_exit;
41
42 static void
43 print_netflow(struct ofpbuf *buf)
44 {
45 const struct netflow_v5_header *hdr;
46 int i;
47
48 hdr = ofpbuf_try_pull(buf, sizeof *hdr);
49 if (!hdr) {
50 printf("truncated NetFlow packet header\n");
51 return;
52 }
53 printf("header: v%"PRIu16", "
54 "uptime %"PRIu32", "
55 "now %"PRIu32".%09"PRIu32", "
56 "seq %"PRIu32", "
57 "engine %"PRIu8",%"PRIu8,
58 ntohs(hdr->version),
59 ntohl(hdr->sysuptime),
60 ntohl(hdr->unix_secs), ntohl(hdr->unix_nsecs),
61 ntohl(hdr->flow_seq),
62 hdr->engine_type, hdr->engine_id);
63 if (hdr->sampling_interval != htons(0)) {
64 printf(", interval %"PRIu16, ntohs(hdr->sampling_interval));
65 }
66 putchar('\n');
67
68 for (i = 0; i < ntohs(hdr->count); i++) {
69 struct netflow_v5_record *rec;
70
71 rec = ofpbuf_try_pull(buf, sizeof *rec);
72 if (!rec) {
73 printf("truncated NetFlow records\n");
74 return;
75 }
76
77 printf("seq %"PRIu32": "IP_FMT" > "IP_FMT, ntohl(hdr->flow_seq),
78 IP_ARGS(rec->src_addr), IP_ARGS(rec->dst_addr));
79
80 printf(", if %"PRIu16" > %"PRIu16,
81 ntohs(rec->input), ntohs(rec->output));
82
83 printf(", %"PRIu32" pkts, %"PRIu32" bytes",
84 ntohl(rec->packet_count), ntohl(rec->byte_count));
85
86 switch (rec->ip_proto) {
87 case IPPROTO_TCP:
88 printf(", TCP %"PRIu16" > %"PRIu16,
89 ntohs(rec->src_port), ntohs(rec->dst_port));
90 if (rec->tcp_flags) {
91 struct ds s = DS_EMPTY_INITIALIZER;
92 packet_format_tcp_flags(&s, rec->tcp_flags);
93 printf(" %s", ds_cstr(&s));
94 ds_destroy(&s);
95 }
96 break;
97
98 case IPPROTO_UDP:
99 printf(", UDP %"PRIu16" > %"PRIu16,
100 ntohs(rec->src_port), ntohs(rec->dst_port));
101 break;
102
103 case IPPROTO_ICMP:
104 printf(", ICMP %"PRIu16":%"PRIu16,
105 ntohs(rec->dst_port) >> 8,
106 ntohs(rec->dst_port) & 0xff);
107 if (rec->src_port != htons(0)) {
108 printf(", src_port=%"PRIu16, ntohs(rec->src_port));
109 }
110 break;
111
112 default:
113 printf(", proto %"PRIu8, rec->ip_proto);
114 break;
115 }
116
117 if (rec->ip_proto != IPPROTO_TCP && rec->tcp_flags != 0) {
118 printf(", flags %"PRIx8, rec->tcp_flags);
119 }
120
121 if (rec->ip_proto != IPPROTO_TCP &&
122 rec->ip_proto != IPPROTO_UDP &&
123 rec->ip_proto != IPPROTO_ICMP) {
124 if (rec->src_port != htons(0)) {
125 printf(", src_port %"PRIu16, ntohs(rec->src_port));
126 }
127 if (rec->dst_port != htons(0)) {
128 printf(", dst_port %"PRIu16, ntohs(rec->dst_port));
129 }
130 }
131
132 if (rec->ip_tos) {
133 printf(", TOS %"PRIx8, rec->ip_tos);
134 }
135
136 printf(", time %"PRIu32"...%"PRIu32,
137 ntohl(rec->init_time), ntohl(rec->used_time));
138
139 if (rec->nexthop != htonl(0)) {
140 printf(", nexthop "IP_FMT, IP_ARGS(rec->nexthop));
141 }
142 if (rec->src_as != htons(0) || rec->dst_as != htons(0)) {
143 printf(", AS %"PRIu16" > %"PRIu16,
144 ntohs(rec->src_as), ntohs(rec->dst_as));
145 }
146 if (rec->src_mask != 0 || rec->dst_mask != 0) {
147 printf(", mask %"PRIu8" > %"PRIu8, rec->src_mask, rec->dst_mask);
148 }
149 if (rec->pad1) {
150 printf(", pad1 %"PRIu8, rec->pad1);
151 }
152 if (rec->pad[0] || rec->pad[1]) {
153 printf(", pad %"PRIu8", %"PRIu8, rec->pad[0], rec->pad[1]);
154 }
155 putchar('\n');
156 }
157
158 if (buf->size) {
159 printf("%zu extra bytes after last record\n", buf->size);
160 }
161 }
162
163 int
164 main(int argc, char *argv[])
165 {
166 struct unixctl_server *server;
167 enum { MAX_RECV = 1500 };
168 const char *target;
169 struct ofpbuf buf;
170 bool exiting = false;
171 int error;
172 int sock;
173 int n;
174
175 proctitle_init(argc, argv);
176 set_program_name(argv[0]);
177 parse_options(argc, argv);
178
179 if (argc - optind != 1) {
180 ovs_fatal(0, "exactly one non-option argument required "
181 "(use --help for help)");
182 }
183 target = argv[optind];
184
185 sock = inet_open_passive(SOCK_DGRAM, target, 0, NULL, 0);
186 if (sock < 0) {
187 ovs_fatal(0, "%s: failed to open (%s)", argv[1], strerror(-sock));
188 }
189
190 daemon_save_fd(STDOUT_FILENO);
191 daemonize_start();
192
193 error = unixctl_server_create(NULL, &server);
194 if (error) {
195 ovs_fatal(error, "failed to create unixctl server");
196 }
197 unixctl_command_register("exit", "", 0, 0, test_netflow_exit, &exiting);
198
199 daemonize_complete();
200
201 ofpbuf_init(&buf, MAX_RECV);
202 n = 0;
203 for (;;) {
204 int retval;
205
206 unixctl_server_run(server);
207
208 ofpbuf_clear(&buf);
209 do {
210 retval = read(sock, buf.data, buf.allocated);
211 } while (retval < 0 && errno == EINTR);
212 if (retval > 0) {
213 ofpbuf_put_uninit(&buf, retval);
214 if (n++ > 0) {
215 putchar('\n');
216 }
217 print_netflow(&buf);
218 fflush(stdout);
219 }
220
221 if (exiting) {
222 break;
223 }
224
225 poll_fd_wait(sock, POLLIN);
226 unixctl_server_wait(server);
227 poll_block();
228 }
229
230 return 0;
231 }
232
233 static void
234 parse_options(int argc, char *argv[])
235 {
236 enum {
237 DAEMON_OPTION_ENUMS
238 };
239 static struct option long_options[] = {
240 {"verbose", optional_argument, NULL, 'v'},
241 {"help", no_argument, NULL, 'h'},
242 DAEMON_LONG_OPTIONS,
243 {NULL, 0, NULL, 0},
244 };
245 char *short_options = long_options_to_short_options(long_options);
246
247 for (;;) {
248 int c = getopt_long(argc, argv, short_options, long_options, NULL);
249 if (c == -1) {
250 break;
251 }
252
253 switch (c) {
254 case 'h':
255 usage();
256
257 case 'v':
258 vlog_set_verbosity(optarg);
259 break;
260
261 DAEMON_OPTION_HANDLERS
262
263 case '?':
264 exit(EXIT_FAILURE);
265
266 default:
267 abort();
268 }
269 }
270 free(short_options);
271 }
272
273 static void
274 usage(void)
275 {
276 printf("%s: netflow collector test utility\n"
277 "usage: %s [OPTIONS] PORT[:IP]\n"
278 "where PORT is the UDP port to listen on and IP is optionally\n"
279 "the IP address to listen on.\n",
280 program_name, program_name);
281 daemon_usage();
282 vlog_usage();
283 printf("\nOther options:\n"
284 " -h, --help display this help message\n");
285 exit(EXIT_SUCCESS);
286 }
287
288 static void
289 test_netflow_exit(struct unixctl_conn *conn,
290 int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
291 void *exiting_)
292 {
293 bool *exiting = exiting_;
294 *exiting = true;
295 unixctl_command_reply(conn, NULL);
296 }