diff --git a/usr.sbin/flowctl/flowctl.8 b/usr.sbin/flowctl/flowctl.8 index c9104cb11310..e72486bbf800 100644 --- a/usr.sbin/flowctl/flowctl.8 +++ b/usr.sbin/flowctl/flowctl.8 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2004 Gleb Smirnoff +.\" Copyright (c) 2004-2005 Gleb Smirnoff .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 18, 2004 +.Dd March 23, 2005 .Os .Dt FLOWCTL 8 .Sh NAME @@ -61,6 +61,11 @@ This command is the analog of the .Dq "show ip cache flow" command of a Cisco router. It dumps the contents of the flow cache in Cisco-like format. +It has optional parameter +.Cm verbose , +which is analog of the +.Dq "show ip cache verbose flow" +command. .El .Sh EXIT STATUS .Ex -std diff --git a/usr.sbin/flowctl/flowctl.c b/usr.sbin/flowctl/flowctl.c index 7efdf92ea302..856fe583a3bb 100644 --- a/usr.sbin/flowctl/flowctl.c +++ b/usr.sbin/flowctl/flowctl.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2004, 2005 Gleb Smirnoff + * Copyright (c) 2004-2005 Gleb Smirnoff * Copyright (c) 2001-2003 Roman V. Palagin * All rights reserved. * @@ -54,9 +54,14 @@ static const char rcs_id[] = #define CISCO_SH_FLOW_HEADER "SrcIf SrcIPaddress DstIf DstIPaddress Pr SrcP DstP Pkts\n" #define CISCO_SH_FLOW "%-13s %-15s %-13s %-15s %2u %4.4x %4.4x %6lu\n" -int main(int, char **); +#define CISCO_SH_VERB_FLOW_HEADER "SrcIf SrcIPaddress DstIf DstIPaddress Pr TOS Flgs Pkts\n" \ +"Port Msk AS Port Msk AS NextHop B/Pk Active\n" + +#define CISCO_SH_VERB_FLOW "%-14s %-15s %-14s %-15s %2u %3x %4x %6lu\n" \ + "%4.4x /%-2u %-5u %4.4x /%-2u %-5u %-15s %9u %8u\n\n" static int flow_cache_print(struct ngnf_flows *recs); +static int flow_cache_print_verbose(struct ngnf_flows *recs); static int ctl_show(int, char **); static void help(void); static void execute_command(int, char **); @@ -147,10 +152,17 @@ ctl_show(int argc, char **argv) struct ngnf_flows *data; char path[NG_PATHLEN + 1]; int token, nread, last = 0; + int verbose = 0; + + if (argc > 0 && !strncmp(argv[0], "verbose", strlen(argv[0]))) + verbose = 1; ng_mesg = alloca(SORCVBUF_SIZE); - printf(CISCO_SH_FLOW_HEADER); + if (verbose) + printf(CISCO_SH_VERB_FLOW_HEADER); + else + printf(CISCO_SH_FLOW_HEADER); for (;;) { /* request set of accounting records */ @@ -173,7 +185,10 @@ ctl_show(int argc, char **argv) (data->nentries * sizeof(struct flow_entry_data))))) err(1, "NgRecvMsg(NGM_NETFLOW_SHOW): arglen too small"); - (void )flow_cache_print(data); + if (verbose) + (void )flow_cache_print_verbose(data); + else + (void )flow_cache_print(data); if (data->last != 0) last = data->last; @@ -215,6 +230,47 @@ flow_cache_print(struct ngnf_flows *recs) return (i); } +static int +flow_cache_print_verbose(struct ngnf_flows *recs) +{ + struct flow_entry_data *fle; + char src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN], next[INET_ADDRSTRLEN]; + char src_if[IFNAMSIZ], dst_if[IFNAMSIZ]; + int i; + + /* quick check */ + if (recs->nentries == 0) + return (0); + + fle = recs->entries; + for (i = 0; i < recs->nentries; i++, fle++) { + inet_ntop(AF_INET, &fle->r.r_src, src, sizeof(src)); + inet_ntop(AF_INET, &fle->r.r_dst, dst, sizeof(dst)); + inet_ntop(AF_INET, &fle->next_hop, next, sizeof(next)); + printf(CISCO_SH_VERB_FLOW, + if_indextoname(fle->fle_i_ifx, src_if), + src, + if_indextoname(fle->fle_o_ifx, dst_if), + dst, + fle->r.r_ip_p, + fle->r.r_tos, + fle->tcp_flags, + fle->packets, + ntohs(fle->r.r_sport), + fle->src_mask, + 0, + ntohs(fle->r.r_dport), + fle->dst_mask, + 0, + next, + (u_int)(fle->bytes / fle->packets), + 0); + + } + + return (i); +} + static void help(void) {