2 * Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include "command-line.h"
27 #include "dynamic-string.h"
31 #include "poll-loop.h"
32 #include "socket-util.h"
35 #include "openvswitch/vlog.h"
37 OVS_NO_RETURN
static void usage(void);
38 static void parse_options(int argc
, char *argv
[]);
40 static unixctl_cb_func test_netflow_exit
;
43 print_netflow(struct ofpbuf
*buf
)
45 const struct netflow_v5_header
*hdr
;
48 hdr
= ofpbuf_try_pull(buf
, sizeof *hdr
);
50 printf("truncated NetFlow packet header\n");
53 printf("header: v%"PRIu16
", "
55 "now %"PRIu32
".%09"PRIu32
", "
57 "engine %"PRIu8
",%"PRIu8
,
59 ntohl(hdr
->sysuptime
),
60 ntohl(hdr
->unix_secs
), ntohl(hdr
->unix_nsecs
),
62 hdr
->engine_type
, hdr
->engine_id
);
63 if (hdr
->sampling_interval
!= htons(0)) {
64 printf(", interval %"PRIu16
, ntohs(hdr
->sampling_interval
));
68 for (i
= 0; i
< ntohs(hdr
->count
); i
++) {
69 struct netflow_v5_record
*rec
;
71 rec
= ofpbuf_try_pull(buf
, sizeof *rec
);
73 printf("truncated NetFlow records\n");
77 printf("seq %"PRIu32
": "IP_FMT
" > "IP_FMT
, ntohl(hdr
->flow_seq
),
78 IP_ARGS(rec
->src_addr
), IP_ARGS(rec
->dst_addr
));
80 printf(", if %"PRIu16
" > %"PRIu16
,
81 ntohs(rec
->input
), ntohs(rec
->output
));
83 printf(", %"PRIu32
" pkts, %"PRIu32
" bytes",
84 ntohl(rec
->packet_count
), ntohl(rec
->byte_count
));
86 switch (rec
->ip_proto
) {
88 printf(", TCP %"PRIu16
" > %"PRIu16
,
89 ntohs(rec
->src_port
), ntohs(rec
->dst_port
));
91 struct ds s
= DS_EMPTY_INITIALIZER
;
92 packet_format_tcp_flags(&s
, rec
->tcp_flags
);
93 printf(" %s", ds_cstr(&s
));
99 printf(", UDP %"PRIu16
" > %"PRIu16
,
100 ntohs(rec
->src_port
), ntohs(rec
->dst_port
));
104 printf(", SCTP %"PRIu16
" > %"PRIu16
,
105 ntohs(rec
->src_port
), ntohs(rec
->dst_port
));
109 printf(", ICMP %"PRIu16
":%"PRIu16
,
110 ntohs(rec
->dst_port
) >> 8,
111 ntohs(rec
->dst_port
) & 0xff);
112 if (rec
->src_port
!= htons(0)) {
113 printf(", src_port=%"PRIu16
, ntohs(rec
->src_port
));
118 printf(", proto %"PRIu8
, rec
->ip_proto
);
122 if (rec
->ip_proto
!= IPPROTO_TCP
&& rec
->tcp_flags
!= 0) {
123 printf(", flags %"PRIx8
, rec
->tcp_flags
);
126 if (rec
->ip_proto
!= IPPROTO_TCP
&&
127 rec
->ip_proto
!= IPPROTO_UDP
&&
128 rec
->ip_proto
!= IPPROTO_SCTP
&&
129 rec
->ip_proto
!= IPPROTO_ICMP
) {
130 if (rec
->src_port
!= htons(0)) {
131 printf(", src_port %"PRIu16
, ntohs(rec
->src_port
));
133 if (rec
->dst_port
!= htons(0)) {
134 printf(", dst_port %"PRIu16
, ntohs(rec
->dst_port
));
139 printf(", TOS %"PRIx8
, rec
->ip_tos
);
142 printf(", time %"PRIu32
"...%"PRIu32
,
143 ntohl(rec
->init_time
), ntohl(rec
->used_time
));
145 if (rec
->nexthop
!= htonl(0)) {
146 printf(", nexthop "IP_FMT
, IP_ARGS(rec
->nexthop
));
148 if (rec
->src_as
!= htons(0) || rec
->dst_as
!= htons(0)) {
149 printf(", AS %"PRIu16
" > %"PRIu16
,
150 ntohs(rec
->src_as
), ntohs(rec
->dst_as
));
152 if (rec
->src_mask
!= 0 || rec
->dst_mask
!= 0) {
153 printf(", mask %"PRIu8
" > %"PRIu8
, rec
->src_mask
, rec
->dst_mask
);
156 printf(", pad1 %"PRIu8
, rec
->pad1
);
158 if (rec
->pad
[0] || rec
->pad
[1]) {
159 printf(", pad %"PRIu8
", %"PRIu8
, rec
->pad
[0], rec
->pad
[1]);
165 printf("%"PRIu32
" extra bytes after last record\n", buf
->size
);
170 test_netflow_main(int argc
, char *argv
[])
172 struct unixctl_server
*server
;
173 enum { MAX_RECV
= 1500 };
176 bool exiting
= false;
181 ovs_cmdl_proctitle_init(argc
, argv
);
182 set_program_name(argv
[0]);
183 service_start(&argc
, &argv
);
184 parse_options(argc
, argv
);
186 if (argc
- optind
!= 1) {
187 ovs_fatal(0, "exactly one non-option argument required "
188 "(use --help for help)");
190 target
= argv
[optind
];
192 sock
= inet_open_passive(SOCK_DGRAM
, target
, 0, NULL
, 0, true);
194 ovs_fatal(0, "%s: failed to open (%s)", argv
[1], ovs_strerror(-sock
));
197 daemon_save_fd(STDOUT_FILENO
);
200 error
= unixctl_server_create(NULL
, &server
);
202 ovs_fatal(error
, "failed to create unixctl server");
204 unixctl_command_register("exit", "", 0, 0, test_netflow_exit
, &exiting
);
206 daemonize_complete();
208 ofpbuf_init(&buf
, MAX_RECV
);
213 unixctl_server_run(server
);
217 retval
= recv(sock
, buf
.data
, buf
.allocated
, 0);
218 } while (retval
< 0 && errno
== EINTR
);
220 ofpbuf_put_uninit(&buf
, retval
);
232 poll_fd_wait(sock
, POLLIN
);
233 unixctl_server_wait(server
);
239 parse_options(int argc
, char *argv
[])
245 static const struct option long_options
[] = {
246 {"help", no_argument
, NULL
, 'h'},
251 char *short_options
= ovs_cmdl_long_options_to_short_options(long_options
);
254 int c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
263 DAEMON_OPTION_HANDLERS
279 printf("%s: netflow collector test utility\n"
280 "usage: %s [OPTIONS] PORT[:IP]\n"
281 "where PORT is the UDP port to listen on and IP is optionally\n"
282 "the IP address to listen on.\n",
283 program_name
, program_name
);
286 printf("\nOther options:\n"
287 " -h, --help display this help message\n");
292 test_netflow_exit(struct unixctl_conn
*conn
,
293 int argc OVS_UNUSED
, const char *argv
[] OVS_UNUSED
,
296 bool *exiting
= exiting_
;
298 unixctl_command_reply(conn
, NULL
);
301 OVSTEST_REGISTER("test-netflow", test_netflow_main
);