2 * Copyright (c) 2011, 2012 Nicira Networks.
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"
30 #include "poll-loop.h"
31 #include "socket-util.h"
36 static void usage(void) NO_RETURN;
37 static void parse_options(int argc, char *argv[]);
39 static unixctl_cb_func test_netflow_exit;
42 print_netflow(struct ofpbuf *buf)
44 const struct netflow_v5_header *hdr;
47 hdr = ofpbuf_try_pull(buf, sizeof *hdr);
49 printf("truncated NetFlow packet header\n");
52 printf("header: v%"PRIu16", "
54 "now %"PRIu32".%09"PRIu32", "
56 "engine %"PRIu8",%"PRIu8,
58 ntohl(hdr->sysuptime),
59 ntohl(hdr->unix_secs), ntohl(hdr->unix_nsecs),
61 hdr->engine_type, hdr->engine_id);
62 if (hdr->sampling_interval != htons(0)) {
63 printf(", interval %"PRIu16, ntohs(hdr->sampling_interval));
67 for (i = 0; i < ntohs(hdr->count); i++) {
68 struct netflow_v5_record *rec;
70 rec = ofpbuf_try_pull(buf, sizeof *rec);
72 printf("truncated NetFlow records\n");
76 printf("rec: "IP_FMT" > "IP_FMT,
77 IP_ARGS(&rec->src_addr), IP_ARGS(&rec->dst_addr));
79 printf(", if %"PRIu16" > %"PRIu16,
80 ntohs(rec->input), ntohs(rec->output));
82 printf(", %"PRIu32" pkts, %"PRIu32" bytes",
83 ntohl(rec->packet_count), ntohl(rec->byte_count));
85 switch (rec->ip_proto) {
87 printf(", TCP %"PRIu16" > %"PRIu16,
88 ntohs(rec->src_port), ntohs(rec->dst_port));
91 if (rec->tcp_flags & TCP_SYN) {
94 if (rec->tcp_flags & TCP_FIN) {
97 if (rec->tcp_flags & TCP_PSH) {
100 if (rec->tcp_flags & TCP_RST) {
103 if (rec->tcp_flags & TCP_URG) {
106 if (rec->tcp_flags & TCP_ACK) {
109 if (rec->tcp_flags & 0x40) {
112 if (rec->tcp_flags & 0x80) {
119 printf(", UDP %"PRIu16" > %"PRIu16,
120 ntohs(rec->src_port), ntohs(rec->dst_port));
124 printf(", ICMP %"PRIu16":%"PRIu16,
125 ntohs(rec->dst_port) >> 8,
126 ntohs(rec->dst_port) & 0xff);
127 if (rec->src_port != htons(0)) {
128 printf(", src_port=%"PRIu16, ntohs(rec->src_port));
133 printf(", proto %"PRIu8, rec->ip_proto);
137 if (rec->ip_proto != IPPROTO_TCP && rec->tcp_flags != 0) {
138 printf(", flags %"PRIx8, rec->tcp_flags);
141 if (rec->ip_proto != IPPROTO_TCP &&
142 rec->ip_proto != IPPROTO_UDP &&
143 rec->ip_proto != IPPROTO_ICMP) {
144 if (rec->src_port != htons(0)) {
145 printf(", src_port %"PRIu16, ntohs(rec->src_port));
147 if (rec->dst_port != htons(0)) {
148 printf(", dst_port %"PRIu16, ntohs(rec->dst_port));
153 printf(", TOS %"PRIx8, rec->ip_tos);
156 printf(", time %"PRIu32"...%"PRIu32,
157 ntohl(rec->init_time), ntohl(rec->used_time));
159 if (rec->nexthop != htonl(0)) {
160 printf(", nexthop "IP_FMT, IP_ARGS(&rec->nexthop));
162 if (rec->src_as != htons(0) || rec->dst_as != htons(0)) {
163 printf(", AS %"PRIu16" > %"PRIu16,
164 ntohs(rec->src_as), ntohs(rec->dst_as));
166 if (rec->src_mask != 0 || rec->dst_mask != 0) {
167 printf(", mask %"PRIu8" > %"PRIu8, rec->src_mask, rec->dst_mask);
170 printf(", pad1 %"PRIu8, rec->pad1);
172 if (rec->pad[0] || rec->pad[1]) {
173 printf(", pad %"PRIu8", %"PRIu8, rec->pad[0], rec->pad[1]);
179 printf("%zu extra bytes after last record\n", buf->size);
184 main(int argc, char *argv[])
186 struct unixctl_server *server;
187 enum { MAX_RECV = 1500 };
190 bool exiting = false;
195 proctitle_init(argc, argv);
196 set_program_name(argv[0]);
197 parse_options(argc, argv);
199 if (argc - optind != 1) {
200 ovs_fatal(0, "exactly one non-option argument required "
201 "(use --help for help)");
203 target = argv[optind];
205 sock = inet_open_passive(SOCK_DGRAM, target, 0, NULL, DSCP_INVALID);
207 ovs_fatal(0, "%s: failed to open (%s)", argv[1], strerror(-sock));
210 daemon_save_fd(STDOUT_FILENO);
213 error = unixctl_server_create(NULL, &server);
215 ovs_fatal(error, "failed to create unixctl server");
217 unixctl_command_register("exit", "", 0, 0, test_netflow_exit, &exiting);
219 daemonize_complete();
221 ofpbuf_init(&buf, MAX_RECV);
226 unixctl_server_run(server);
230 retval = read(sock, buf.data, buf.allocated);
231 } while (retval < 0 && errno == EINTR);
233 ofpbuf_put_uninit(&buf, retval);
245 poll_fd_wait(sock, POLLIN);
246 unixctl_server_wait(server);
254 parse_options(int argc, char *argv[])
259 static struct option long_options[] = {
260 {"verbose", optional_argument, NULL, 'v'},
261 {"help", no_argument, NULL, 'h'},
265 char *short_options = long_options_to_short_options(long_options);
268 int c = getopt_long(argc, argv, short_options, long_options, NULL);
278 vlog_set_verbosity(optarg);
281 DAEMON_OPTION_HANDLERS
296 printf("%s: netflow collector test utility\n"
297 "usage: %s [OPTIONS] PORT[:IP]\n"
298 "where PORT is the UDP port to listen on and IP is optionally\n"
299 "the IP address to listen on.\n",
300 program_name, program_name);
303 printf("\nOther options:\n"
304 " -h, --help display this help message\n");
309 test_netflow_exit(struct unixctl_conn *conn,
310 int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
313 bool *exiting = exiting_;
315 unixctl_command_reply(conn, NULL);