diff --git a/print-sflow.c b/print-sflow.c index f27370a..82c3706 100644 --- a/print-sflow.c +++ b/print-sflow.c @@ -61,6 +61,8 @@ static const char rcsid[] _U_ = * */ +#define IPV6_AGENT_OFFSET 12 + struct sflow_datagram_t { u_int8_t version[4]; u_int8_t ip_version[4]; @@ -213,6 +215,12 @@ struct sflow_expanded_counter_sample_t { #define SFLOW_COUNTER_BASEVG 4 #define SFLOW_COUNTER_VLAN 5 #define SFLOW_COUNTER_PROCESSOR 1001 +#define SFLOW_COUNTER_HOST_DESC 2000 +#define SFLOW_COUNTER_HOST_ADAPTORS 2001 +#define SFLOW_COUNTER_HOST_CPU 2003 +#define SFLOW_COUNTER_HOST_MEMORY 2004 +#define SFLOW_COUNTER_HOST_DISC 2005 +#define SFLOW_COUNTER_HOST_NET_IO 2006 static const struct tok sflow_counter_type_values[] = { { SFLOW_COUNTER_GENERIC, "Generic counter"}, @@ -221,6 +229,12 @@ static const struct tok sflow_counter_type_values[] = { { SFLOW_COUNTER_BASEVG, "100 BaseVG counter"}, { SFLOW_COUNTER_VLAN, "Vlan counter"}, { SFLOW_COUNTER_PROCESSOR, "Processor counter"}, + { SFLOW_COUNTER_HOST_DESC, "Host Description"}, + { SFLOW_COUNTER_HOST_ADAPTORS, "Host Adaptors"}, + { SFLOW_COUNTER_HOST_CPU, "Host CPU"}, + { SFLOW_COUNTER_HOST_MEMORY, "Host Memory"}, + { SFLOW_COUNTER_HOST_DISC, "Host Disc"}, + { SFLOW_COUNTER_HOST_NET_IO, "Host Network I/O"}, { 0, NULL} }; @@ -251,7 +265,7 @@ struct sflow_generic_counter_t { u_int8_t ifinbroadcastpkts[4]; u_int8_t ifindiscards[4]; u_int8_t ifinerrors[4]; - u_int8_t ifinunkownprotos[4]; + u_int8_t ifinunknownprotos[4]; u_int8_t ifoutoctets[8]; u_int8_t ifoutunicastpkts[4]; u_int8_t ifoutmulticastpkts[4]; @@ -303,6 +317,136 @@ struct sflow_vlan_counter_t { u_int8_t discards[4]; }; +#define SFLOW_OS_NAME_UNKNOWN 0 +#define SFLOW_OS_NAME_OTHER 1 +#define SFLOW_OS_NAME_LINUX 2 +#define SFLOW_OS_NAME_WINDOWS 3 +#define SFLOW_OS_NAME_DARWIN 4 +#define SFLOW_OS_NAME_HPUX 5 +#define SFLOW_OS_NAME_AIX 6 +#define SFLOW_OS_NAME_DRAGONFLY 7 +#define SFLOW_OS_NAME_FREEBSD 8 +#define SFLOW_OS_NAME_NETBSD 9 +#define SFLOW_OS_NAME_OPENBSD 10 +#define SFLOW_OS_NAME_OSF 11 +#define SFLOW_OS_NAME_SOLARIS 12 + +static const struct tok sflow_os_name_values[] = { + { SFLOW_OS_NAME_UNKNOWN, "Unknown"}, + { SFLOW_OS_NAME_OTHER, "Other"}, + { SFLOW_OS_NAME_LINUX, "Linux"}, + { SFLOW_OS_NAME_WINDOWS, "Windows"}, + { SFLOW_OS_NAME_DARWIN, "Darwin"}, + { SFLOW_OS_NAME_HPUX, "HP-UX"}, + { SFLOW_OS_NAME_AIX, "AIX"}, + { SFLOW_OS_NAME_DRAGONFLY, "DRAGONFLY"}, + { SFLOW_OS_NAME_FREEBSD, "FreeBSD"}, + { SFLOW_OS_NAME_NETBSD, "NetBSD"}, + { SFLOW_OS_NAME_OPENBSD, "OpenBSD"}, + { SFLOW_OS_NAME_OSF, "OSF"}, + { SFLOW_OS_NAME_SOLARIS, "Solaris"}, + { 0, NULL} +}; + + +#define SFLOW_MACH_TYPE_UNKNOWN 0 +#define SFLOW_MACH_TYPE_OTHER 1 +#define SFLOW_MACH_TYPE_X86 2 +#define SFLOW_MACH_TYPE_X86_64 3 +#define SFLOW_MACH_TYPE_IA64 4 +#define SFLOW_MACH_TYPE_SPARC 5 +#define SFLOW_MACH_TYPE_ALPHA 6 +#define SFLOW_MACH_TYPE_POWERPC 7 +#define SFLOW_MACH_TYPE_M68K 8 +#define SFLOW_MACH_TYPE_MIPS 9 +#define SFLOW_MACH_TYPE_ARM 10 +#define SFLOW_MACH_TYPE_HPPA 11 +#define SFLOW_MACH_TYPE_S390 12 + +static const struct tok sflow_mach_type_values[] = { + { SFLOW_MACH_TYPE_UNKNOWN , "Unknown"}, + { SFLOW_MACH_TYPE_OTHER , "Other"}, + { SFLOW_MACH_TYPE_X86 , "x86"}, + { SFLOW_MACH_TYPE_X86_64 , "x86_64"}, + { SFLOW_MACH_TYPE_IA64 , "ia64"}, + { SFLOW_MACH_TYPE_SPARC , "SPARC"}, + { SFLOW_MACH_TYPE_ALPHA , "Alpha"}, + { SFLOW_MACH_TYPE_POWERPC , "PowerPC"}, + { SFLOW_MACH_TYPE_M68K , "M68K"}, + { SFLOW_MACH_TYPE_MIPS , "MIPS"}, + { SFLOW_MACH_TYPE_ARM , "ARM"}, + { SFLOW_MACH_TYPE_HPPA , "PA-RISC"}, + { SFLOW_MACH_TYPE_S390 , "S390"}, + { 0, NULL} + +}; + +/* this looks a bit odd thanks to the embedded variable-length strings */ +struct sflow_host_desc_counter_t { + u_int8_t host_name_len[4]; + u_int8_t uuid[16]; + u_int8_t machine_type[4]; + u_int8_t os_type[4]; + u_int8_t os_rel_len[4]; +}; + +struct sflow_host_cpu_counter_t { + u_int8_t load_one[4]; + u_int8_t load_five[4]; + u_int8_t load_fifteen[4]; + u_int8_t proc_run[4]; + u_int8_t proc_total[4]; + u_int8_t cpu_num[4]; + u_int8_t cpu_speed[4]; + u_int8_t uptime[4]; + u_int8_t cpu_user[4]; + u_int8_t cpu_nice[4]; + u_int8_t cpu_system[4]; + u_int8_t cpu_idle[4]; + u_int8_t cpu_wio[4]; + u_int8_t cpu_intr[4]; + u_int8_t cpu_sintr[4]; + u_int8_t interrupts[4]; + u_int8_t contexts[4]; +}; + +struct sflow_host_memory_counter_t { + u_int8_t mem_total[8]; + u_int8_t mem_free[8]; + u_int8_t mem_shared[8]; + u_int8_t mem_buffers[8]; + u_int8_t mem_cached[8]; + u_int8_t swap_total[8]; + u_int8_t swap_free[8]; + u_int8_t page_in[4]; + u_int8_t page_out[4]; + u_int8_t swap_in[4]; + u_int8_t swap_out[4]; +}; + +struct sflow_host_disc_counter_t { + u_int8_t disc_total[8]; + u_int8_t disc_free[8]; + u_int8_t part_max_used[4]; + u_int8_t reads[4]; + u_int8_t bytes_read[8]; + u_int8_t read_time[4]; + u_int8_t writes[4]; + u_int8_t bytes_written[8]; + u_int8_t write_time[4]; +}; + +struct sflow_host_net_io_counter_t { + u_int8_t bytes_in[8]; + u_int8_t packets_in[4]; + u_int8_t errors_in[4]; + u_int8_t drops_in[4]; + u_int8_t bytes_out[8]; + u_int8_t packets_out[4]; + u_int8_t errors_out[4]; + u_int8_t drops_out[4]; +}; + static int print_sflow_counter_generic(const u_char *pointer, u_int len) { @@ -333,7 +477,7 @@ print_sflow_counter_generic(const u_char *pointer, u_int len) { EXTRACT_32BITS(sflow_gen_counter->ifindiscards)); printf("\n\t In errors %u, unknown protos %u", EXTRACT_32BITS(sflow_gen_counter->ifinerrors), - EXTRACT_32BITS(sflow_gen_counter->ifinunkownprotos)); + EXTRACT_32BITS(sflow_gen_counter->ifinunknownprotos)); printf("\n\t Out octets %" PRIu64 ", unicast pkts %u, multicast pkts %u, broadcast pkts %u, discards %u", EXTRACT_64BITS(sflow_gen_counter->ifoutoctets), @@ -468,6 +612,235 @@ print_sflow_counter_processor(const u_char *pointer, u_int len) { } static int +print_sflow_counter_host_desc(const u_char *pointer, int len) { + + const struct sflow_host_desc_counter_t *sflow_host_desc_counter; + int offset; + int name_len; + int full_size; + + + /* first sanity check, which will not include the strings + themselves but will include all the "fixed" contents. we will + do additional checks as the string lengths become known */ + full_size = sizeof(struct sflow_host_desc_counter_t); + if (len < full_size) + return 1; + + sflow_host_desc_counter = (const struct sflow_host_desc_counter_t *)pointer; + offset = 0; + + name_len = EXTRACT_32BITS(sflow_host_desc_counter->host_name_len); + /* everything is supposed to be padded to 4 byte boundaries so + figure the number of four byte quantities */ + offset += ((name_len + 3) / 4) * 4; + + full_size += offset; + + /* next sanity check */ + if (len < full_size) + return 1; + + /* why yes, this does look funny, it will make sense if you look + at sflow_host_desc_counter_t :) */ + printf("\n\t name %*s, ",name_len,sflow_host_desc_counter->uuid); + + + printf("uuid TBD, machine type %s, os %s, ", + tok2str(sflow_mach_type_values, "UNKNOWN", + EXTRACT_32BITS(sflow_host_desc_counter->machine_type + offset)), + tok2str(sflow_os_name_values, "UNKNOWN", + EXTRACT_32BITS(sflow_host_desc_counter->os_type + offset))); + + name_len = EXTRACT_32BITS(sflow_host_desc_counter->os_rel_len + offset); + + /* is there enough for the release name? */ + if (len < (full_size + name_len)) + return 1; + + printf("release %*s",name_len,sflow_host_desc_counter->os_rel_len + 4 + offset); + + return 0; + +} + +struct sflow_counter_host_adaptors_t { + u_int8_t num_adaptors[4]; +}; + +struct sflow_counter_host_adaptor_t { + u_int8_t ifindex[4]; + u_int8_t num_macs[4]; +}; + +static int +print_sflow_counter_host_adaptors(const u_char *pointer, int len) { + + int num_adaptors, num_macs; + const u_char *tptr; + const struct sflow_counter_host_adaptor_t *host_adaptor; + int tlen, i, j, m; + + tlen = len; + + /* first get the number of adaptors */ + if (len < sizeof(struct sflow_counter_host_adaptors_t)) + return 1; + + tptr = pointer; + num_adaptors = EXTRACT_32BITS(tptr); + + tptr += sizeof(struct sflow_counter_host_adaptors_t); + tlen -= sizeof(struct sflow_counter_host_adaptors_t); + + printf("\n\t num_adaptors %u",num_adaptors); + for (i = 0; i < num_adaptors; i++) { + if (tlen < sizeof(struct sflow_counter_host_adaptor_t)) + return 1; + + host_adaptor = (const struct sflow_counter_host_adaptor_t *)tptr; + num_macs = EXTRACT_32BITS(host_adaptor->num_macs); + printf("\n\t ifindex %u mac%s ", + EXTRACT_32BITS(host_adaptor->ifindex), + (num_macs > 1) ? "s" : ""); + tptr += sizeof(struct sflow_counter_host_adaptor_t); + tlen -= sizeof(struct sflow_counter_host_adaptor_t); + for (j = 0; j < num_macs; j++) { + /* yes, 8 - they are supposed to be padded out to a four + byte boundary */ + if (tlen < 8) + return 1; + printf("%s %s", + (j > 0) ? "," : "", + etheraddr_string(tptr)); + tlen -= 8; + tptr += 8; + } + } + + return 0; +} + + +static int +print_sflow_counter_host_cpu(const u_char *pointer, int len) { + + const struct sflow_host_cpu_counter_t *sflow_host_cpu_counter; + + float lav1,lav5,lav15; + int temp; + + if (len < sizeof(struct sflow_host_cpu_counter_t)) + return 1; + + sflow_host_cpu_counter = (const struct sflow_host_cpu_counter_t *)pointer; + + temp = EXTRACT_32BITS(sflow_host_cpu_counter->load_one); + memcpy(&temp,&lav1,4); + + temp = EXTRACT_32BITS(sflow_host_cpu_counter->load_five); + memcpy(&temp,&lav5,4); + + temp = EXTRACT_32BITS(sflow_host_cpu_counter->load_fifteen); + memcpy(&temp,&lav15,4); + + printf("\n\t lavg 1m %f, lavg 5m %f, lavg 15m %f, running processes %u, total processes %u, num cpus %u, cpu MHz %u, uptime secs %u, user cpu ms %u nice cpu ms %u, sys cpu ms %u, idle cpu ms %u, wio cpu ms %u, intr cpu ms %u, sintr cpu ms %u, interrupts %u, context switches %u", + lav1, + lav5, + lav15, + EXTRACT_32BITS(sflow_host_cpu_counter->proc_run), + EXTRACT_32BITS(sflow_host_cpu_counter->proc_total), + EXTRACT_32BITS(sflow_host_cpu_counter->cpu_num), + EXTRACT_32BITS(sflow_host_cpu_counter->cpu_speed), + EXTRACT_32BITS(sflow_host_cpu_counter->uptime), + EXTRACT_32BITS(sflow_host_cpu_counter->cpu_user), + EXTRACT_32BITS(sflow_host_cpu_counter->cpu_nice), + EXTRACT_32BITS(sflow_host_cpu_counter->cpu_system), + EXTRACT_32BITS(sflow_host_cpu_counter->cpu_idle), + EXTRACT_32BITS(sflow_host_cpu_counter->cpu_wio), + EXTRACT_32BITS(sflow_host_cpu_counter->cpu_intr), + EXTRACT_32BITS(sflow_host_cpu_counter->cpu_sintr), + EXTRACT_32BITS(sflow_host_cpu_counter->interrupts), + EXTRACT_32BITS(sflow_host_cpu_counter->contexts)); + + return 0; +} + +static int +print_sflow_counter_host_memory(const u_char *pointer, int len) { + + const struct sflow_host_memory_counter_t *sflow_host_memory_counter; + + if (len < sizeof(struct sflow_host_memory_counter_t)) + return 1; + + sflow_host_memory_counter = (const struct sflow_host_memory_counter_t *)pointer; + printf("\n\t mem tot %"PRIu64", mem free %"PRIu64", mem shared %"PRIu64", mem buffers %"PRIu64", mem cache %"PRIu64", swap total %"PRIu64", swap free %"PRIu64", page in %u, page out %u, swap in %u, swap out %u", + EXTRACT_64BITS(sflow_host_memory_counter->mem_total), + EXTRACT_64BITS(sflow_host_memory_counter->mem_free), + EXTRACT_64BITS(sflow_host_memory_counter->mem_shared), + EXTRACT_64BITS(sflow_host_memory_counter->mem_buffers), + EXTRACT_64BITS(sflow_host_memory_counter->mem_cached), + EXTRACT_64BITS(sflow_host_memory_counter->swap_total), + EXTRACT_64BITS(sflow_host_memory_counter->swap_free), + EXTRACT_32BITS(sflow_host_memory_counter->page_in), + EXTRACT_32BITS(sflow_host_memory_counter->page_out), + EXTRACT_32BITS(sflow_host_memory_counter->swap_in), + EXTRACT_32BITS(sflow_host_memory_counter->swap_out)); + + return 0; + +} + +static int +print_sflow_counter_host_disc(const u_char *pointer, int len) { + + const struct sflow_host_disc_counter_t *sflow_host_disc_counter; + + if (len < sizeof(struct sflow_host_disc_counter_t)) + return 1; + + sflow_host_disc_counter = (const struct sflow_host_disc_counter_t *)pointer; + + printf("\n\t total disc %"PRIu64", free disc %"PRIu64", max part pct used %.2f, reads %u, read bytes %"PRIu64", read ms %u, writes %u, write bytes %"PRIu64", write ms %u", + EXTRACT_64BITS(sflow_host_disc_counter->disc_total), + EXTRACT_64BITS(sflow_host_disc_counter->disc_free), + (float) EXTRACT_32BITS(sflow_host_disc_counter->part_max_used) / 100.0, + EXTRACT_32BITS(sflow_host_disc_counter->reads), + EXTRACT_64BITS(sflow_host_disc_counter->bytes_read), + EXTRACT_32BITS(sflow_host_disc_counter->read_time), + EXTRACT_32BITS(sflow_host_disc_counter->writes), + EXTRACT_64BITS(sflow_host_disc_counter->bytes_written), + EXTRACT_32BITS(sflow_host_disc_counter->write_time)); + + return 0; + +} + +static int +print_sflow_counter_host_net_io(const u_char *pointer, int len) { + + const struct sflow_host_net_io_counter_t *sflow_host_net_io_counter; + + if (len < sizeof(struct sflow_host_net_io_counter_t)) + return 1; + + sflow_host_net_io_counter = (const struct sflow_host_net_io_counter_t *)pointer; + + printf("\n\t bytes in %"PRIu64", pkts in %u, err in %u, drop in %u, bytes out %"PRIu64", pkts out %u, err out %u, drop out %u", + EXTRACT_64BITS(sflow_host_net_io_counter->bytes_in), + EXTRACT_32BITS(sflow_host_net_io_counter->packets_in), + EXTRACT_32BITS(sflow_host_net_io_counter->errors_in), + EXTRACT_32BITS(sflow_host_net_io_counter->drops_in), + EXTRACT_64BITS(sflow_host_net_io_counter->bytes_out), + EXTRACT_32BITS(sflow_host_net_io_counter->packets_out), + EXTRACT_32BITS(sflow_host_net_io_counter->errors_out), + EXTRACT_32BITS(sflow_host_net_io_counter->drops_out)); + + return 0; +} + +static int sflow_print_counter_records(const u_char *pointer, u_int len, u_int records) { u_int nrecords; @@ -529,6 +902,30 @@ sflow_print_counter_records(const u_char *pointer, u_int len, u_int records) { if (print_sflow_counter_processor(tptr,tlen)) return 1; break; + case SFLOW_COUNTER_HOST_DESC: + if (print_sflow_counter_host_desc(tptr,tlen)) + return 1; + break; + case SFLOW_COUNTER_HOST_ADAPTORS: + if (print_sflow_counter_host_adaptors(tptr,tlen)) + return 1; + break; + case SFLOW_COUNTER_HOST_CPU: + if (print_sflow_counter_host_cpu(tptr,tlen)) + return 1; + break; + case SFLOW_COUNTER_HOST_MEMORY: + if (print_sflow_counter_host_memory(tptr,tlen)) + return 1; + break; + case SFLOW_COUNTER_HOST_DISC: + if (print_sflow_counter_host_disc(tptr,tlen)) + return 1; + break; + case SFLOW_COUNTER_HOST_NET_IO: + if (print_sflow_counter_host_net_io(tptr,tlen)) + return 1; + break; default: if (vflag <= 1) print_unknown_data(tptr, "\n\t\t", counter_len); @@ -819,7 +1216,7 @@ sflow_print(const u_char *pptr, u_int len) { u_int tlen; u_int32_t sflow_sample_type, sflow_sample_len; u_int32_t nsamples; - + u_int32_t v6_offset; tptr = pptr; tlen = len; @@ -846,6 +1243,7 @@ sflow_print(const u_char *pptr, u_int len) { } /* ok they seem to want to know everything - lets fully decode it */ + nsamples=EXTRACT_32BITS(sflow_datagram->samples); printf("sFlowv%u, %s agent %s, agent-id %u, seqnum %u, uptime %u, samples %u, length %u", EXTRACT_32BITS(sflow_datagram->version),