]> git.proxmox.com Git - mirror_ovs.git/blame - tests/test-netflow.c
lib/odp-util: Skip ignored fields when parsing and formatting.
[mirror_ovs.git] / tests / test-netflow.c
CommitLineData
17f7f7e0 1/*
eadd1644 2 * Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
17f7f7e0
BP
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"
7393104d 27#include "dynamic-string.h"
17f7f7e0
BP
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"
eadd1644 36#include "ovstest.h"
17f7f7e0
BP
37
38static void usage(void) NO_RETURN;
39static void parse_options(int argc, char *argv[]);
40
41static unixctl_cb_func test_netflow_exit;
42
43static void
44print_netflow(struct ofpbuf *buf)
45{
46 const struct netflow_v5_header *hdr;
47 int i;
48
49 hdr = ofpbuf_try_pull(buf, sizeof *hdr);
50 if (!hdr) {
51 printf("truncated NetFlow packet header\n");
52 return;
53 }
54 printf("header: v%"PRIu16", "
55 "uptime %"PRIu32", "
56 "now %"PRIu32".%09"PRIu32", "
57 "seq %"PRIu32", "
58 "engine %"PRIu8",%"PRIu8,
59 ntohs(hdr->version),
60 ntohl(hdr->sysuptime),
61 ntohl(hdr->unix_secs), ntohl(hdr->unix_nsecs),
62 ntohl(hdr->flow_seq),
63 hdr->engine_type, hdr->engine_id);
64 if (hdr->sampling_interval != htons(0)) {
65 printf(", interval %"PRIu16, ntohs(hdr->sampling_interval));
66 }
67 putchar('\n');
68
69 for (i = 0; i < ntohs(hdr->count); i++) {
70 struct netflow_v5_record *rec;
71
72 rec = ofpbuf_try_pull(buf, sizeof *rec);
73 if (!rec) {
74 printf("truncated NetFlow records\n");
75 return;
76 }
77
52440c19 78 printf("seq %"PRIu32": "IP_FMT" > "IP_FMT, ntohl(hdr->flow_seq),
ed36537e 79 IP_ARGS(rec->src_addr), IP_ARGS(rec->dst_addr));
17f7f7e0
BP
80
81 printf(", if %"PRIu16" > %"PRIu16,
82 ntohs(rec->input), ntohs(rec->output));
83
84 printf(", %"PRIu32" pkts, %"PRIu32" bytes",
85 ntohl(rec->packet_count), ntohl(rec->byte_count));
86
87 switch (rec->ip_proto) {
88 case IPPROTO_TCP:
89 printf(", TCP %"PRIu16" > %"PRIu16,
90 ntohs(rec->src_port), ntohs(rec->dst_port));
91 if (rec->tcp_flags) {
7393104d
BP
92 struct ds s = DS_EMPTY_INITIALIZER;
93 packet_format_tcp_flags(&s, rec->tcp_flags);
94 printf(" %s", ds_cstr(&s));
95 ds_destroy(&s);
17f7f7e0
BP
96 }
97 break;
98
99 case IPPROTO_UDP:
100 printf(", UDP %"PRIu16" > %"PRIu16,
101 ntohs(rec->src_port), ntohs(rec->dst_port));
102 break;
103
0d56eaf2
JS
104 case IPPROTO_SCTP:
105 printf(", SCTP %"PRIu16" > %"PRIu16,
106 ntohs(rec->src_port), ntohs(rec->dst_port));
107 break;
108
17f7f7e0
BP
109 case IPPROTO_ICMP:
110 printf(", ICMP %"PRIu16":%"PRIu16,
111 ntohs(rec->dst_port) >> 8,
112 ntohs(rec->dst_port) & 0xff);
113 if (rec->src_port != htons(0)) {
114 printf(", src_port=%"PRIu16, ntohs(rec->src_port));
115 }
116 break;
117
118 default:
119 printf(", proto %"PRIu8, rec->ip_proto);
120 break;
121 }
122
123 if (rec->ip_proto != IPPROTO_TCP && rec->tcp_flags != 0) {
124 printf(", flags %"PRIx8, rec->tcp_flags);
125 }
126
127 if (rec->ip_proto != IPPROTO_TCP &&
128 rec->ip_proto != IPPROTO_UDP &&
0d56eaf2 129 rec->ip_proto != IPPROTO_SCTP &&
17f7f7e0
BP
130 rec->ip_proto != IPPROTO_ICMP) {
131 if (rec->src_port != htons(0)) {
132 printf(", src_port %"PRIu16, ntohs(rec->src_port));
133 }
134 if (rec->dst_port != htons(0)) {
135 printf(", dst_port %"PRIu16, ntohs(rec->dst_port));
136 }
137 }
138
139 if (rec->ip_tos) {
140 printf(", TOS %"PRIx8, rec->ip_tos);
141 }
142
143 printf(", time %"PRIu32"...%"PRIu32,
144 ntohl(rec->init_time), ntohl(rec->used_time));
145
146 if (rec->nexthop != htonl(0)) {
ed36537e 147 printf(", nexthop "IP_FMT, IP_ARGS(rec->nexthop));
17f7f7e0
BP
148 }
149 if (rec->src_as != htons(0) || rec->dst_as != htons(0)) {
150 printf(", AS %"PRIu16" > %"PRIu16,
151 ntohs(rec->src_as), ntohs(rec->dst_as));
152 }
153 if (rec->src_mask != 0 || rec->dst_mask != 0) {
154 printf(", mask %"PRIu8" > %"PRIu8, rec->src_mask, rec->dst_mask);
155 }
156 if (rec->pad1) {
157 printf(", pad1 %"PRIu8, rec->pad1);
158 }
159 if (rec->pad[0] || rec->pad[1]) {
160 printf(", pad %"PRIu8", %"PRIu8, rec->pad[0], rec->pad[1]);
161 }
162 putchar('\n');
163 }
164
1f317cb5
PS
165 if (ofpbuf_size(buf)) {
166 printf("%"PRIu32" extra bytes after last record\n", ofpbuf_size(buf));
17f7f7e0
BP
167 }
168}
169
eadd1644
AZ
170static void
171test_netflow_main(int argc, char *argv[])
17f7f7e0
BP
172{
173 struct unixctl_server *server;
174 enum { MAX_RECV = 1500 };
175 const char *target;
176 struct ofpbuf buf;
177 bool exiting = false;
178 int error;
179 int sock;
17f7f7e0
BP
180 int n;
181
182 proctitle_init(argc, argv);
183 set_program_name(argv[0]);
8f26aeb9 184 service_start(&argc, &argv);
17f7f7e0
BP
185 parse_options(argc, argv);
186
187 if (argc - optind != 1) {
188 ovs_fatal(0, "exactly one non-option argument required "
189 "(use --help for help)");
190 }
191 target = argv[optind];
192
b52ecd96 193 sock = inet_open_passive(SOCK_DGRAM, target, 0, NULL, 0, true);
17f7f7e0 194 if (sock < 0) {
10a89ef0 195 ovs_fatal(0, "%s: failed to open (%s)", argv[1], ovs_strerror(-sock));
17f7f7e0
BP
196 }
197
7d0c5973 198 daemon_save_fd(STDOUT_FILENO);
17f7f7e0
BP
199 daemonize_start();
200
201 error = unixctl_server_create(NULL, &server);
202 if (error) {
203 ovs_fatal(error, "failed to create unixctl server");
204 }
205 unixctl_command_register("exit", "", 0, 0, test_netflow_exit, &exiting);
206
207 daemonize_complete();
208
17f7f7e0
BP
209 ofpbuf_init(&buf, MAX_RECV);
210 n = 0;
211 for (;;) {
212 int retval;
213
214 unixctl_server_run(server);
215
216 ofpbuf_clear(&buf);
217 do {
8f26aeb9 218 retval = recv(sock, ofpbuf_data(&buf), buf.allocated, 0);
17f7f7e0
BP
219 } while (retval < 0 && errno == EINTR);
220 if (retval > 0) {
221 ofpbuf_put_uninit(&buf, retval);
222 if (n++ > 0) {
223 putchar('\n');
224 }
225 print_netflow(&buf);
226 fflush(stdout);
227 }
228
229 if (exiting) {
230 break;
231 }
232
233 poll_fd_wait(sock, POLLIN);
234 unixctl_server_wait(server);
235 poll_block();
236 }
17f7f7e0
BP
237}
238
239static void
240parse_options(int argc, char *argv[])
241{
242 enum {
977529e4
BP
243 DAEMON_OPTION_ENUMS,
244 VLOG_OPTION_ENUMS
17f7f7e0 245 };
07fc4ed3 246 static const struct option long_options[] = {
17f7f7e0
BP
247 {"help", no_argument, NULL, 'h'},
248 DAEMON_LONG_OPTIONS,
977529e4 249 VLOG_LONG_OPTIONS,
17f7f7e0
BP
250 {NULL, 0, NULL, 0},
251 };
252 char *short_options = long_options_to_short_options(long_options);
253
254 for (;;) {
255 int c = getopt_long(argc, argv, short_options, long_options, NULL);
256 if (c == -1) {
257 break;
258 }
259
260 switch (c) {
261 case 'h':
262 usage();
263
17f7f7e0 264 DAEMON_OPTION_HANDLERS
977529e4 265 VLOG_OPTION_HANDLERS
17f7f7e0
BP
266
267 case '?':
268 exit(EXIT_FAILURE);
269
270 default:
271 abort();
272 }
273 }
274 free(short_options);
275}
276
277static void
278usage(void)
279{
280 printf("%s: netflow collector test utility\n"
281 "usage: %s [OPTIONS] PORT[:IP]\n"
282 "where PORT is the UDP port to listen on and IP is optionally\n"
283 "the IP address to listen on.\n",
284 program_name, program_name);
285 daemon_usage();
286 vlog_usage();
287 printf("\nOther options:\n"
288 " -h, --help display this help message\n");
289 exit(EXIT_SUCCESS);
290}
291
292static void
293test_netflow_exit(struct unixctl_conn *conn,
294 int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
295 void *exiting_)
296{
297 bool *exiting = exiting_;
298 *exiting = true;
bde9f75d 299 unixctl_command_reply(conn, NULL);
17f7f7e0 300}
eadd1644
AZ
301
302OVSTEST_REGISTER("test-netflow", test_netflow_main);