From eaa7a857c8794b15062c9e93a79deb3259ebe468 Mon Sep 17 00:00:00 2001 From: Peter Haag Date: Wed, 27 Dec 2017 19:56:21 +0100 Subject: [PATCH] Update sflow code to commit 7322984 of https://github.com/sflow/sflowtool --- ChangeLog | 4 + bin/Makefile.am | 2 +- bin/applybits_inline.c | 22 +- bin/collector.c | 30 +- bin/collector_inline.c | 23 +- bin/exporter.c | 18 +- bin/ft2nfdump.c | 9 +- bin/ipfix.c | 70 +- bin/ipfix.h | 10 +- bin/netflow_v1.c | 10 +- bin/netflow_v5_v7.c | 16 +- bin/netflow_v9.c | 40 +- bin/nf_common.c | 216 +- bin/nfanon.c | 64 +- bin/nfexport.c | 22 +- bin/nffile.c | 14 +- bin/nffile.h | 13 +- bin/nffile_inline.c | 107 +- bin/nfgen.c | 50 +- bin/nflowcache.c | 23 +- bin/nfreader.c | 27 +- bin/nfstat.c | 28 +- bin/nftest.c | 174 +- bin/pack.pcap | Bin 479666 -> 0 bytes bin/sfcapd.c | 2 +- bin/sflow.c | 2751 ------------------------- bin/sflow.h | 1800 ++++++++++++---- bin/sflow_nfdump.c | 4431 ++++++++++++++++++++++++++++++++++++++++ bin/sflow_nfdump.h | 55 + bin/sflow_proto.h | 702 ------- bin/sflow_v2v4.h | 436 ++++ 31 files changed, 6847 insertions(+), 4322 deletions(-) delete mode 100644 bin/pack.pcap delete mode 100644 bin/sflow.c create mode 100644 bin/sflow_nfdump.c create mode 100644 bin/sflow_nfdump.h delete mode 100644 bin/sflow_proto.h create mode 100755 bin/sflow_v2v4.h diff --git a/ChangeLog b/ChangeLog index 2e338ad..ec981c9 100755 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2017-12-27 +- Add ipfix delta timestamp elements 158/159. +- Update sflow code to commit 7322984 of https://github.com/sflow/sflowtool + 2017-12-22 - Fix potential memory leaks in nfpcapd diff --git a/bin/Makefile.am b/bin/Makefile.am index 3b02f10..091652c 100755 --- a/bin/Makefile.am +++ b/bin/Makefile.am @@ -111,7 +111,7 @@ nfpcapd_LDADD += -lpcap nfpcapd_LDFLAGS = -pthread endif -sfcapd_SOURCES = sfcapd.c sflow.c sflow.h sflow_proto.h \ +sfcapd_SOURCES = sfcapd.c sflow_nfdump.c sflow_nfdump.h sflow.h sflow_v2v4.h \ $(nfstatfile) $(launch) \ $(nfnet) $(collector) $(bookkeeper) $(expire) sfcapd_LDADD = -lnfdump diff --git a/bin/applybits_inline.c b/bin/applybits_inline.c index a35fbb6..6b13836 100755 --- a/bin/applybits_inline.c +++ b/bin/applybits_inline.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2017, Peter Haag * Copyright (c) 2014, Peter Haag * Copyright (c) 2009, Peter Haag * Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung @@ -28,11 +29,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * $Author: haag $ - * - * $Id: applybits_inline.c 39 2009-11-25 08:11:15Z haag $ - * - * $LastChangedRevision: 39 $ * */ @@ -46,11 +42,11 @@ static inline void ApplyNetMaskBits(master_record_t *flow_record, int apply_netb uint32_t mask_bits = flow_record->src_mask; if ( mask_bits > 64 ) { mask = 0xffffffffffffffffLL << ( 128 - mask_bits ); - flow_record->v6.srcaddr[1] &= mask; + flow_record->V6.srcaddr[1] &= mask; } else { mask = 0xffffffffffffffffLL << ( 64 - mask_bits ); - flow_record->v6.srcaddr[0] &= mask; - flow_record->v6.srcaddr[1] = 0; + flow_record->V6.srcaddr[0] &= mask; + flow_record->V6.srcaddr[1] = 0; } } if ( apply_netbits & 2 ) { @@ -59,21 +55,21 @@ static inline void ApplyNetMaskBits(master_record_t *flow_record, int apply_netb if ( mask_bits > 64 ) { mask = 0xffffffffffffffffLL << ( 128 - mask_bits ); - flow_record->v6.dstaddr[1] &= mask; + flow_record->V6.dstaddr[1] &= mask; } else { mask = 0xffffffffffffffffLL << ( 64 - mask_bits ); - flow_record->v6.dstaddr[0] &= mask; - flow_record->v6.dstaddr[1] = 0; + flow_record->V6.dstaddr[0] &= mask; + flow_record->V6.dstaddr[1] = 0; } } } else { // IPv4 if ( apply_netbits & 1 ) { uint32_t srcmask = 0xffffffff << ( 32 - flow_record->src_mask ); - flow_record->v4.srcaddr &= srcmask; + flow_record->V4.srcaddr &= srcmask; } if ( apply_netbits & 2 ) { uint32_t dstmask = 0xffffffff << ( 32 - flow_record->dst_mask ); - flow_record->v4.dstaddr &= dstmask; + flow_record->V4.dstaddr &= dstmask; } } diff --git a/bin/collector.c b/bin/collector.c index 47ad6ae..a86c56d 100755 --- a/bin/collector.c +++ b/bin/collector.c @@ -155,15 +155,15 @@ int ok; uint64_t _ip[2]; ok = inet_pton(PF_INET6, p, _ip); (*source)->sa_family = PF_INET6; - (*source)->ip.v6[0] = ntohll(_ip[0]); - (*source)->ip.v6[1] = ntohll(_ip[1]); + (*source)->ip.V6[0] = ntohll(_ip[0]); + (*source)->ip.V6[1] = ntohll(_ip[1]); } else { uint32_t _ip; ok = inet_pton(PF_INET, p, &_ip); (*source)->sa_family = PF_INET; - (*source)->ip.v6[0] = 0; - (*source)->ip.v6[1] = 0; - (*source)->ip.v4 = ntohl(_ip); + (*source)->ip.V6[0] = 0; + (*source)->ip.V6[1] = 0; + (*source)->ip.V4 = ntohl(_ip); } switch (ok) { case 0: @@ -339,9 +339,9 @@ int err; } #endif (*source)->sa_family = PF_INET; - (*source)->ip.v6[0] = 0; - (*source)->ip.v6[1] = 0; - (*source)->ip.v4 = ntohl(u.sa_in->sin_addr.s_addr); + (*source)->ip.V6[0] = 0; + (*source)->ip.V6[1] = 0; + (*source)->ip.V4 = ntohl(u.sa_in->sin_addr.s_addr); ptr = &u.sa_in->sin_addr; } break; case PF_INET6: { @@ -358,14 +358,14 @@ int err; #endif // ptr = &((struct sockaddr_in6 *)sa)->sin6_addr; (*source)->sa_family = PF_INET6; - (*source)->ip.v6[0] = ntohll(ip_ptr[0]); - (*source)->ip.v6[1] = ntohll(ip_ptr[1]); + (*source)->ip.V6[0] = ntohll(ip_ptr[0]); + (*source)->ip.V6[1] = ntohll(ip_ptr[1]); ptr = &u.sa_in6->sin6_addr; } break; default: // keep compiler happy - (*source)->ip.v6[0] = 0; - (*source)->ip.v6[1] = 0; + (*source)->ip.V6[0] = 0; + (*source)->ip.V6[1] = 0; ptr = NULL; LogError("Unknown sa fanily: %d in '%s', line '%d'", ss->ss_family, __FILE__, __LINE__ ); @@ -530,14 +530,14 @@ int FlushInfoExporter(FlowSource_t *fs, exporter_info_record_t *exporter) { char ipstr[IP_STRING_LEN]; printf("Flush Exporter: "); if ( exporter->sa_family == AF_INET ) { - uint32_t _ip = htonl(exporter->ip.v4); + uint32_t _ip = htonl(exporter->ip.V4); inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr)); printf("SysID: %u, IP: %16s, version: %u, ID: %2u\n", exporter->sysid, ipstr, exporter->version, exporter->id); } else if ( exporter->sa_family == AF_INET6 ) { uint64_t _ip[2]; - _ip[0] = htonll(exporter->ip.v6[0]); - _ip[1] = htonll(exporter->ip.v6[1]); + _ip[0] = htonll(exporter->ip.V6[0]); + _ip[1] = htonll(exporter->ip.V6[1]); inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr)); printf("SysID: %u, IP: %40s, version: %u, ID: %2u\n", exporter->sysid, ipstr, exporter->version, exporter->id); diff --git a/bin/collector_inline.c b/bin/collector_inline.c index 4e1c22b..aaf518b 100755 --- a/bin/collector_inline.c +++ b/bin/collector_inline.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2017, Peter Haag * Copyright (c) 2014, Peter Haag * Copyright (c) 2009, Peter Haag * Copyright (c) 2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung @@ -28,12 +29,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * $Author: haag $ - * - * $Id: collector_inline.c 37 2009-11-10 08:40:30Z haag $ - * - * $LastChangedRevision: 37 $ - * */ static inline FlowSource_t *GetFlowSource(struct sockaddr_storage *ss) { @@ -59,9 +54,9 @@ char as[100]; return NULL; } #endif - ip.v6[0] = 0; - ip.v6[1] = 0; - ip.v4 = ntohl(u.sa_in->sin_addr.s_addr); + ip.V6[0] = 0; + ip.V6[1] = 0; + ip.V4 = ntohl(u.sa_in->sin_addr.s_addr); ptr = &u.sa_in->sin_addr; } break; case PF_INET6: { @@ -75,14 +70,14 @@ char as[100]; } #endif // ptr = &((struct sockaddr_in6 *)sa)->sin6_addr; - ip.v6[0] = ntohll(ip_ptr[0]); - ip.v6[1] = ntohll(ip_ptr[1]); + ip.V6[0] = ntohll(ip_ptr[0]); + ip.V6[1] = ntohll(ip_ptr[1]); ptr = &u.sa_in6->sin6_addr; } break; default: // keep compiler happy - ip.v6[0] = 0; - ip.v6[1] = 0; + ip.V6[0] = 0; + ip.V6[1] = 0; ptr = NULL; LogError("Unknown sa fanily: %d in '%s', line '%d'", ss->ss_family, __FILE__, __LINE__ ); @@ -97,7 +92,7 @@ char as[100]; fs = FlowSource; while ( fs ) { - if ( ip.v6[0] == fs->ip.v6[0] && ip.v6[1] == fs->ip.v6[1] ) + if ( ip.V6[0] == fs->ip.V6[0] && ip.V6[1] == fs->ip.V6[1] ) return fs; // if we match any source, store the current IP address - works as faster cache next time diff --git a/bin/exporter.c b/bin/exporter.c index 974935b..687d7b9 100755 --- a/bin/exporter.c +++ b/bin/exporter.c @@ -151,14 +151,14 @@ char *p1, *p2; #define IP_STRING_LEN 40 char ipstr[IP_STRING_LEN]; if ( exporter_record->sa_family == AF_INET ) { - uint32_t _ip = htonl(exporter_record->ip.v4); + uint32_t _ip = htonl(exporter_record->ip.V4); inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr)); printf("SysID: %u, IP: %16s, version: %u, ID: %2u, Slot: %u\n", exporter_record->sysid, ipstr, exporter_record->version, exporter_record->id, id); } else if ( exporter_record->sa_family == AF_INET6 ) { uint64_t _ip[2]; - _ip[0] = htonll(exporter_record->ip.v6[0]); - _ip[1] = htonll(exporter_record->ip.v6[1]); + _ip[0] = htonll(exporter_record->ip.V6[0]); + _ip[1] = htonll(exporter_record->ip.V6[1]); inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr)); printf("SysID: %u, IP: %40s, version: %u, ID: %2u, Slot: %u\n", exporter_record->sysid, ipstr, exporter_record->version, exporter_record->id, id); @@ -347,14 +347,14 @@ uint64_t total_bytes; found = 1; printf("\n"); if ( exporter_record->sa_family == AF_INET ) { - uint32_t _ip = htonl(exporter_record->ip.v4); + uint32_t _ip = htonl(exporter_record->ip.V4); inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr)); printf("SysID: %u, IP: %16s, version: %u, ID: %2u, Sequence Failures: %u\n", exporter_record->sysid, ipstr, exporter_record->version, exporter_record->exporter_id, exporter_record->sequence_failure); } else if ( exporter_record->sa_family == AF_INET6 ) { uint64_t _ip[2]; - _ip[0] = htonll(exporter_record->ip.v6[0]); - _ip[1] = htonll(exporter_record->ip.v6[1]); + _ip[0] = htonll(exporter_record->ip.V6[0]); + _ip[1] = htonll(exporter_record->ip.V6[1]); inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr)); printf("SysID: %u, IP: %40s, version: %u, ID: %2u, Sequence Failures: %u\n", exporter_record->sysid, ipstr, exporter_record->version, exporter_record->exporter_id, exporter_record->sequence_failure); @@ -410,7 +410,7 @@ uint64_t total_bytes; printf("\n"); exporter = &exporter_list[i]->info; if ( exporter->sa_family == AF_INET ) { - uint32_t _ip = htonl(exporter->ip.v4); + uint32_t _ip = htonl(exporter->ip.V4); inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr)); if ( exporter_list[i]->flows ) printf("SysID: %u, IP: %16s, version: %u, ID: %2u, Sequence failures: %u, packets: %llu, flows: %llu\n", @@ -424,8 +424,8 @@ uint64_t total_bytes; } else if ( exporter->sa_family == AF_INET6 ) { uint64_t _ip[2]; - _ip[0] = htonll(exporter->ip.v6[0]); - _ip[1] = htonll(exporter->ip.v6[1]); + _ip[0] = htonll(exporter->ip.V6[0]); + _ip[1] = htonll(exporter->ip.V6[1]); inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr)); if ( exporter_list[i]->flows ) printf("SysID: %u, IP: %40s, version: %u, ID: %2u, Sequence failures: %u, packets: %llu, flows: %llu\n ", diff --git a/bin/ft2nfdump.c b/bin/ft2nfdump.c index 4f37d76..86e7fa1 100644 --- a/bin/ft2nfdump.c +++ b/bin/ft2nfdump.c @@ -1,5 +1,6 @@ /* * All rights reserved. + * Copyright (c) 2017, Peter Haag * Copyright (c) 2016, Peter Haag * Copyright (c) 2014, Peter Haag * Copyright (c) 2009, Peter Haag @@ -238,8 +239,8 @@ uint32_t cnt; record.last = ftt.secs; record.msec_last = ftt.msecs; - record.v4.srcaddr = *((uint32_t*)(rec+fo.srcaddr)); - record.v4.dstaddr = *((uint32_t*)(rec+fo.dstaddr)); + record.V4.srcaddr = *((uint32_t*)(rec+fo.srcaddr)); + record.V4.dstaddr = *((uint32_t*)(rec+fo.dstaddr)); record.srcport = *((uint16_t*)(rec+fo.srcport)); record.dstport = *((uint16_t*)(rec+fo.dstport)); @@ -268,10 +269,10 @@ uint32_t cnt; record.dst_tos = 0; break; case EX_ROUTER_IP_v4: - record.ip_nexthop.v4 = *((uint32_t*)(rec+fo.peer_nexthop)); + record.ip_nexthop.V4 = *((uint32_t*)(rec+fo.peer_nexthop)); break; case EX_NEXT_HOP_v4: - record.ip_router.v4 = *((uint32_t*)(rec+fo.router_sc)); + record.ip_router.V4 = *((uint32_t*)(rec+fo.router_sc)); break; case EX_ROUTER_ID: record.engine_type = *((uint8_t*)(rec+fo.engine_type)); diff --git a/bin/ipfix.c b/bin/ipfix.c index 3e7b397..dbc18cc 100644 --- a/bin/ipfix.c +++ b/bin/ipfix.c @@ -28,12 +28,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * $Author:$ - * - * $Id:$ - * - * $LastChangedRevision:$ - * */ #include "config.h" @@ -106,12 +100,13 @@ typedef struct sequence_map_s { #define move_mac 11 #define move_mpls 12 #define Time64Mili 13 -#define saveICMP 14 -#define zero8 15 -#define zero16 16 -#define zero32 17 -#define zero64 18 -#define zero128 19 +#define TimeDeltaMicro 14 +#define saveICMP 15 +#define zero8 16 +#define zero16 17 +#define zero32 18 +#define zero64 19 +#define zero128 20 uint32_t id; // sequence ID as defined above uint16_t input_offset; // copy/process data at this input offset @@ -135,6 +130,7 @@ typedef struct input_translation_s { uint32_t output_record_size; // required size in nfdump format // tmp vars needed while processing the data record + int delta_time; // delta micro or absolute ms time stamps uint64_t flow_start; // start time in msec uint64_t flow_end; // end time in msec uint32_t ICMP_offset; // offset of ICMP type/code in data stream @@ -266,6 +262,8 @@ static struct ipfix_element_map_s { { IPFIX_postSourceMacAddress, _6bytes, _8bytes, move_mac, zero64, EX_MAC_2}, { IPFIX_flowStartMilliseconds, _8bytes, _8bytes, Time64Mili, zero32, COMMON_BLOCK}, { IPFIX_flowEndMilliseconds, _8bytes, _8bytes, Time64Mili, zero32, COMMON_BLOCK}, + { IPFIX_flowStartDeltaMicroseconds, _4bytes, _4bytes, TimeDeltaMicro, zero32, COMMON_BLOCK}, + { IPFIX_flowEndDeltaMicroseconds, _4bytes, _4bytes, TimeDeltaMicro, zero32, COMMON_BLOCK}, {0, 0, 0} }; @@ -319,6 +317,8 @@ static inline void Process_ipfix_template_withdraw(exporter_ipfix_domain_t *expo static inline void Process_ipfix_option_data(exporter_ipfix_domain_t *exporter, void *data_flowset, FlowSource_t *fs); +static inline void Process_ipfix_data(exporter_ipfix_domain_t *exporter, uint32_t ExportTime, void *data_flowset, FlowSource_t *fs, input_translation_t *table ); + #include "inline.c" #include "nffile_inline.c" @@ -356,18 +356,18 @@ uint32_t ObservationDomain = ntohl(ipfix_header->ObservationDomain); while ( *e ) { if ( (*e)->info.id == ObservationDomain && (*e)->info.version == 10 && - (*e)->info.ip.v6[0] == fs->ip.v6[0] && (*e)->info.ip.v6[1] == fs->ip.v6[1]) + (*e)->info.ip.V6[0] == fs->ip.V6[0] && (*e)->info.ip.V6[1] == fs->ip.V6[1]) return *e; e = &((*e)->next); } if ( fs->sa_family == AF_INET ) { - uint32_t _ip = htonl(fs->ip.v4); + uint32_t _ip = htonl(fs->ip.V4); inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr)); } else if ( fs->sa_family == AF_INET6 ) { uint64_t _ip[2]; - _ip[0] = htonll(fs->ip.v6[0]); - _ip[1] = htonll(fs->ip.v6[1]); + _ip[0] = htonll(fs->ip.V6[0]); + _ip[1] = htonll(fs->ip.V6[1]); inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr)); } else { strncpy(ipstr, "", IP_STRING_LEN); @@ -637,7 +637,8 @@ size_t size_required; table->flags = 0; SetFlag(table->flags, FLAG_PKG_64); SetFlag(table->flags, FLAG_BYTES_64); - table->ICMP_offset = 0; + table->delta_time = 0; + table->ICMP_offset = 0; // table->sampler_offset = 0; // table->sampler_size = 0; // table->engine_offset = 0; @@ -658,10 +659,20 @@ size_t size_required; // The order we Push all ipfix elements, must corresponde to the structure of the common record // followed by all available extension in the extension map offset = BYTE_OFFSET_first; - PushSequence( table, IPFIX_flowStartMilliseconds, &offset, &table->flow_start); - offset = BYTE_OFFSET_first + 4; - PushSequence( table, IPFIX_flowEndMilliseconds, &offset, &table->flow_end); - offset = BYTE_OFFSET_first + 8; + if ( cache.lookup_info[IPFIX_flowStartDeltaMicroseconds].found ) { + PushSequence( table, IPFIX_flowStartDeltaMicroseconds, &offset, &table->flow_start); + offset = BYTE_OFFSET_first + 4; + PushSequence( table, IPFIX_flowEndDeltaMicroseconds, &offset, &table->flow_end); + offset = BYTE_OFFSET_first + 8; + table->delta_time = 1; + dbg_printf("Time stamp: flow start/end delta microseconds\n"); + } else if ( cache.lookup_info[IPFIX_flowStartMilliseconds].found ) { + PushSequence( table, IPFIX_flowStartMilliseconds, &offset, &table->flow_start); + offset = BYTE_OFFSET_first + 4; + PushSequence( table, IPFIX_flowEndMilliseconds, &offset, &table->flow_end); + offset = BYTE_OFFSET_first + 8; + dbg_printf("Time stamp: flow start/end absolute milliseconds\n"); + } offset +=1; // Skip netflow v9 fwd status PushSequence( table, IPFIX_tcpControlBits, &offset, NULL); PushSequence( table, IPFIX_protocolIdentifier, &offset, NULL); @@ -1133,7 +1144,7 @@ uint16_t Offset = 0; fs->sa_family == PF_INET6 ? "ipv6" : "ipv4", EX_ROUTER_IP_v4); } - // XXX for now, we do not stre router ID in IPFIX + // XXX for now, we do not store router ID in IPFIX extension_descriptor[EX_ROUTER_ID].enabled = 0; /* @@ -1380,7 +1391,7 @@ uint16_t offset_std_sampler_interval, offset_std_sampler_algorithm, found_std_sa } // End of Process_ipfix_option_templates -static inline void Process_ipfix_data(exporter_ipfix_domain_t *exporter, void *data_flowset, FlowSource_t *fs, input_translation_t *table ){ +static inline void Process_ipfix_data(exporter_ipfix_domain_t *exporter, uint32_t ExportTime, void *data_flowset, FlowSource_t *fs, input_translation_t *table ){ uint64_t sampling_rate; uint32_t size_left; uint8_t *in, *out; @@ -1550,6 +1561,11 @@ char *string; { uint64_t DateMiliseconds = Get_val64((void *)&in[input_offset]); *(uint64_t *)stack = DateMiliseconds; + } break; + case TimeDeltaMicro: + { uint64_t DeltaMicroSec = Get_val32((void *)&in[input_offset]); + *(uint64_t *)stack = ((1000000LL * (uint64_t)ExportTime) - DeltaMicroSec) / 1000LL; + } break; case move_mac: /* 64bit access to potentially unaligned output buffer. use 2 x 32bit for _LP64 CPUs */ @@ -1621,15 +1637,15 @@ char *string; // 64bit access to potentially unaligned output buffer. use 2 x 32bit for _LP64 CPUs type_mask_t t; - t.val.val64 = exporter->info.ip.v6[0]; + t.val.val64 = exporter->info.ip.V6[0]; *((uint32_t *)&out[output_offset]) = t.val.val32[0]; *((uint32_t *)&out[output_offset+4]) = t.val.val32[1]; - t.val.val64 = exporter->info.ip.v6[1]; + t.val.val64 = exporter->info.ip.V6[1]; *((uint32_t *)&out[output_offset+8]) = t.val.val32[0]; *((uint32_t *)&out[output_offset+12]) = t.val.val32[1]; } else { - *((uint32_t *)&out[output_offset]) = exporter->info.ip.v4; + *((uint32_t *)&out[output_offset]) = exporter->info.ip.V4; } } @@ -1892,7 +1908,7 @@ static uint32_t packet_cntr = 0; dbg_printf("Process data flowset, length: %u\n", flowset_length); table = GetTranslationTable(exporter, flowset_id); if ( table ) { - Process_ipfix_data(exporter, flowset_header, fs, table); + Process_ipfix_data(exporter, ExportTime, flowset_header, fs, table); exporter->DataRecords++; } else if ( HasOptionTable(fs, flowset_id) ) { Process_ipfix_option_data(exporter, flowset_header, fs); diff --git a/bin/ipfix.h b/bin/ipfix.h index 6c1feed..1b5e7c9 100644 --- a/bin/ipfix.h +++ b/bin/ipfix.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2017, Peter Haag * Copyright (c) 2014, Peter Haag * Copyright (c) 2009, Peter Haag * All rights reserved. @@ -27,12 +28,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * $Author:$ - * - * $Id:$ - * - * $LastChangedRevision:$ - * */ #ifndef _IPFIX_H @@ -260,7 +255,8 @@ typedef struct ipfix_template_elements_e_s { #define IPFIX_packetTotalCount 86 #define IPFIX_flowStartMilliseconds 152 #define IPFIX_flowEndMilliseconds 153 -// reserved 89 +#define IPFIX_flowStartDeltaMicroseconds 158 +#define IPFIX_flowEndDeltaMicroseconds 159 /* prototypes */ int Init_IPFIX(void); diff --git a/bin/netflow_v1.c b/bin/netflow_v1.c index 2d18f5c..e6b8429 100644 --- a/bin/netflow_v1.c +++ b/bin/netflow_v1.c @@ -177,7 +177,7 @@ char ipstr[IP_STRING_LEN]; // search the appropriate exporter engine while ( *e ) { if ( (*e)->info.version == version && - (*e)->info.ip.v6[0] == fs->ip.v6[0] && (*e)->info.ip.v6[1] == fs->ip.v6[1]) + (*e)->info.ip.V6[0] == fs->ip.V6[0] && (*e)->info.ip.V6[1] == fs->ip.V6[1]) return *e; e = &((*e)->next); } @@ -223,12 +223,12 @@ char ipstr[IP_STRING_LEN]; FlushInfoExporter(fs, &((*e)->info)); if ( fs->sa_family == AF_INET ) { - uint32_t _ip = htonl(fs->ip.v4); + uint32_t _ip = htonl(fs->ip.V4); inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr)); } else if ( fs->sa_family == AF_INET6 ) { uint64_t _ip[2]; - _ip[0] = htonll(fs->ip.v6[0]); - _ip[1] = htonll(fs->ip.v6[1]); + _ip[0] = htonll(fs->ip.V6[0]); + _ip[1] = htonll(fs->ip.V6[1]); inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr)); } else { strncpy(ipstr, "", IP_STRING_LEN); @@ -364,7 +364,7 @@ char *string; } break; case EX_ROUTER_IP_v4: { // IPv4 router address tpl_ext_23_t *tpl = (tpl_ext_23_t *)data_ptr; - tpl->router_ip = fs->ip.v4; + tpl->router_ip = fs->ip.V4; data_ptr = (void *)tpl->data; ClearFlag(common_record->flags, FLAG_IPV6_EXP); } break; diff --git a/bin/netflow_v5_v7.c b/bin/netflow_v5_v7.c index 779ac70..0ea9739 100644 --- a/bin/netflow_v5_v7.c +++ b/bin/netflow_v5_v7.c @@ -192,7 +192,7 @@ char ipstr[IP_STRING_LEN]; // search the appropriate exporter engine while ( *e ) { if ( (*e)->info.version == version && (*e)->info.id == engine_tag && - (*e)->info.ip.v6[0] == fs->ip.v6[0] && (*e)->info.ip.v6[1] == fs->ip.v6[1]) + (*e)->info.ip.V6[0] == fs->ip.V6[0] && (*e)->info.ip.V6[1] == fs->ip.V6[1]) return *e; e = &((*e)->next); } @@ -258,12 +258,12 @@ char ipstr[IP_STRING_LEN]; FlushInfoSampler(fs, &(sampler->info)); if ( fs->sa_family == AF_INET ) { - uint32_t _ip = htonl(fs->ip.v4); + uint32_t _ip = htonl(fs->ip.V4); inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr)); } else if ( fs->sa_family == AF_INET6 ) { uint64_t _ip[2]; - _ip[0] = htonll(fs->ip.v6[0]); - _ip[1] = htonll(fs->ip.v6[1]); + _ip[0] = htonll(fs->ip.V6[0]); + _ip[1] = htonll(fs->ip.V6[1]); inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr)); } else { strncpy(ipstr, "", IP_STRING_LEN); @@ -493,7 +493,7 @@ char *string; } break; case EX_ROUTER_IP_v4: { // IPv4 router address tpl_ext_23_t *tpl = (tpl_ext_23_t *)data_ptr; - tpl->router_ip = fs->ip.v4; + tpl->router_ip = fs->ip.V4; data_ptr = (void *)tpl->data; ClearFlag(common_record->flags, FLAG_IPV6_EXP); } break; @@ -707,8 +707,8 @@ uint32_t i, id, t1, t2; v5_output_record->First = htonl(t1); v5_output_record->Last = htonl(t2); - v5_output_record->srcaddr = htonl(master_record->v4.srcaddr); - v5_output_record->dstaddr = htonl(master_record->v4.dstaddr); + v5_output_record->srcaddr = htonl(master_record->V4.srcaddr); + v5_output_record->dstaddr = htonl(master_record->V4.dstaddr); v5_output_record->srcport = htons(master_record->srcport); v5_output_record->dstport = htons(master_record->dstport); @@ -746,7 +746,7 @@ uint32_t i, id, t1, t2; v5_output_record->dst_mask = master_record->dst_mask; break; case EX_NEXT_HOP_v4: - v5_output_record->nexthop = htonl(master_record->ip_nexthop.v4); + v5_output_record->nexthop = htonl(master_record->ip_nexthop.V4); break; // default: Other extensions can not be sent with v5 } diff --git a/bin/netflow_v9.c b/bin/netflow_v9.c index be96590..f49587f 100644 --- a/bin/netflow_v9.c +++ b/bin/netflow_v9.c @@ -475,18 +475,18 @@ exporter_v9_domain_t **e = (exporter_v9_domain_t **)&(fs->exporter_data); while ( *e ) { if ( (*e)->info.id == exporter_id && (*e)->info.version == 9 && - (*e)->info.ip.v6[0] == fs->ip.v6[0] && (*e)->info.ip.v6[1] == fs->ip.v6[1]) + (*e)->info.ip.V6[0] == fs->ip.V6[0] && (*e)->info.ip.V6[1] == fs->ip.V6[1]) return *e; e = &((*e)->next); } if ( fs->sa_family == AF_INET ) { - uint32_t _ip = htonl(fs->ip.v4); + uint32_t _ip = htonl(fs->ip.V4); inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr)); } else if ( fs->sa_family == AF_INET6 ) { uint64_t _ip[2]; - _ip[0] = htonll(fs->ip.v6[0]); - _ip[1] = htonll(fs->ip.v6[1]); + _ip[0] = htonll(fs->ip.V6[0]); + _ip[1] = htonll(fs->ip.V6[1]); inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr)); } else { strncpy(ipstr, "", IP_STRING_LEN); @@ -1845,15 +1845,15 @@ char *string; /* 64bit access to potentially unaligned output buffer. use 2 x 32bit for _LP64 CPUs */ type_mask_t t; - t.val.val64 = exporter->info.ip.v6[0]; + t.val.val64 = exporter->info.ip.V6[0]; *((uint32_t *)&out[output_offset]) = t.val.val32[0]; *((uint32_t *)&out[output_offset+4]) = t.val.val32[1]; - t.val.val64 = exporter->info.ip.v6[1]; + t.val.val64 = exporter->info.ip.V6[1]; *((uint32_t *)&out[output_offset+8]) = t.val.val32[0]; *((uint32_t *)&out[output_offset+12]) = t.val.val32[1]; } else { - *((uint32_t *)&out[output_offset]) = exporter->info.ip.v4; + *((uint32_t *)&out[output_offset]) = exporter->info.ip.V4; } } @@ -2626,18 +2626,18 @@ uint16_t icmp; // IP address info if ((master_record->flags & FLAG_IPV6_ADDR) != 0 ) { // IPv6 - master_record->v6.srcaddr[0] = htonll(master_record->v6.srcaddr[0]); - master_record->v6.srcaddr[1] = htonll(master_record->v6.srcaddr[1]); - master_record->v6.dstaddr[0] = htonll(master_record->v6.dstaddr[0]); - master_record->v6.dstaddr[1] = htonll(master_record->v6.dstaddr[1]); + master_record->V6.srcaddr[0] = htonll(master_record->V6.srcaddr[0]); + master_record->V6.srcaddr[1] = htonll(master_record->V6.srcaddr[1]); + master_record->V6.dstaddr[0] = htonll(master_record->V6.dstaddr[0]); + master_record->V6.dstaddr[1] = htonll(master_record->V6.dstaddr[1]); // keep compiler happy - // memcpy(peer->buff_ptr, master_record->v6.srcaddr, 4 * sizeof(uint64_t)); + // memcpy(peer->buff_ptr, master_record->V6.srcaddr, 4 * sizeof(uint64_t)); memcpy(peer->buff_ptr, master_record->ip_union._ip_64.addr, 4 * sizeof(uint64_t)); peer->buff_ptr = (void *)((pointer_addr_t)peer->buff_ptr + 4 * sizeof(uint64_t)); } else { - Put_val32(htonl(master_record->v4.srcaddr), peer->buff_ptr); + Put_val32(htonl(master_record->V4.srcaddr), peer->buff_ptr); peer->buff_ptr = (void *)((pointer_addr_t)peer->buff_ptr + sizeof(uint32_t)); - Put_val32(htonl(master_record->v4.dstaddr), peer->buff_ptr); + Put_val32(htonl(master_record->V4.dstaddr), peer->buff_ptr); peer->buff_ptr = (void *)((pointer_addr_t)peer->buff_ptr + sizeof(uint32_t)); } @@ -2712,23 +2712,23 @@ uint16_t icmp; peer->buff_ptr = (void *)tpl->data; } break; case EX_NEXT_HOP_v4: - Put_val32(htonl(master_record->ip_nexthop.v4), peer->buff_ptr); + Put_val32(htonl(master_record->ip_nexthop.V4), peer->buff_ptr); peer->buff_ptr = (void *)((pointer_addr_t)peer->buff_ptr + sizeof(uint32_t)); break; case EX_NEXT_HOP_v6: - Put_val64(htonll(master_record->ip_nexthop.v6[0]), peer->buff_ptr); + Put_val64(htonll(master_record->ip_nexthop.V6[0]), peer->buff_ptr); peer->buff_ptr = (void *)((pointer_addr_t)peer->buff_ptr + sizeof(uint64_t)); - Put_val64(htonll(master_record->ip_nexthop.v6[1]), peer->buff_ptr); + Put_val64(htonll(master_record->ip_nexthop.V6[1]), peer->buff_ptr); peer->buff_ptr = (void *)((pointer_addr_t)peer->buff_ptr + sizeof(uint64_t)); break; case EX_NEXT_HOP_BGP_v4: - Put_val32(htonl(master_record->bgp_nexthop.v4), peer->buff_ptr); + Put_val32(htonl(master_record->bgp_nexthop.V4), peer->buff_ptr); peer->buff_ptr = (void *)((pointer_addr_t)peer->buff_ptr + sizeof(uint32_t)); break; case EX_NEXT_HOP_BGP_v6: - Put_val64(htonll(master_record->bgp_nexthop.v6[0]), peer->buff_ptr); + Put_val64(htonll(master_record->bgp_nexthop.V6[0]), peer->buff_ptr); peer->buff_ptr = (void *)((pointer_addr_t)peer->buff_ptr + sizeof(uint64_t)); - Put_val64(htonll(master_record->bgp_nexthop.v6[1]), peer->buff_ptr); + Put_val64(htonll(master_record->bgp_nexthop.V6[1]), peer->buff_ptr); peer->buff_ptr = (void *)((pointer_addr_t)peer->buff_ptr + sizeof(uint64_t)); break; case EX_VLAN: diff --git a/bin/nf_common.c b/bin/nf_common.c index 4793f90..fbecd31 100644 --- a/bin/nf_common.c +++ b/bin/nf_common.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2017, Peter Haag * Copyright (c) 2016, Peter Haag * Copyright (c) 2014, Peter Haag * Copyright (c) 2009, Peter Haag @@ -29,7 +30,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * */ #include "config.h" @@ -684,16 +684,16 @@ extension_map_t *extension_map = r->map_ref; uint64_t dnet[2]; // remember IPs for network - snet[0] = r->v6.srcaddr[0]; - snet[1] = r->v6.srcaddr[1]; - dnet[0] = r->v6.dstaddr[0]; - dnet[1] = r->v6.dstaddr[1]; - r->v6.srcaddr[0] = htonll(r->v6.srcaddr[0]); - r->v6.srcaddr[1] = htonll(r->v6.srcaddr[1]); - r->v6.dstaddr[0] = htonll(r->v6.dstaddr[0]); - r->v6.dstaddr[1] = htonll(r->v6.dstaddr[1]); - inet_ntop(AF_INET6, r->v6.srcaddr, as, sizeof(as)); - inet_ntop(AF_INET6, r->v6.dstaddr, ds, sizeof(ds)); + snet[0] = r->V6.srcaddr[0]; + snet[1] = r->V6.srcaddr[1]; + dnet[0] = r->V6.dstaddr[0]; + dnet[1] = r->V6.dstaddr[1]; + r->V6.srcaddr[0] = htonll(r->V6.srcaddr[0]); + r->V6.srcaddr[1] = htonll(r->V6.srcaddr[1]); + r->V6.dstaddr[0] = htonll(r->V6.dstaddr[0]); + r->V6.dstaddr[1] = htonll(r->V6.dstaddr[1]); + inet_ntop(AF_INET6, r->V6.srcaddr, as, sizeof(as)); + inet_ntop(AF_INET6, r->V6.dstaddr, ds, sizeof(ds)); if ( ! long_v6 ) { condense_v6(as); condense_v6(ds); @@ -730,12 +730,12 @@ extension_map_t *extension_map = r->map_ref; } else { // IPv4 uint32_t snet, dnet; - snet = r->v4.srcaddr; - dnet = r->v4.dstaddr; - r->v4.srcaddr = htonl(r->v4.srcaddr); - r->v4.dstaddr = htonl(r->v4.dstaddr); - inet_ntop(AF_INET, &r->v4.srcaddr, as, sizeof(as)); - inet_ntop(AF_INET, &r->v4.dstaddr, ds, sizeof(ds)); + snet = r->V4.srcaddr; + dnet = r->V4.dstaddr; + r->V4.srcaddr = htonl(r->V4.srcaddr); + r->V4.dstaddr = htonl(r->V4.dstaddr); + inet_ntop(AF_INET, &r->V4.srcaddr, as, sizeof(as)); + inet_ntop(AF_INET, &r->V4.dstaddr, ds, sizeof(ds)); if ( r->src_mask || r->dst_mask) { snet &= 0xffffffffL << ( 32 - r->src_mask ); snet = htonl(snet); @@ -866,8 +866,8 @@ extension_map_t *extension_map = r->map_ref; break; case EX_NEXT_HOP_v4: as[0] = 0; - r->ip_nexthop.v4 = htonl(r->ip_nexthop.v4); - inet_ntop(AF_INET, &r->ip_nexthop.v4, as, sizeof(as)); + r->ip_nexthop.V4 = htonl(r->ip_nexthop.V4); + inet_ntop(AF_INET, &r->ip_nexthop.V4, as, sizeof(as)); as[IP_STRING_LEN-1] = 0; snprintf(_s, slen-1, @@ -880,9 +880,9 @@ extension_map_t *extension_map = r->map_ref; break; case EX_NEXT_HOP_v6: as[0] = 0; - r->ip_nexthop.v6[0] = htonll(r->ip_nexthop.v6[0]); - r->ip_nexthop.v6[1] = htonll(r->ip_nexthop.v6[1]); - inet_ntop(AF_INET6, r->ip_nexthop.v6, as, sizeof(as)); + r->ip_nexthop.V6[0] = htonll(r->ip_nexthop.V6[0]); + r->ip_nexthop.V6[1] = htonll(r->ip_nexthop.V6[1]); + inet_ntop(AF_INET6, r->ip_nexthop.V6, as, sizeof(as)); if ( ! long_v6 ) { condense_v6(as); condense_v6(ds); @@ -898,8 +898,8 @@ extension_map_t *extension_map = r->map_ref; break; case EX_NEXT_HOP_BGP_v4: as[0] = 0; - r->bgp_nexthop.v4 = htonl(r->bgp_nexthop.v4); - inet_ntop(AF_INET, &r->bgp_nexthop.v4, as, sizeof(as)); + r->bgp_nexthop.V4 = htonl(r->bgp_nexthop.V4); + inet_ntop(AF_INET, &r->bgp_nexthop.V4, as, sizeof(as)); as[IP_STRING_LEN-1] = 0; snprintf(_s, slen-1, @@ -912,9 +912,9 @@ extension_map_t *extension_map = r->map_ref; break; case EX_NEXT_HOP_BGP_v6: as[0] = 0; - r->bgp_nexthop.v6[0] = htonll(r->bgp_nexthop.v6[0]); - r->bgp_nexthop.v6[1] = htonll(r->bgp_nexthop.v6[1]); - inet_ntop(AF_INET6, r->ip_nexthop.v6, as, sizeof(as)); + r->bgp_nexthop.V6[0] = htonll(r->bgp_nexthop.V6[0]); + r->bgp_nexthop.V6[1] = htonll(r->bgp_nexthop.V6[1]); + inet_ntop(AF_INET6, r->ip_nexthop.V6, as, sizeof(as)); if ( ! long_v6 ) { condense_v6(as); condense_v6(ds); @@ -1015,8 +1015,8 @@ extension_map_t *extension_map = r->map_ref; } break; case EX_ROUTER_IP_v4: as[0] = 0; - r->ip_router.v4 = htonl(r->ip_router.v4); - inet_ntop(AF_INET, &r->ip_router.v4, as, sizeof(as)); + r->ip_router.V4 = htonl(r->ip_router.V4); + inet_ntop(AF_INET, &r->ip_router.V4, as, sizeof(as)); as[IP_STRING_LEN-1] = 0; snprintf(_s, slen-1, @@ -1029,9 +1029,9 @@ extension_map_t *extension_map = r->map_ref; break; case EX_ROUTER_IP_v6: as[0] = 0; - r->ip_router.v6[0] = htonll(r->ip_router.v6[0]); - r->ip_router.v6[1] = htonll(r->ip_router.v6[1]); - inet_ntop(AF_INET6, &r->ip_router.v6, as, sizeof(as)); + r->ip_router.V6[0] = htonll(r->ip_router.V6[0]); + r->ip_router.V6[1] = htonll(r->ip_router.V6[1]); + inet_ntop(AF_INET6, &r->ip_router.V6, as, sizeof(as)); if ( ! long_v6 ) { condense_v6(as); } @@ -1223,15 +1223,15 @@ master_record_t *r = (master_record_t *)record; } // Make sure Endian does not screw us up - sa[0] = ( r->v6.srcaddr[0] >> 32 ) & 0xffffffffLL; - sa[1] = r->v6.srcaddr[0] & 0xffffffffLL; - sa[2] = ( r->v6.srcaddr[1] >> 32 ) & 0xffffffffLL; - sa[3] = r->v6.srcaddr[1] & 0xffffffffLL; + sa[0] = ( r->V6.srcaddr[0] >> 32 ) & 0xffffffffLL; + sa[1] = r->V6.srcaddr[0] & 0xffffffffLL; + sa[2] = ( r->V6.srcaddr[1] >> 32 ) & 0xffffffffLL; + sa[3] = r->V6.srcaddr[1] & 0xffffffffLL; - da[0] = ( r->v6.dstaddr[0] >> 32 ) & 0xffffffffLL; - da[1] = r->v6.dstaddr[0] & 0xffffffffLL; - da[2] = ( r->v6.dstaddr[1] >> 32 ) & 0xffffffffLL; - da[3] = r->v6.dstaddr[1] & 0xffffffffLL; + da[0] = ( r->V6.dstaddr[0] >> 32 ) & 0xffffffffLL; + da[1] = r->V6.dstaddr[0] & 0xffffffffLL; + da[2] = ( r->V6.dstaddr[1] >> 32 ) & 0xffffffffLL; + da[3] = r->V6.dstaddr[1] & 0xffffffffLL; snprintf(data_string, STRINGSIZE-1 ,"%i|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%llu|%llu", af, r->first, r->msec_first ,r->last, r->msec_last, r->prot, @@ -1261,16 +1261,16 @@ master_record_t *r = (master_record_t *)record; uint64_t dnet[2]; // remember IPs for network - snet[0] = r->v6.srcaddr[0]; - snet[1] = r->v6.srcaddr[1]; - dnet[0] = r->v6.dstaddr[0]; - dnet[1] = r->v6.dstaddr[1]; - r->v6.srcaddr[0] = htonll(r->v6.srcaddr[0]); - r->v6.srcaddr[1] = htonll(r->v6.srcaddr[1]); - r->v6.dstaddr[0] = htonll(r->v6.dstaddr[0]); - r->v6.dstaddr[1] = htonll(r->v6.dstaddr[1]); - inet_ntop(AF_INET6, r->v6.srcaddr, as, sizeof(as)); - inet_ntop(AF_INET6, r->v6.dstaddr, ds, sizeof(ds)); + snet[0] = r->V6.srcaddr[0]; + snet[1] = r->V6.srcaddr[1]; + dnet[0] = r->V6.dstaddr[0]; + dnet[1] = r->V6.dstaddr[1]; + r->V6.srcaddr[0] = htonll(r->V6.srcaddr[0]); + r->V6.srcaddr[1] = htonll(r->V6.srcaddr[1]); + r->V6.dstaddr[0] = htonll(r->V6.dstaddr[0]); + r->V6.dstaddr[1] = htonll(r->V6.dstaddr[1]); + inet_ntop(AF_INET6, r->V6.srcaddr, as, sizeof(as)); + inet_ntop(AF_INET6, r->V6.dstaddr, ds, sizeof(ds)); if ( r->src_mask || r->dst_mask) { if ( r->src_mask > 64 ) @@ -1300,12 +1300,12 @@ master_record_t *r = (master_record_t *)record; } else { // IPv4 uint32_t snet, dnet; - snet = r->v4.srcaddr; - dnet = r->v4.dstaddr; - r->v4.srcaddr = htonl(r->v4.srcaddr); - r->v4.dstaddr = htonl(r->v4.dstaddr); - inet_ntop(AF_INET, &r->v4.srcaddr, as, sizeof(as)); - inet_ntop(AF_INET, &r->v4.dstaddr, ds, sizeof(ds)); + snet = r->V4.srcaddr; + dnet = r->V4.dstaddr; + r->V4.srcaddr = htonl(r->V4.srcaddr); + r->V4.dstaddr = htonl(r->V4.dstaddr); + inet_ntop(AF_INET, &r->V4.srcaddr, as, sizeof(as)); + inet_ntop(AF_INET, &r->V4.dstaddr, ds, sizeof(ds)); if ( r->src_mask || r->dst_mask) { snet &= 0xffffffffL << ( 32 - r->src_mask ); snet = htonl(snet); @@ -1384,9 +1384,9 @@ master_record_t *r = (master_record_t *)record; if ( (r->flags & FLAG_IPV6_NH ) != 0 ) { // IPv6 // EX_NEXT_HOP_v6: as[0] = 0; - r->ip_nexthop.v6[0] = htonll(r->ip_nexthop.v6[0]); - r->ip_nexthop.v6[1] = htonll(r->ip_nexthop.v6[1]); - inet_ntop(AF_INET6, r->ip_nexthop.v6, as, sizeof(as)); + r->ip_nexthop.V6[0] = htonll(r->ip_nexthop.V6[0]); + r->ip_nexthop.V6[1] = htonll(r->ip_nexthop.V6[1]); + inet_ntop(AF_INET6, r->ip_nexthop.V6, as, sizeof(as)); as[IP_STRING_LEN-1] = 0; snprintf(_s, slen-1, ",%s", as); @@ -1397,8 +1397,8 @@ master_record_t *r = (master_record_t *)record; } else { // EX_NEXT_HOP_v4: as[0] = 0; - r->ip_nexthop.v4 = htonl(r->ip_nexthop.v4); - inet_ntop(AF_INET, &r->ip_nexthop.v4, as, sizeof(as)); + r->ip_nexthop.V4 = htonl(r->ip_nexthop.V4); + inet_ntop(AF_INET, &r->ip_nexthop.V4, as, sizeof(as)); as[IP_STRING_LEN-1] = 0; snprintf(_s, slen-1, ",%s", as); @@ -1410,9 +1410,9 @@ master_record_t *r = (master_record_t *)record; if ( (r->flags & FLAG_IPV6_NH ) != 0 ) { // IPv6 // EX_NEXT_HOP_BGP_v6: as[0] = 0; - r->bgp_nexthop.v6[0] = htonll(r->bgp_nexthop.v6[0]); - r->bgp_nexthop.v6[1] = htonll(r->bgp_nexthop.v6[1]); - inet_ntop(AF_INET6, r->ip_nexthop.v6, as, sizeof(as)); + r->bgp_nexthop.V6[0] = htonll(r->bgp_nexthop.V6[0]); + r->bgp_nexthop.V6[1] = htonll(r->bgp_nexthop.V6[1]); + inet_ntop(AF_INET6, r->ip_nexthop.V6, as, sizeof(as)); as[IP_STRING_LEN-1] = 0; snprintf(_s, slen-1, ",%s", as); @@ -1423,8 +1423,8 @@ master_record_t *r = (master_record_t *)record; } else { // EX_NEXT_HOP_BGP_v4: as[0] = 0; - r->bgp_nexthop.v4 = htonl(r->bgp_nexthop.v4); - inet_ntop(AF_INET, &r->bgp_nexthop.v4, as, sizeof(as)); + r->bgp_nexthop.V4 = htonl(r->bgp_nexthop.V4); + inet_ntop(AF_INET, &r->bgp_nexthop.V4, as, sizeof(as)); as[IP_STRING_LEN-1] = 0; snprintf(_s, slen-1, ",%s", as); @@ -1519,9 +1519,9 @@ master_record_t *r = (master_record_t *)record; if ( (r->flags & FLAG_IPV6_EXP ) != 0 ) { // IPv6 // EX_NEXT_HOP_v6: as[0] = 0; - r->ip_router.v6[0] = htonll(r->ip_router.v6[0]); - r->ip_router.v6[1] = htonll(r->ip_router.v6[1]); - inet_ntop(AF_INET6, r->ip_router.v6, as, sizeof(as)); + r->ip_router.V6[0] = htonll(r->ip_router.V6[0]); + r->ip_router.V6[1] = htonll(r->ip_router.V6[1]); + inet_ntop(AF_INET6, r->ip_router.V6, as, sizeof(as)); as[IP_STRING_LEN-1] = 0; snprintf(_s, slen-1, ",%s", as); @@ -1532,8 +1532,8 @@ master_record_t *r = (master_record_t *)record; } else { // EX_NEXT_HOP_v4: as[0] = 0; - r->ip_router.v4 = htonl(r->ip_router.v4); - inet_ntop(AF_INET, &r->ip_router.v4, as, sizeof(as)); + r->ip_router.V4 = htonl(r->ip_router.V4); + inet_ntop(AF_INET, &r->ip_router.V4, as, sizeof(as)); as[IP_STRING_LEN-1] = 0; snprintf(_s, slen-1, ",%s", as); @@ -1927,15 +1927,15 @@ char tmp_str[IP_STRING_LEN]; if ( (r->flags & FLAG_IPV6_ADDR ) != 0 ) { // IPv6 uint64_t ip[2]; - ip[0] = htonll(r->v6.srcaddr[0]); - ip[1] = htonll(r->v6.srcaddr[1]); + ip[0] = htonll(r->V6.srcaddr[0]); + ip[1] = htonll(r->V6.srcaddr[1]); inet_ntop(AF_INET6, ip, tmp_str, sizeof(tmp_str)); if ( ! long_v6 ) { condense_v6(tmp_str); } } else { // IPv4 uint32_t ip; - ip = htonl(r->v4.srcaddr); + ip = htonl(r->V4.srcaddr); inet_ntop(AF_INET, &ip, tmp_str, sizeof(tmp_str)); } tmp_str[IP_STRING_LEN-1] = 0; @@ -1956,8 +1956,8 @@ char tmp_str[IP_STRING_LEN], portchar; if ( (r->flags & FLAG_IPV6_ADDR ) != 0 ) { // IPv6 uint64_t ip[2]; - ip[0] = htonll(r->v6.srcaddr[0]); - ip[1] = htonll(r->v6.srcaddr[1]); + ip[0] = htonll(r->V6.srcaddr[0]); + ip[1] = htonll(r->V6.srcaddr[1]); inet_ntop(AF_INET6, ip, tmp_str, sizeof(tmp_str)); if ( ! long_v6 ) { condense_v6(tmp_str); @@ -1965,7 +1965,7 @@ char tmp_str[IP_STRING_LEN], portchar; portchar = '.'; } else { // IPv4 uint32_t ip; - ip = htonl(r->v4.srcaddr); + ip = htonl(r->V4.srcaddr); inet_ntop(AF_INET, &ip, tmp_str, sizeof(tmp_str)); portchar = ':'; } @@ -1987,15 +1987,15 @@ char tmp_str[IP_STRING_LEN]; if ( (r->flags & FLAG_IPV6_ADDR ) != 0 ) { // IPv6 uint64_t ip[2]; - ip[0] = htonll(r->v6.dstaddr[0]); - ip[1] = htonll(r->v6.dstaddr[1]); + ip[0] = htonll(r->V6.dstaddr[0]); + ip[1] = htonll(r->V6.dstaddr[1]); inet_ntop(AF_INET6, ip, tmp_str, sizeof(tmp_str)); if ( ! long_v6 ) { condense_v6(tmp_str); } } else { // IPv4 uint32_t ip; - ip = htonl(r->v4.dstaddr); + ip = htonl(r->V4.dstaddr); inet_ntop(AF_INET, &ip, tmp_str, sizeof(tmp_str)); } tmp_str[IP_STRING_LEN-1] = 0; @@ -2017,15 +2017,15 @@ char tmp_str[IP_STRING_LEN]; if ( (r->flags & FLAG_IPV6_NH ) != 0 ) { // IPv6 uint64_t ip[2]; - ip[0] = htonll(r->ip_nexthop.v6[0]); - ip[1] = htonll(r->ip_nexthop.v6[1]); + ip[0] = htonll(r->ip_nexthop.V6[0]); + ip[1] = htonll(r->ip_nexthop.V6[1]); inet_ntop(AF_INET6, ip, tmp_str, sizeof(tmp_str)); if ( ! long_v6 ) { condense_v6(tmp_str); } } else { // IPv4 uint32_t ip; - ip = htonl(r->ip_nexthop.v4); + ip = htonl(r->ip_nexthop.V4); inet_ntop(AF_INET, &ip, tmp_str, sizeof(tmp_str)); } tmp_str[IP_STRING_LEN-1] = 0; @@ -2046,15 +2046,15 @@ char tmp_str[IP_STRING_LEN]; if ( (r->flags & FLAG_IPV6_NH ) != 0 ) { // IPv6 uint64_t ip[2]; - ip[0] = htonll(r->bgp_nexthop.v6[0]); - ip[1] = htonll(r->bgp_nexthop.v6[1]); + ip[0] = htonll(r->bgp_nexthop.V6[0]); + ip[1] = htonll(r->bgp_nexthop.V6[1]); inet_ntop(AF_INET6, ip, tmp_str, sizeof(tmp_str)); if ( ! long_v6 ) { condense_v6(tmp_str); } } else { // IPv4 uint32_t ip; - ip = htonl(r->bgp_nexthop.v4); + ip = htonl(r->bgp_nexthop.V4); inet_ntop(AF_INET, &ip, tmp_str, sizeof(tmp_str)); } tmp_str[IP_STRING_LEN-1] = 0; @@ -2075,15 +2075,15 @@ char tmp_str[IP_STRING_LEN]; if ( (r->flags & FLAG_IPV6_EXP ) != 0 ) { // IPv6 uint64_t ip[2]; - ip[0] = htonll(r->ip_router.v6[0]); - ip[1] = htonll(r->ip_router.v6[1]); + ip[0] = htonll(r->ip_router.V6[0]); + ip[1] = htonll(r->ip_router.V6[1]); inet_ntop(AF_INET6, ip, tmp_str, sizeof(tmp_str)); if ( ! long_v6 ) { condense_v6(tmp_str); } } else { // IPv4 uint32_t ip; - ip = htonl(r->ip_router.v4); + ip = htonl(r->ip_router.V4); inet_ntop(AF_INET, &ip, tmp_str, sizeof(tmp_str)); } tmp_str[IP_STRING_LEN-1] = 0; @@ -2106,8 +2106,8 @@ char icmp_port[MAX_STRING_LENGTH]; if ( (r->flags & FLAG_IPV6_ADDR ) != 0 ) { // IPv6 uint64_t ip[2]; - ip[0] = htonll(r->v6.dstaddr[0]); - ip[1] = htonll(r->v6.dstaddr[1]); + ip[0] = htonll(r->V6.dstaddr[0]); + ip[1] = htonll(r->V6.dstaddr[1]); inet_ntop(AF_INET6, ip, tmp_str, sizeof(tmp_str)); if ( ! long_v6 ) { condense_v6(tmp_str); @@ -2115,7 +2115,7 @@ char icmp_port[MAX_STRING_LENGTH]; portchar = '.'; } else { // IPv4 uint32_t ip; - ip = htonl(r->v4.dstaddr); + ip = htonl(r->V4.dstaddr); inet_ntop(AF_INET, &ip, tmp_str, sizeof(tmp_str)); portchar = ':'; } @@ -2140,15 +2140,15 @@ char tmp_str[IP_STRING_LEN]; if ( (r->flags & FLAG_IPV6_ADDR ) != 0 ) { // IPv6 uint64_t ip[2]; - ip[0] = htonll(r->v6.srcaddr[0]); - ip[1] = htonll(r->v6.srcaddr[1]); + ip[0] = htonll(r->V6.srcaddr[0]); + ip[1] = htonll(r->V6.srcaddr[1]); inet_ntop(AF_INET6, ip, tmp_str, sizeof(tmp_str)); if ( ! long_v6 ) { condense_v6(tmp_str); } } else { // IPv4 uint32_t ip; - ip = htonl(r->v4.srcaddr); + ip = htonl(r->V4.srcaddr); inet_ntop(AF_INET, &ip, tmp_str, sizeof(tmp_str)); } tmp_str[IP_STRING_LEN-1] = 0; @@ -2171,15 +2171,15 @@ char tmp_str[IP_STRING_LEN]; if ( (r->flags & FLAG_IPV6_ADDR ) != 0 ) { // IPv6 uint64_t ip[2]; - ip[0] = htonll(r->v6.dstaddr[0]); - ip[1] = htonll(r->v6.dstaddr[1]); + ip[0] = htonll(r->V6.dstaddr[0]); + ip[1] = htonll(r->V6.dstaddr[1]); inet_ntop(AF_INET6, ip, tmp_str, sizeof(tmp_str)); if ( ! long_v6 ) { condense_v6(tmp_str); } } else { // IPv4 uint32_t ip; - ip = htonl(r->v4.dstaddr); + ip = htonl(r->V4.dstaddr); inet_ntop(AF_INET, &ip, tmp_str, sizeof(tmp_str)); } tmp_str[IP_STRING_LEN-1] = 0; @@ -2737,15 +2737,15 @@ char tmp_str[IP_STRING_LEN]; if ( (r->xlate_flags & 1 ) != 0 ) { // IPv6 uint64_t ip[2]; - ip[0] = htonll(r->xlate_src_ip.v6[0]); - ip[1] = htonll(r->xlate_src_ip.v6[1]); + ip[0] = htonll(r->xlate_src_ip.V6[0]); + ip[1] = htonll(r->xlate_src_ip.V6[1]); inet_ntop(AF_INET6, ip, tmp_str, sizeof(tmp_str)); if ( ! long_v6 ) { condense_v6(tmp_str); } } else { // IPv4 uint32_t ip; - ip = htonl(r->xlate_src_ip.v4); + ip = htonl(r->xlate_src_ip.V4); inet_ntop(AF_INET, &ip, tmp_str, sizeof(tmp_str)); } tmp_str[IP_STRING_LEN-1] = 0; @@ -2765,15 +2765,15 @@ char tmp_str[IP_STRING_LEN]; if ( (r->xlate_flags & 1 ) != 0 ) { // IPv6 uint64_t ip[2]; - ip[0] = htonll(r->xlate_dst_ip.v6[0]); - ip[1] = htonll(r->xlate_dst_ip.v6[1]); + ip[0] = htonll(r->xlate_dst_ip.V6[0]); + ip[1] = htonll(r->xlate_dst_ip.V6[1]); inet_ntop(AF_INET6, ip, tmp_str, sizeof(tmp_str)); if ( ! long_v6 ) { condense_v6(tmp_str); } } else { // IPv4 uint32_t ip; - ip = htonl(r->xlate_dst_ip.v4); + ip = htonl(r->xlate_dst_ip.V4); inet_ntop(AF_INET, &ip, tmp_str, sizeof(tmp_str)); } tmp_str[IP_STRING_LEN-1] = 0; @@ -2807,8 +2807,8 @@ char tmp_str[IP_STRING_LEN], portchar; if ( (r->xlate_flags & 1 ) != 0 ) { // IPv6 uint64_t ip[2]; - ip[0] = htonll(r->xlate_src_ip.v6[0]); - ip[1] = htonll(r->xlate_src_ip.v6[1]); + ip[0] = htonll(r->xlate_src_ip.V6[0]); + ip[1] = htonll(r->xlate_src_ip.V6[1]); inet_ntop(AF_INET6, ip, tmp_str, sizeof(tmp_str)); if ( ! long_v6 ) { condense_v6(tmp_str); @@ -2817,7 +2817,7 @@ char tmp_str[IP_STRING_LEN], portchar; portchar = '.'; } else { // IPv4 uint32_t ip; - ip = htonl(r->xlate_src_ip.v4); + ip = htonl(r->xlate_src_ip.V4); inet_ntop(AF_INET, &ip, tmp_str, sizeof(tmp_str)); portchar = ':'; @@ -2850,7 +2850,7 @@ char tmp_str[IP_STRING_LEN], portchar; portchar = '.'; } else { // IPv4 uint32_t ip; - ip = htonl(r->xlate_dst_ip.v4); + ip = htonl(r->xlate_dst_ip.V4); inet_ntop(AF_INET, &ip, tmp_str, sizeof(tmp_str)); portchar = ':'; diff --git a/bin/nfanon.c b/bin/nfanon.c index 98debab..323c2a1 100755 --- a/bin/nfanon.c +++ b/bin/nfanon.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2017, Peter Haag * Copyright (c) 2014, Peter Haag * Copyright (c) 2009, Peter Haag * Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung @@ -28,13 +29,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * $Author: haag $ - * - * $Id:$ - * - * $LastChangedRevision: 48 $ - * - * */ #include "config.h" @@ -106,18 +100,18 @@ int i; if ( (master_record->flags & FLAG_IPV6_ADDR) != 0 ) { // IPv6 // IPv6 uint64_t anon_ip[2]; - anonymize_v6(master_record->v6.srcaddr, anon_ip); - master_record->v6.srcaddr[0] = anon_ip[0]; - master_record->v6.srcaddr[1] = anon_ip[1]; + anonymize_v6(master_record->V6.srcaddr, anon_ip); + master_record->V6.srcaddr[0] = anon_ip[0]; + master_record->V6.srcaddr[1] = anon_ip[1]; - anonymize_v6(master_record->v6.dstaddr, anon_ip); - master_record->v6.dstaddr[0] = anon_ip[0]; - master_record->v6.dstaddr[1] = anon_ip[1]; + anonymize_v6(master_record->V6.dstaddr, anon_ip); + master_record->V6.dstaddr[0] = anon_ip[0]; + master_record->V6.dstaddr[1] = anon_ip[1]; } else { // IPv4 - master_record->v4.srcaddr = anonymize(master_record->v4.srcaddr); - master_record->v4.dstaddr = anonymize(master_record->v4.dstaddr); + master_record->V4.srcaddr = anonymize(master_record->V4.srcaddr); + master_record->V4.dstaddr = anonymize(master_record->V4.dstaddr); } // Process optional extensions @@ -133,45 +127,45 @@ int i; master_record->dstas = 0; break; case EX_NEXT_HOP_v4: - master_record->ip_nexthop.v4 = anonymize(master_record->ip_nexthop.v4); + master_record->ip_nexthop.V4 = anonymize(master_record->ip_nexthop.V4); break; case EX_NEXT_HOP_v6: { uint64_t anon_ip[2]; - anonymize_v6(master_record->ip_nexthop.v6, anon_ip); - master_record->ip_nexthop.v6[0] = anon_ip[0]; - master_record->ip_nexthop.v6[1] = anon_ip[1]; + anonymize_v6(master_record->ip_nexthop.V6, anon_ip); + master_record->ip_nexthop.V6[0] = anon_ip[0]; + master_record->ip_nexthop.V6[1] = anon_ip[1]; } break; case EX_NEXT_HOP_BGP_v4: - master_record->bgp_nexthop.v4 = anonymize(master_record->bgp_nexthop.v4); + master_record->bgp_nexthop.V4 = anonymize(master_record->bgp_nexthop.V4); break; case EX_NEXT_HOP_BGP_v6: { uint64_t anon_ip[2]; - anonymize_v6(master_record->bgp_nexthop.v6, anon_ip); - master_record->bgp_nexthop.v6[0] = anon_ip[0]; - master_record->bgp_nexthop.v6[1] = anon_ip[1]; + anonymize_v6(master_record->bgp_nexthop.V6, anon_ip); + master_record->bgp_nexthop.V6[0] = anon_ip[0]; + master_record->bgp_nexthop.V6[1] = anon_ip[1]; } break; case EX_ROUTER_IP_v4: - master_record->ip_router.v4 = anonymize(master_record->ip_router.v4); + master_record->ip_router.V4 = anonymize(master_record->ip_router.V4); break; case EX_ROUTER_IP_v6: { uint64_t anon_ip[2]; - anonymize_v6(master_record->ip_router.v6, anon_ip); - master_record->ip_router.v6[0] = anon_ip[0]; - master_record->ip_router.v6[1] = anon_ip[1]; + anonymize_v6(master_record->ip_router.V6, anon_ip); + master_record->ip_router.V6[0] = anon_ip[0]; + master_record->ip_router.V6[1] = anon_ip[1]; } break; #ifdef NSEL case EX_NSEL_XLATE_IP_v4: - master_record->xlate_src_ip.v4 = anonymize(master_record->xlate_src_ip.v4); - master_record->xlate_dst_ip.v4 = anonymize(master_record->xlate_dst_ip.v4); + master_record->xlate_src_ip.V4 = anonymize(master_record->xlate_src_ip.V4); + master_record->xlate_dst_ip.V4 = anonymize(master_record->xlate_dst_ip.V4); break; case EX_NSEL_XLATE_IP_v6: { uint64_t anon_ip[2]; - anonymize_v6(master_record->xlate_src_ip.v6, anon_ip); - master_record->xlate_src_ip.v6[0] = anon_ip[0]; - master_record->xlate_src_ip.v6[1] = anon_ip[1]; - anonymize_v6(master_record->xlate_dst_ip.v6, anon_ip); - master_record->xlate_dst_ip.v6[0] = anon_ip[0]; - master_record->xlate_dst_ip.v6[1] = anon_ip[1]; + anonymize_v6(master_record->xlate_src_ip.V6, anon_ip); + master_record->xlate_src_ip.V6[0] = anon_ip[0]; + master_record->xlate_src_ip.V6[1] = anon_ip[1]; + anonymize_v6(master_record->xlate_dst_ip.V6, anon_ip); + master_record->xlate_dst_ip.V6[0] = anon_ip[0]; + master_record->xlate_dst_ip.V6[1] = anon_ip[1]; } break; #endif } diff --git a/bin/nfexport.c b/bin/nfexport.c index cda68b7..87eb196 100755 --- a/bin/nfexport.c +++ b/bin/nfexport.c @@ -29,12 +29,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * $Author: haag $ - * - * $Id: nfexport.c 54 2010-01-29 11:30:22Z haag $ - * - * $LastChangedRevision: 54 $ - * */ #include "config.h" @@ -321,10 +315,10 @@ char *string; // apply IP mask from aggregation, to provide a pretty output if ( FlowTable->has_masks ) { - flow_record->v6.srcaddr[0] &= FlowTable->IPmask[0]; - flow_record->v6.srcaddr[1] &= FlowTable->IPmask[1]; - flow_record->v6.dstaddr[0] &= FlowTable->IPmask[2]; - flow_record->v6.dstaddr[1] &= FlowTable->IPmask[3]; + flow_record->V6.srcaddr[0] &= FlowTable->IPmask[0]; + flow_record->V6.srcaddr[1] &= FlowTable->IPmask[1]; + flow_record->V6.dstaddr[0] &= FlowTable->IPmask[2]; + flow_record->V6.dstaddr[1] &= FlowTable->IPmask[3]; } if ( FlowTable->apply_netbits ) @@ -368,10 +362,10 @@ char *string; // apply IP mask from aggregation, to provide a pretty output if ( FlowTable->has_masks ) { - flow_record->v6.srcaddr[0] &= FlowTable->IPmask[0]; - flow_record->v6.srcaddr[1] &= FlowTable->IPmask[1]; - flow_record->v6.dstaddr[0] &= FlowTable->IPmask[2]; - flow_record->v6.dstaddr[1] &= FlowTable->IPmask[3]; + flow_record->V6.srcaddr[0] &= FlowTable->IPmask[0]; + flow_record->V6.srcaddr[1] &= FlowTable->IPmask[1]; + flow_record->V6.dstaddr[0] &= FlowTable->IPmask[2]; + flow_record->V6.dstaddr[1] &= FlowTable->IPmask[3]; } if ( FlowTable->apply_netbits ) diff --git a/bin/nffile.c b/bin/nffile.c index abb7cf1..1d27fe2 100644 --- a/bin/nffile.c +++ b/bin/nffile.c @@ -1213,19 +1213,19 @@ void *p = (void *)input_record; if ( (input_record->flags & FLAG_IPV6_ADDR) != 0 ) { // IPv6 // IPv6 // keep compiler happy - // memcpy((void *)output_record->v6.srcaddr, p, 4 * sizeof(uint64_t)); + // memcpy((void *)output_record->V6.srcaddr, p, 4 * sizeof(uint64_t)); memcpy((void *)output_record->ip_union._ip_64.addr, p, 4 * sizeof(uint64_t)); p = (void *)((pointer_addr_t)p + 4 * sizeof(uint64_t)); } else { // IPv4 u = (uint32_t *)p; - output_record->v6.srcaddr[0] = 0; - output_record->v6.srcaddr[1] = 0; - output_record->v4.srcaddr = u[0]; + output_record->V6.srcaddr[0] = 0; + output_record->V6.srcaddr[1] = 0; + output_record->V4.srcaddr = u[0]; - output_record->v6.dstaddr[0] = 0; - output_record->v6.dstaddr[1] = 0; - output_record->v4.dstaddr = u[1]; + output_record->V6.dstaddr[0] = 0; + output_record->V6.dstaddr[1] = 0; + output_record->V4.dstaddr = u[1]; p = (void *)((pointer_addr_t)p + 2 * sizeof(uint32_t)); } diff --git a/bin/nffile.h b/bin/nffile.h index 15f1f25..89d1c6f 100644 --- a/bin/nffile.h +++ b/bin/nffile.h @@ -29,12 +29,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * $Author: haag $ - * - * $Id: nffile.h 40 2009-12-16 10:41:44Z haag $ - * - * $LastChangedRevision: 40 $ - * */ #ifndef _NFFILE_H @@ -345,7 +339,7 @@ typedef struct nffile_s { * +----+--------------+--------------+--------------+--------------+--------------+--------------+--------------+--------------+ * | 2 | last (21) |fwd_status(89)| tcpflags (6) | proto (4) | src tos (5) | * +----+--------------+--------------+--------------+--------------+--------------+--------------+--------------+--------------+ - * | 3 | srcport (7) | dstport(11)/ICMP (32) | exporter ID | | + * | 3 | srcport (7) | dstport(11)/ICMP (32) | exporter ID | reserved icmp type/code | * +----+--------------+--------------+--------------+--------------+--------------+--------------+--------------+--------------+ * @@ -494,8 +488,8 @@ typedef struct ip_addr_s { #define IP_ADDR_T } ip_addr_t; -#define v4 ip_union._v4 -#define v6 ip_union._v6 +#define V4 ip_union._v4 +#define V6 ip_union._v6 /* * Extension 2: @@ -1505,7 +1499,6 @@ typedef struct master_record_s { uint16_t icmp; }; - #ifdef WORDS_BIGENDIAN # define OffsetPort 3 # define OffsetExporterSysID 3 diff --git a/bin/nffile_inline.c b/bin/nffile_inline.c index 8401cac..d7c532e 100755 --- a/bin/nffile_inline.c +++ b/bin/nffile_inline.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2017, Peter Haag * Copyright (c) 2016, Peter Haag * Copyright (c) 2014, Peter Haag * Copyright (c) 2009, Peter Haag @@ -134,19 +135,19 @@ void *p = (void *)input_record; if ( (input_record->flags & FLAG_IPV6_ADDR) != 0 ) { // IPv6 // IPv6 // keep compiler happy - // memcpy((void *)output_record->v6.srcaddr, p, 4 * sizeof(uint64_t)); + // memcpy((void *)output_record->V6.srcaddr, p, 4 * sizeof(uint64_t)); memcpy((void *)output_record->ip_union._ip_64.addr, p, 4 * sizeof(uint64_t)); p = (void *)((pointer_addr_t)p + 4 * sizeof(uint64_t)); } else { // IPv4 u = (uint32_t *)p; - output_record->v6.srcaddr[0] = 0; - output_record->v6.srcaddr[1] = 0; - output_record->v4.srcaddr = u[0]; + output_record->V6.srcaddr[0] = 0; + output_record->V6.srcaddr[1] = 0; + output_record->V4.srcaddr = u[0]; - output_record->v6.dstaddr[0] = 0; - output_record->v6.dstaddr[1] = 0; - output_record->v4.dstaddr = u[1]; + output_record->V6.dstaddr[0] = 0; + output_record->V6.dstaddr[1] = 0; + output_record->V4.dstaddr = u[1]; p = (void *)((pointer_addr_t)p + 2 * sizeof(uint32_t)); } @@ -223,29 +224,29 @@ void *p = (void *)input_record; } break; case EX_NEXT_HOP_v4: { tpl_ext_9_t *tpl = (tpl_ext_9_t *)p; - output_record->ip_nexthop.v6[0] = 0; - output_record->ip_nexthop.v6[1] = 0; - output_record->ip_nexthop.v4 = tpl->nexthop; + output_record->ip_nexthop.V6[0] = 0; + output_record->ip_nexthop.V6[1] = 0; + output_record->ip_nexthop.V4 = tpl->nexthop; p = (void *)tpl->data; ClearFlag(output_record->flags, FLAG_IPV6_NH); } break; case EX_NEXT_HOP_v6: { tpl_ext_10_t *tpl = (tpl_ext_10_t *)p; - CopyV6IP((uint32_t *)output_record->ip_nexthop.v6, (uint32_t *)tpl->nexthop); + CopyV6IP((uint32_t *)output_record->ip_nexthop.V6, (uint32_t *)tpl->nexthop); p = (void *)tpl->data; SetFlag(output_record->flags, FLAG_IPV6_NH); } break; case EX_NEXT_HOP_BGP_v4: { tpl_ext_11_t *tpl = (tpl_ext_11_t *)p; - output_record->bgp_nexthop.v6[0] = 0; - output_record->bgp_nexthop.v6[1] = 0; - output_record->bgp_nexthop.v4 = tpl->bgp_nexthop; + output_record->bgp_nexthop.V6[0] = 0; + output_record->bgp_nexthop.V6[1] = 0; + output_record->bgp_nexthop.V4 = tpl->bgp_nexthop; ClearFlag(output_record->flags, FLAG_IPV6_NHB); p = (void *)tpl->data; } break; case EX_NEXT_HOP_BGP_v6: { tpl_ext_12_t *tpl = (tpl_ext_12_t *)p; - CopyV6IP((uint32_t *)output_record->bgp_nexthop.v6, (uint32_t *)tpl->bgp_nexthop); + CopyV6IP((uint32_t *)output_record->bgp_nexthop.V6, (uint32_t *)tpl->bgp_nexthop); p = (void *)tpl->data; SetFlag(output_record->flags, FLAG_IPV6_NHB); } break; @@ -322,15 +323,15 @@ void *p = (void *)input_record; } break; case EX_ROUTER_IP_v4: { tpl_ext_23_t *tpl = (tpl_ext_23_t *)p; - output_record->ip_router.v6[0] = 0; - output_record->ip_router.v6[1] = 0; - output_record->ip_router.v4 = tpl->router_ip; + output_record->ip_router.V6[0] = 0; + output_record->ip_router.V6[1] = 0; + output_record->ip_router.V4 = tpl->router_ip; p = (void *)tpl->data; ClearFlag(output_record->flags, FLAG_IPV6_EXP); } break; case EX_ROUTER_IP_v6: { tpl_ext_24_t *tpl = (tpl_ext_24_t *)p; - CopyV6IP((uint32_t *)output_record->ip_router.v6, (uint32_t *)tpl->router_ip); + CopyV6IP((uint32_t *)output_record->ip_router.V6, (uint32_t *)tpl->router_ip); p = (void *)tpl->data; SetFlag(output_record->flags, FLAG_IPV6_EXP); } break; @@ -383,21 +384,21 @@ void *p = (void *)input_record; } break; case EX_NSEL_XLATE_IP_v4: { tpl_ext_39_t *tpl = (tpl_ext_39_t *)p; - output_record->xlate_src_ip.v6[0] = 0; - output_record->xlate_src_ip.v6[1] = 0; - output_record->xlate_src_ip.v4 = tpl->xlate_src_ip; - output_record->xlate_dst_ip.v6[0] = 0; - output_record->xlate_dst_ip.v6[1] = 0; - output_record->xlate_dst_ip.v4 = tpl->xlate_dst_ip; + output_record->xlate_src_ip.V6[0] = 0; + output_record->xlate_src_ip.V6[1] = 0; + output_record->xlate_src_ip.V4 = tpl->xlate_src_ip; + output_record->xlate_dst_ip.V6[0] = 0; + output_record->xlate_dst_ip.V6[1] = 0; + output_record->xlate_dst_ip.V4 = tpl->xlate_dst_ip; p = (void *)tpl->data; output_record->xlate_flags = 0; } break; case EX_NSEL_XLATE_IP_v6: { tpl_ext_40_t *tpl = (tpl_ext_40_t *)p; - output_record->xlate_src_ip.v6[0] = tpl->xlate_src_ip[0]; - output_record->xlate_src_ip.v6[1] = tpl->xlate_src_ip[1]; - output_record->xlate_dst_ip.v6[0] = tpl->xlate_dst_ip[0]; - output_record->xlate_dst_ip.v6[1] = tpl->xlate_dst_ip[1]; + output_record->xlate_src_ip.V6[0] = tpl->xlate_src_ip[0]; + output_record->xlate_src_ip.V6[1] = tpl->xlate_src_ip[1]; + output_record->xlate_dst_ip.V6[0] = tpl->xlate_dst_ip[0]; + output_record->xlate_dst_ip.V6[1] = tpl->xlate_dst_ip[1]; p = (void *)tpl->data; output_record->xlate_flags = 1; } break; @@ -442,12 +443,12 @@ void *p = (void *)input_record; // compat record v1.6.10 case EX_NEL_GLOBAL_IP_v4: { tpl_ext_47_t *tpl = (tpl_ext_47_t *)p; - output_record->xlate_src_ip.v6[0] = 0; - output_record->xlate_src_ip.v6[1] = 0; - output_record->xlate_src_ip.v4 = tpl->nat_inside; - output_record->xlate_dst_ip.v6[0] = 0; - output_record->xlate_dst_ip.v6[1] = 0; - output_record->xlate_dst_ip.v4 = tpl->nat_outside; + output_record->xlate_src_ip.V6[0] = 0; + output_record->xlate_src_ip.V6[1] = 0; + output_record->xlate_src_ip.V4 = tpl->nat_inside; + output_record->xlate_dst_ip.V6[0] = 0; + output_record->xlate_dst_ip.V6[1] = 0; + output_record->xlate_dst_ip.V4 = tpl->nat_outside; p = (void *)tpl->data; output_record->xlate_src_port = compat_nel_bug.port[0]; @@ -522,14 +523,14 @@ int i; if ( (master_record->flags & FLAG_IPV6_ADDR) != 0 ) { // IPv6 // IPv6 // keep compiler happy - // memcpy(p, (void *)master_record->v6.srcaddr, 4 * sizeof(uint64_t)); + // memcpy(p, (void *)master_record->V6.srcaddr, 4 * sizeof(uint64_t)); memcpy(p, (void *)master_record->ip_union._ip_64.addr, 4 * sizeof(uint64_t)); p = (void *)((pointer_addr_t)p + 4 * sizeof(uint64_t)); } else { // IPv4 uint32_t *u = (uint32_t *)p; - u[0] = master_record->v4.srcaddr; - u[1] = master_record->v4.dstaddr; + u[0] = master_record->V4.srcaddr; + u[1] = master_record->V4.dstaddr; p = (void *)((pointer_addr_t)p + 2 * sizeof(uint32_t)); } @@ -603,24 +604,24 @@ int i; } break; case EX_NEXT_HOP_v4: { tpl_ext_9_t *tpl = (tpl_ext_9_t *)p; - tpl->nexthop = master_record->ip_nexthop.v4; + tpl->nexthop = master_record->ip_nexthop.V4; p = (void *)tpl->data; } break; case EX_NEXT_HOP_v6: { tpl_ext_10_t *tpl = (tpl_ext_10_t *)p; - tpl->nexthop[0] = master_record->ip_nexthop.v6[0]; - tpl->nexthop[1] = master_record->ip_nexthop.v6[1]; + tpl->nexthop[0] = master_record->ip_nexthop.V6[0]; + tpl->nexthop[1] = master_record->ip_nexthop.V6[1]; p = (void *)tpl->data; } break; case EX_NEXT_HOP_BGP_v4: { tpl_ext_11_t *tpl = (tpl_ext_11_t *)p; - tpl->bgp_nexthop = master_record->bgp_nexthop.v4; + tpl->bgp_nexthop = master_record->bgp_nexthop.V4; p = (void *)tpl->data; } break; case EX_NEXT_HOP_BGP_v6: { tpl_ext_12_t *tpl = (tpl_ext_12_t *)p; - tpl->bgp_nexthop[0] = master_record->bgp_nexthop.v6[0]; - tpl->bgp_nexthop[1] = master_record->bgp_nexthop.v6[1]; + tpl->bgp_nexthop[0] = master_record->bgp_nexthop.V6[0]; + tpl->bgp_nexthop[1] = master_record->bgp_nexthop.V6[1]; p = (void *)tpl->data; } break; case EX_VLAN: { @@ -695,13 +696,13 @@ int i; } break; case EX_ROUTER_IP_v4: { tpl_ext_23_t *tpl = (tpl_ext_23_t *)p; - tpl->router_ip = master_record->ip_router.v4; + tpl->router_ip = master_record->ip_router.V4; p = (void *)tpl->data; } break; case EX_ROUTER_IP_v6: { tpl_ext_24_t *tpl = (tpl_ext_24_t *)p; - tpl->router_ip[0] = master_record->ip_router.v6[0]; - tpl->router_ip[1] = master_record->ip_router.v6[1]; + tpl->router_ip[0] = master_record->ip_router.V6[0]; + tpl->router_ip[1] = master_record->ip_router.V6[1]; p = (void *)tpl->data; } break; case EX_ROUTER_ID: { @@ -741,17 +742,17 @@ int i; } break; case EX_NSEL_XLATE_IP_v4: { tpl_ext_39_t *tpl = (tpl_ext_39_t *)p; - tpl->xlate_src_ip = master_record->xlate_src_ip.v4; - tpl->xlate_dst_ip = master_record->xlate_dst_ip.v4; + tpl->xlate_src_ip = master_record->xlate_src_ip.V4; + tpl->xlate_dst_ip = master_record->xlate_dst_ip.V4; p = (void *)tpl->data; } break; case EX_NSEL_XLATE_IP_v6: { tpl_ext_40_t *tpl = (tpl_ext_40_t *)p; - tpl->xlate_src_ip[0] = master_record->xlate_src_ip.v6[0]; - tpl->xlate_src_ip[1] = master_record->xlate_src_ip.v6[1]; + tpl->xlate_src_ip[0] = master_record->xlate_src_ip.V6[0]; + tpl->xlate_src_ip[1] = master_record->xlate_src_ip.V6[1]; p = (void *)tpl->data; - tpl->xlate_dst_ip[0] = master_record->xlate_dst_ip.v6[0]; - tpl->xlate_dst_ip[1] = master_record->xlate_dst_ip.v6[1]; + tpl->xlate_dst_ip[0] = master_record->xlate_dst_ip.V6[0]; + tpl->xlate_dst_ip[1] = master_record->xlate_dst_ip.V6[1]; p = (void *)tpl->data; } break; case EX_NSEL_ACL: { diff --git a/bin/nfgen.c b/bin/nfgen.c index bc37ea3..0b174ce 100644 --- a/bin/nfgen.c +++ b/bin/nfgen.c @@ -96,18 +96,18 @@ static void SetIPaddress(master_record_t *record, int af, char *src_ip, char *d if ( af == PF_INET6 ) { SetFlag(record->flags, FLAG_IPV6_ADDR); - inet_pton(PF_INET6, src_ip, &(record->v6.srcaddr[0])); - inet_pton(PF_INET6, dst_ip, &(record->v6.dstaddr[0])); - record->v6.srcaddr[0] = ntohll(record->v6.srcaddr[0]); - record->v6.srcaddr[1] = ntohll(record->v6.srcaddr[1]); - record->v6.dstaddr[0] = ntohll(record->v6.dstaddr[0]); - record->v6.dstaddr[1] = ntohll(record->v6.dstaddr[1]); + inet_pton(PF_INET6, src_ip, &(record->V6.srcaddr[0])); + inet_pton(PF_INET6, dst_ip, &(record->V6.dstaddr[0])); + record->V6.srcaddr[0] = ntohll(record->V6.srcaddr[0]); + record->V6.srcaddr[1] = ntohll(record->V6.srcaddr[1]); + record->V6.dstaddr[0] = ntohll(record->V6.dstaddr[0]); + record->V6.dstaddr[1] = ntohll(record->V6.dstaddr[1]); } else { ClearFlag(record->flags, FLAG_IPV6_ADDR); - inet_pton(PF_INET, src_ip, &record->v4.srcaddr); - inet_pton(PF_INET, dst_ip, &record->v4.dstaddr); - record->v4.srcaddr = ntohl(record->v4.srcaddr); - record->v4.dstaddr = ntohl(record->v4.dstaddr); + inet_pton(PF_INET, src_ip, &record->V4.srcaddr); + inet_pton(PF_INET, dst_ip, &record->V4.dstaddr); + record->V4.srcaddr = ntohl(record->V4.srcaddr); + record->V4.dstaddr = ntohl(record->V4.dstaddr); } } // End of SetIPaddress @@ -116,13 +116,13 @@ static void SetNextIPaddress(master_record_t *record, int af, char *next_ip) { if ( af == PF_INET6 ) { SetFlag(record->flags, FLAG_IPV6_NH); - inet_pton(PF_INET6, next_ip, &(record->ip_nexthop.v6[0])); - record->ip_nexthop.v6[0] = ntohll(record->ip_nexthop.v6[0]); - record->ip_nexthop.v6[1] = ntohll(record->ip_nexthop.v6[1]); + inet_pton(PF_INET6, next_ip, &(record->ip_nexthop.V6[0])); + record->ip_nexthop.V6[0] = ntohll(record->ip_nexthop.V6[0]); + record->ip_nexthop.V6[1] = ntohll(record->ip_nexthop.V6[1]); } else { ClearFlag(record->flags, FLAG_IPV6_NH); - inet_pton(PF_INET, next_ip, &record->ip_nexthop.v4); - record->ip_nexthop.v4 = ntohl(record->ip_nexthop.v4); + inet_pton(PF_INET, next_ip, &record->ip_nexthop.V4); + record->ip_nexthop.V4 = ntohl(record->ip_nexthop.V4); } } // End of SetNextIPaddress @@ -131,13 +131,13 @@ static void SetRouterIPaddress(master_record_t *record, int af, char *next_ip) if ( af == PF_INET6 ) { SetFlag(record->flags, FLAG_IPV6_NH); - inet_pton(PF_INET6, next_ip, &(record->ip_router.v6[0])); - record->ip_router.v6[0] = ntohll(record->ip_router.v6[0]); - record->ip_router.v6[1] = ntohll(record->ip_router.v6[1]); + inet_pton(PF_INET6, next_ip, &(record->ip_router.V6[0])); + record->ip_router.V6[0] = ntohll(record->ip_router.V6[0]); + record->ip_router.V6[1] = ntohll(record->ip_router.V6[1]); } else { ClearFlag(record->flags, FLAG_IPV6_NH); - inet_pton(PF_INET, next_ip, &record->ip_router.v4); - record->ip_router.v4 = ntohl(record->ip_router.v4); + inet_pton(PF_INET, next_ip, &record->ip_router.V4); + record->ip_router.V4 = ntohl(record->ip_router.V4); } } // End of SetRouterIPaddress @@ -146,13 +146,13 @@ static void SetBGPNextIPaddress(master_record_t *record, int af, char *next_ip) if ( af == PF_INET6 ) { SetFlag(record->flags, FLAG_IPV6_NHB); - inet_pton(PF_INET6, next_ip, &(record->bgp_nexthop.v6[0])); - record->bgp_nexthop.v6[0] = ntohll(record->bgp_nexthop.v6[0]); - record->bgp_nexthop.v6[1] = ntohll(record->bgp_nexthop.v6[1]); + inet_pton(PF_INET6, next_ip, &(record->bgp_nexthop.V6[0])); + record->bgp_nexthop.V6[0] = ntohll(record->bgp_nexthop.V6[0]); + record->bgp_nexthop.V6[1] = ntohll(record->bgp_nexthop.V6[1]); } else { ClearFlag(record->flags, FLAG_IPV6_NHB); - inet_pton(PF_INET, next_ip, &record->bgp_nexthop.v4); - record->bgp_nexthop.v4 = ntohl(record->bgp_nexthop.v4); + inet_pton(PF_INET, next_ip, &record->bgp_nexthop.V4); + record->bgp_nexthop.V4 = ntohl(record->bgp_nexthop.V4); } } // End of SetBGPNextIPaddress diff --git a/bin/nflowcache.c b/bin/nflowcache.c index 3aa2480..912e27b 100755 --- a/bin/nflowcache.c +++ b/bin/nflowcache.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2017, Peter Haag * Copyright (c) 2014, Peter Haag * Copyright (c) 2009, Peter Haag * Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung @@ -28,12 +29,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * $Author: haag $ - * - * $Id: nflowcache.c 40 2009-12-16 10:41:44Z haag $ - * - * $LastChangedRevision: 40 $ - * */ #include "config.h" @@ -916,20 +911,20 @@ Default_key_t *keyptr; } else if ( swap_flow ) { // default 5-tuple aggregation for bidirectional flows keyptr = (Default_key_t *)keymem; - keyptr->srcaddr[0] = flow_record->v6.dstaddr[0]; - keyptr->srcaddr[1] = flow_record->v6.dstaddr[1]; - keyptr->dstaddr[0] = flow_record->v6.srcaddr[0]; - keyptr->dstaddr[1] = flow_record->v6.srcaddr[1]; + keyptr->srcaddr[0] = flow_record->V6.dstaddr[0]; + keyptr->srcaddr[1] = flow_record->V6.dstaddr[1]; + keyptr->dstaddr[0] = flow_record->V6.srcaddr[0]; + keyptr->dstaddr[1] = flow_record->V6.srcaddr[1]; keyptr->srcport = flow_record->dstport; keyptr->dstport = flow_record->srcport; keyptr->proto = flow_record->prot; } else { // default 5-tuple aggregation keyptr = (Default_key_t *)keymem; - keyptr->srcaddr[0] = flow_record->v6.srcaddr[0]; - keyptr->srcaddr[1] = flow_record->v6.srcaddr[1]; - keyptr->dstaddr[0] = flow_record->v6.dstaddr[0]; - keyptr->dstaddr[1] = flow_record->v6.dstaddr[1]; + keyptr->srcaddr[0] = flow_record->V6.srcaddr[0]; + keyptr->srcaddr[1] = flow_record->V6.srcaddr[1]; + keyptr->dstaddr[0] = flow_record->V6.dstaddr[0]; + keyptr->dstaddr[1] = flow_record->V6.dstaddr[1]; keyptr->srcport = flow_record->srcport; keyptr->dstport = flow_record->dstport; keyptr->proto = flow_record->prot; diff --git a/bin/nfreader.c b/bin/nfreader.c index 50f1312..3304795 100755 --- a/bin/nfreader.c +++ b/bin/nfreader.c @@ -29,13 +29,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * $Author: haag $ - * - * $Id: nfreader.c 48 2010-01-02 08:06:27Z haag $ - * - * $LastChangedRevision: 48 $ - * - * */ /* @@ -124,17 +117,17 @@ struct tm *ts; master_record_t *r = (master_record_t *)record; if ( (r->flags & FLAG_IPV6_ADDR ) != 0 ) { // IPv6 - r->v6.srcaddr[0] = htonll(r->v6.srcaddr[0]); - r->v6.srcaddr[1] = htonll(r->v6.srcaddr[1]); - r->v6.dstaddr[0] = htonll(r->v6.dstaddr[0]); - r->v6.dstaddr[1] = htonll(r->v6.dstaddr[1]); - inet_ntop(AF_INET6, r->v6.srcaddr, as, sizeof(as)); - inet_ntop(AF_INET6, r->v6.dstaddr, ds, sizeof(ds)); + r->V6.srcaddr[0] = htonll(r->V6.srcaddr[0]); + r->V6.srcaddr[1] = htonll(r->V6.srcaddr[1]); + r->V6.dstaddr[0] = htonll(r->V6.dstaddr[0]); + r->V6.dstaddr[1] = htonll(r->V6.dstaddr[1]); + inet_ntop(AF_INET6, r->V6.srcaddr, as, sizeof(as)); + inet_ntop(AF_INET6, r->V6.dstaddr, ds, sizeof(ds)); } else { // IPv4 - r->v4.srcaddr = htonl(r->v4.srcaddr); - r->v4.dstaddr = htonl(r->v4.dstaddr); - inet_ntop(AF_INET, &r->v4.srcaddr, as, sizeof(as)); - inet_ntop(AF_INET, &r->v4.dstaddr, ds, sizeof(ds)); + r->V4.srcaddr = htonl(r->V4.srcaddr); + r->V4.dstaddr = htonl(r->V4.dstaddr); + inet_ntop(AF_INET, &r->V4.srcaddr, as, sizeof(as)); + inet_ntop(AF_INET, &r->V4.dstaddr, ds, sizeof(ds)); } as[40-1] = 0; ds[40-1] = 0; diff --git a/bin/nfstat.c b/bin/nfstat.c index 450935e..41da14b 100644 --- a/bin/nfstat.c +++ b/bin/nfstat.c @@ -1543,10 +1543,10 @@ char *string; // apply IP mask from aggregation, to provide a pretty output if ( FlowTable->has_masks ) { - flow_record->v6.srcaddr[0] &= FlowTable->IPmask[0]; - flow_record->v6.srcaddr[1] &= FlowTable->IPmask[1]; - flow_record->v6.dstaddr[0] &= FlowTable->IPmask[2]; - flow_record->v6.dstaddr[1] &= FlowTable->IPmask[3]; + flow_record->V6.srcaddr[0] &= FlowTable->IPmask[0]; + flow_record->V6.srcaddr[1] &= FlowTable->IPmask[1]; + flow_record->V6.dstaddr[0] &= FlowTable->IPmask[2]; + flow_record->V6.dstaddr[1] &= FlowTable->IPmask[3]; } if ( aggr_record_mask ) { @@ -1718,10 +1718,10 @@ int i, max; // apply IP mask from aggregation, to provide a pretty output if ( FlowTable->has_masks ) { - flow_record->v6.srcaddr[0] &= FlowTable->IPmask[0]; - flow_record->v6.srcaddr[1] &= FlowTable->IPmask[1]; - flow_record->v6.dstaddr[0] &= FlowTable->IPmask[2]; - flow_record->v6.dstaddr[1] &= FlowTable->IPmask[3]; + flow_record->V6.srcaddr[0] &= FlowTable->IPmask[0]; + flow_record->V6.srcaddr[1] &= FlowTable->IPmask[1]; + flow_record->V6.dstaddr[0] &= FlowTable->IPmask[2]; + flow_record->V6.dstaddr[1] &= FlowTable->IPmask[3]; } if ( FlowTable->apply_netbits ) { @@ -1887,12 +1887,12 @@ uint64_t _tmp_ip[2]; uint64_t _tmp_l; uint32_t _tmp; - _tmp_ip[0] = flow_record->v6.srcaddr[0]; - _tmp_ip[1] = flow_record->v6.srcaddr[1]; - flow_record->v6.srcaddr[0] = flow_record->v6.dstaddr[0]; - flow_record->v6.srcaddr[1] = flow_record->v6.dstaddr[1]; - flow_record->v6.dstaddr[0] = _tmp_ip[0]; - flow_record->v6.dstaddr[1] = _tmp_ip[1]; + _tmp_ip[0] = flow_record->V6.srcaddr[0]; + _tmp_ip[1] = flow_record->V6.srcaddr[1]; + flow_record->V6.srcaddr[0] = flow_record->V6.dstaddr[0]; + flow_record->V6.srcaddr[1] = flow_record->V6.dstaddr[1]; + flow_record->V6.dstaddr[0] = _tmp_ip[0]; + flow_record->V6.dstaddr[1] = _tmp_ip[1]; _tmp = flow_record->srcport; flow_record->srcport = flow_record->dstport; diff --git a/bin/nftest.c b/bin/nftest.c index 5183a54..58aa48f 100644 --- a/bin/nftest.c +++ b/bin/nftest.c @@ -368,12 +368,12 @@ void *p; ret = check_filter_block("icmp-code 4", &flow_record, 0); - inet_pton(PF_INET6, "fe80::2110:abcd:1234:5678", flow_record.v6.srcaddr); - inet_pton(PF_INET6, "fe80::1104:fedc:4321:8765", flow_record.v6.dstaddr); - flow_record.v6.srcaddr[0] = ntohll(flow_record.v6.srcaddr[0]); - flow_record.v6.srcaddr[1] = ntohll(flow_record.v6.srcaddr[1]); - flow_record.v6.dstaddr[0] = ntohll(flow_record.v6.dstaddr[0]); - flow_record.v6.dstaddr[1] = ntohll(flow_record.v6.dstaddr[1]); + inet_pton(PF_INET6, "fe80::2110:abcd:1234:5678", flow_record.V6.srcaddr); + inet_pton(PF_INET6, "fe80::1104:fedc:4321:8765", flow_record.V6.dstaddr); + flow_record.V6.srcaddr[0] = ntohll(flow_record.V6.srcaddr[0]); + flow_record.V6.srcaddr[1] = ntohll(flow_record.V6.srcaddr[1]); + flow_record.V6.dstaddr[0] = ntohll(flow_record.V6.dstaddr[0]); + flow_record.V6.dstaddr[1] = ntohll(flow_record.V6.dstaddr[1]); ret = check_filter_block("src ip fe80::2110:abcd:1234:5678", &flow_record, 1); ret = check_filter_block("src ip fe80::2110:abcd:1234:5679", &flow_record, 0); ret = check_filter_block("src ip fe80::2111:abcd:1234:5678", &flow_record, 0); @@ -390,39 +390,39 @@ void *p; ret = check_filter_block("src ip in [fe80::2110:abcd:1234:5678]", &flow_record, 1); ret = check_filter_block("src ip in [fe80::2110:abcd:1234:5679]", &flow_record, 0); - inet_pton(PF_INET6, "fe80::2110:abcd:1234:0", flow_record.v6.srcaddr); - flow_record.v6.srcaddr[0] = ntohll(flow_record.v6.srcaddr[0]); - flow_record.v6.srcaddr[1] = ntohll(flow_record.v6.srcaddr[1]); + inet_pton(PF_INET6, "fe80::2110:abcd:1234:0", flow_record.V6.srcaddr); + flow_record.V6.srcaddr[0] = ntohll(flow_record.V6.srcaddr[0]); + flow_record.V6.srcaddr[1] = ntohll(flow_record.V6.srcaddr[1]); ret = check_filter_block("src net fe80::2110:abcd:1234:0/112", &flow_record, 1); - inet_pton(PF_INET6, "fe80::2110:abcd:1234:ffff", flow_record.v6.srcaddr); - flow_record.v6.srcaddr[0] = ntohll(flow_record.v6.srcaddr[0]); - flow_record.v6.srcaddr[1] = ntohll(flow_record.v6.srcaddr[1]); + inet_pton(PF_INET6, "fe80::2110:abcd:1234:ffff", flow_record.V6.srcaddr); + flow_record.V6.srcaddr[0] = ntohll(flow_record.V6.srcaddr[0]); + flow_record.V6.srcaddr[1] = ntohll(flow_record.V6.srcaddr[1]); ret = check_filter_block("src net fe80::2110:abcd:1234:0/112", &flow_record, 1); - inet_pton(PF_INET6, "fe80::2110:abcd:1235:ffff", flow_record.v6.srcaddr); - flow_record.v6.srcaddr[0] = ntohll(flow_record.v6.srcaddr[0]); - flow_record.v6.srcaddr[1] = ntohll(flow_record.v6.srcaddr[1]); + inet_pton(PF_INET6, "fe80::2110:abcd:1235:ffff", flow_record.V6.srcaddr); + flow_record.V6.srcaddr[0] = ntohll(flow_record.V6.srcaddr[0]); + flow_record.V6.srcaddr[1] = ntohll(flow_record.V6.srcaddr[1]); ret = check_filter_block("src net fe80::2110:abcd:1234:0/112", &flow_record, 0); ret = check_filter_block("src net fe80::0/16", &flow_record, 1); ret = check_filter_block("src net fe81::0/16", &flow_record, 0); - flow_record.v6.srcaddr[0] = 0; - flow_record.v6.srcaddr[1] = 0; + flow_record.V6.srcaddr[0] = 0; + flow_record.V6.srcaddr[1] = 0; - inet_pton(PF_INET6, "fe80::2110:abcd:1234:0", flow_record.v6.dstaddr); - flow_record.v6.dstaddr[0] = ntohll(flow_record.v6.dstaddr[0]); - flow_record.v6.dstaddr[1] = ntohll(flow_record.v6.dstaddr[1]); + inet_pton(PF_INET6, "fe80::2110:abcd:1234:0", flow_record.V6.dstaddr); + flow_record.V6.dstaddr[0] = ntohll(flow_record.V6.dstaddr[0]); + flow_record.V6.dstaddr[1] = ntohll(flow_record.V6.dstaddr[1]); ret = check_filter_block("dst net fe80::2110:abcd:1234:0/112", &flow_record, 1); - inet_pton(PF_INET6, "fe80::2110:abcd:1234:ffff", flow_record.v6.dstaddr); - flow_record.v6.dstaddr[0] = ntohll(flow_record.v6.dstaddr[0]); - flow_record.v6.dstaddr[1] = ntohll(flow_record.v6.dstaddr[1]); + inet_pton(PF_INET6, "fe80::2110:abcd:1234:ffff", flow_record.V6.dstaddr); + flow_record.V6.dstaddr[0] = ntohll(flow_record.V6.dstaddr[0]); + flow_record.V6.dstaddr[1] = ntohll(flow_record.V6.dstaddr[1]); ret = check_filter_block("dst net fe80::2110:abcd:1234:0/112", &flow_record, 1); - inet_pton(PF_INET6, "fe80::2110:abcd:1235:ffff", flow_record.v6.dstaddr); - flow_record.v6.dstaddr[0] = ntohll(flow_record.v6.dstaddr[0]); - flow_record.v6.dstaddr[1] = ntohll(flow_record.v6.dstaddr[1]); + inet_pton(PF_INET6, "fe80::2110:abcd:1235:ffff", flow_record.V6.dstaddr); + flow_record.V6.dstaddr[0] = ntohll(flow_record.V6.dstaddr[0]); + flow_record.V6.dstaddr[1] = ntohll(flow_record.V6.dstaddr[1]); ret = check_filter_block("dst net fe80::2110:abcd:1234:0/112", &flow_record, 0); ret = check_filter_block("dst net fe80::0/16", &flow_record, 1); ret = check_filter_block("not dst net fe80::0/16", &flow_record, 0); @@ -433,12 +433,12 @@ void *p; /* 172.32.7.16 => 0xac200710 * 10.10.10.11 => 0x0a0a0a0b */ - flow_record.v6.srcaddr[0] = 0; - flow_record.v6.srcaddr[1] = 0; - flow_record.v6.dstaddr[0] = 0; - flow_record.v6.dstaddr[1] = 0; - flow_record.v4.srcaddr = 0xac200710; - flow_record.v4.dstaddr = 0x0a0a0a0b; + flow_record.V6.srcaddr[0] = 0; + flow_record.V6.srcaddr[1] = 0; + flow_record.V6.dstaddr[0] = 0; + flow_record.V6.dstaddr[1] = 0; + flow_record.V4.srcaddr = 0xac200710; + flow_record.V4.dstaddr = 0x0a0a0a0b; ret = check_filter_block("src ip 172.32.7.16", &flow_record, 1); ret = check_filter_block("src ip 172.32.7.15", &flow_record, 0); ret = check_filter_block("dst ip 10.10.10.11", &flow_record, 1); @@ -596,53 +596,53 @@ void *p; ret = check_filter_block("src ip 172.32.7.15 and dst ip 10.10.10.11", &flow_record, 0); ret = check_filter_block("src ip 172.32.7.16 and dst ip 10.10.10.12", &flow_record, 0); - flow_record.v4.srcaddr = 0; - flow_record.v4.dstaddr = 0; + flow_record.V4.srcaddr = 0; + flow_record.V4.dstaddr = 0; // 172.32.7.16 => 0xac200710 - flow_record.ip_nexthop.v6[0] = 0; - flow_record.ip_nexthop.v6[1] = 0; - flow_record.ip_nexthop.v4 = 0xac200710; + flow_record.ip_nexthop.V6[0] = 0; + flow_record.ip_nexthop.V6[1] = 0; + flow_record.ip_nexthop.V4 = 0xac200710; ret = check_filter_block("next ip 172.32.7.16", &flow_record, 1); ret = check_filter_block("next ip 172.32.7.15", &flow_record, 0); ret = check_filter_block("next ip in [172.32.7.16 fe80::2110:abcd:1235:ffff]", &flow_record, 1); ret = check_filter_block("next ip in [172.32.7.15 fe80::2110:abcd:1235:ffff]", &flow_record, 0); - inet_pton(PF_INET6, "fe80::2110:abcd:1235:ffff", flow_record.ip_nexthop.v6); - flow_record.ip_nexthop.v6[0] = ntohll(flow_record.ip_nexthop.v6[0]); - flow_record.ip_nexthop.v6[1] = ntohll(flow_record.ip_nexthop.v6[1]); + inet_pton(PF_INET6, "fe80::2110:abcd:1235:ffff", flow_record.ip_nexthop.V6); + flow_record.ip_nexthop.V6[0] = ntohll(flow_record.ip_nexthop.V6[0]); + flow_record.ip_nexthop.V6[1] = ntohll(flow_record.ip_nexthop.V6[1]); ret = check_filter_block("next ip fe80::2110:abcd:1235:ffff", &flow_record, 1); ret = check_filter_block("next ip in [172.32.7.16 fe80::2110:abcd:1235:ffff]", &flow_record, 1); ret = check_filter_block("next ip in [172.32.7.16 fe80::2110:abcd:1235:fffe]", &flow_record, 0); ret = check_filter_block("next ip fe80::2110:abcd:1235:fffe", &flow_record, 0); ret = check_filter_block("next ip fe81::2110:abcd:1235:ffff", &flow_record, 0); - flow_record.ip_nexthop.v6[0] = 0; - flow_record.ip_nexthop.v6[1] = 0; + flow_record.ip_nexthop.V6[0] = 0; + flow_record.ip_nexthop.V6[1] = 0; - flow_record.bgp_nexthop.v6[0] = 0; - flow_record.bgp_nexthop.v6[1] = 0; - flow_record.bgp_nexthop.v4 = 0xac200710; + flow_record.bgp_nexthop.V6[0] = 0; + flow_record.bgp_nexthop.V6[1] = 0; + flow_record.bgp_nexthop.V4 = 0xac200710; ret = check_filter_block("bgpnext ip 172.32.7.16", &flow_record, 1); ret = check_filter_block("bgpnext ip 172.32.7.15", &flow_record, 0); - inet_pton(PF_INET6, "fe80::2110:abcd:1235:ffff", flow_record.bgp_nexthop.v6); - flow_record.bgp_nexthop.v6[0] = ntohll(flow_record.bgp_nexthop.v6[0]); - flow_record.bgp_nexthop.v6[1] = ntohll(flow_record.bgp_nexthop.v6[1]); + inet_pton(PF_INET6, "fe80::2110:abcd:1235:ffff", flow_record.bgp_nexthop.V6); + flow_record.bgp_nexthop.V6[0] = ntohll(flow_record.bgp_nexthop.V6[0]); + flow_record.bgp_nexthop.V6[1] = ntohll(flow_record.bgp_nexthop.V6[1]); ret = check_filter_block("bgpnext ip fe80::2110:abcd:1235:ffff", &flow_record, 1); ret = check_filter_block("bgpnext ip fe80::2110:abcd:1235:fffe", &flow_record, 0); ret = check_filter_block("bgpnext ip fe81::2110:abcd:1235:ffff", &flow_record, 0); - flow_record.ip_router.v6[0] = 0; - flow_record.ip_router.v6[1] = 0; - flow_record.ip_router.v4 = 0xac200720; - flow_record.ip_nexthop.v4 = 0xac200720; + flow_record.ip_router.V6[0] = 0; + flow_record.ip_router.V6[1] = 0; + flow_record.ip_router.V4 = 0xac200720; + flow_record.ip_nexthop.V4 = 0xac200720; ret = check_filter_block("router ip 172.32.7.32", &flow_record, 1); ret = check_filter_block("router ip 172.32.7.33", &flow_record, 0); - inet_pton(PF_INET6, "fe80::2110:abcd:1235:ffff", flow_record.ip_router.v6); - flow_record.ip_router.v6[0] = ntohll(flow_record.ip_router.v6[0]); - flow_record.ip_router.v6[1] = ntohll(flow_record.ip_router.v6[1]); + inet_pton(PF_INET6, "fe80::2110:abcd:1235:ffff", flow_record.ip_router.V6); + flow_record.ip_router.V6[0] = ntohll(flow_record.ip_router.V6[0]); + flow_record.ip_router.V6[1] = ntohll(flow_record.ip_router.V6[1]); ret = check_filter_block("router ip fe80::2110:abcd:1235:ffff", &flow_record, 1); ret = check_filter_block("router ip fe80::2110:abcd:1235:fffe", &flow_record, 0); ret = check_filter_block("router ip fe81::2110:abcd:1235:ffff", &flow_record, 0); @@ -1039,12 +1039,12 @@ void *p; ret = check_filter_block("asa xevent < 1004", &flow_record, 0); ret = check_filter_block("asa xevent > 1004", &flow_record, 0); - flow_record.xlate_src_ip.v6[0] = 0; - flow_record.xlate_src_ip.v6[1] = 0; - flow_record.xlate_src_ip.v4 = 0xac200710; - flow_record.xlate_dst_ip.v6[0] = 0; - flow_record.xlate_dst_ip.v6[1] = 0; - flow_record.xlate_dst_ip.v4 = 0x0a0a0a0b; + flow_record.xlate_src_ip.V6[0] = 0; + flow_record.xlate_src_ip.V6[1] = 0; + flow_record.xlate_src_ip.V4 = 0xac200710; + flow_record.xlate_dst_ip.V6[0] = 0; + flow_record.xlate_dst_ip.V6[1] = 0; + flow_record.xlate_dst_ip.V4 = 0x0a0a0a0b; ret = check_filter_block("src xip 172.32.7.16", &flow_record, 1); ret = check_filter_block("src xip 172.32.7.15", &flow_record, 0); ret = check_filter_block("dst xip 10.10.10.11", &flow_record, 1); @@ -1060,23 +1060,23 @@ void *p; ret = check_filter_block("xnet 172.32.7.0/24", &flow_record, 1); ret = check_filter_block("xnet 10.10.10.0/24", &flow_record, 1); - inet_pton(PF_INET6, "fe80::2110:abcd:1235:ffff", flow_record.xlate_src_ip.v6); - flow_record.xlate_src_ip.v6[0] = ntohll(flow_record.xlate_src_ip.v6[0]); - flow_record.xlate_src_ip.v6[1] = ntohll(flow_record.xlate_src_ip.v6[1]); + inet_pton(PF_INET6, "fe80::2110:abcd:1235:ffff", flow_record.xlate_src_ip.V6); + flow_record.xlate_src_ip.V6[0] = ntohll(flow_record.xlate_src_ip.V6[0]); + flow_record.xlate_src_ip.V6[1] = ntohll(flow_record.xlate_src_ip.V6[1]); ret = check_filter_block("src xip fe80::2110:abcd:1235:ffff", &flow_record, 1); ret = check_filter_block("src xip fe80::2110:abcd:1235:fffe", &flow_record, 0); - flow_record.xlate_src_ip.v6[0] = 0; - flow_record.xlate_src_ip.v6[1] = 0; - inet_pton(PF_INET6, "fe80::2110:abcd:1235:fffe", flow_record.xlate_dst_ip.v6); - flow_record.xlate_dst_ip.v6[0] = ntohll(flow_record.xlate_dst_ip.v6[0]); - flow_record.xlate_dst_ip.v6[1] = ntohll(flow_record.xlate_dst_ip.v6[1]); + flow_record.xlate_src_ip.V6[0] = 0; + flow_record.xlate_src_ip.V6[1] = 0; + inet_pton(PF_INET6, "fe80::2110:abcd:1235:fffe", flow_record.xlate_dst_ip.V6); + flow_record.xlate_dst_ip.V6[0] = ntohll(flow_record.xlate_dst_ip.V6[0]); + flow_record.xlate_dst_ip.V6[1] = ntohll(flow_record.xlate_dst_ip.V6[1]); ret = check_filter_block("dst xip fe80::2110:abcd:1235:fffe", &flow_record, 1); ret = check_filter_block("dst xip fe80::2110:abcd:1235:fffc", &flow_record, 0); - flow_record.xlate_src_ip.v6[0] = 0; - flow_record.xlate_src_ip.v6[1] = 0; - flow_record.xlate_dst_ip.v6[0] = 0; - flow_record.xlate_dst_ip.v6[1] = 0; + flow_record.xlate_src_ip.V6[0] = 0; + flow_record.xlate_src_ip.V6[1] = 0; + flow_record.xlate_dst_ip.V6[0] = 0; + flow_record.xlate_dst_ip.V6[1] = 0; flow_record.xlate_src_port = 1023; flow_record.xlate_dst_port = 32798; @@ -1205,12 +1205,12 @@ exit(0); flow_record.xlate_src_port = 0xffff; flow_record.xlate_dst_port = 0xffff; - flow_record.xlate_src_ip.v6[0] = 0; - flow_record.xlate_src_ip.v6[1] = 0; - flow_record.xlate_src_ip.v4 = 0xac200710; - flow_record.xlate_dst_ip.v6[0] = 0; - flow_record.xlate_dst_ip.v6[1] = 0; - flow_record.xlate_dst_ip.v4 = 0x0a0a0a0b; + flow_record.xlate_src_ip.V6[0] = 0; + flow_record.xlate_src_ip.V6[1] = 0; + flow_record.xlate_src_ip.V4 = 0xac200710; + flow_record.xlate_dst_ip.V6[0] = 0; + flow_record.xlate_dst_ip.V6[1] = 0; + flow_record.xlate_dst_ip.V4 = 0x0a0a0a0b; ret = check_filter_block("src nip 172.32.7.16", &flow_record, 1); ret = check_filter_block("src nip 172.32.7.15", &flow_record, 0); ret = check_filter_block("dst nip 10.10.10.11", &flow_record, 1); @@ -1220,17 +1220,17 @@ exit(0); ret = check_filter_block("nip 172.32.7.15", &flow_record, 0); ret = check_filter_block("nip 10.10.10.12", &flow_record, 0); - inet_pton(PF_INET6, "fe80::2110:abcd:1235:ffff", flow_record.xlate_src_ip.v6); - flow_record.xlate_src_ip.v6[0] = ntohll(flow_record.xlate_src_ip.v6[0]); - flow_record.xlate_src_ip.v6[1] = ntohll(flow_record.xlate_src_ip.v6[1]); + inet_pton(PF_INET6, "fe80::2110:abcd:1235:ffff", flow_record.xlate_src_ip.V6); + flow_record.xlate_src_ip.V6[0] = ntohll(flow_record.xlate_src_ip.V6[0]); + flow_record.xlate_src_ip.V6[1] = ntohll(flow_record.xlate_src_ip.V6[1]); ret = check_filter_block("src nip fe80::2110:abcd:1235:ffff", &flow_record, 1); ret = check_filter_block("src nip fe80::2110:abcd:1235:fffe", &flow_record, 0); - flow_record.xlate_src_ip.v6[0] = 0; - flow_record.xlate_src_ip.v6[1] = 0; - inet_pton(PF_INET6, "fe80::2110:abcd:1235:fffe", flow_record.xlate_dst_ip.v6); - flow_record.xlate_dst_ip.v6[0] = ntohll(flow_record.xlate_dst_ip.v6[0]); - flow_record.xlate_dst_ip.v6[1] = ntohll(flow_record.xlate_dst_ip.v6[1]); + flow_record.xlate_src_ip.V6[0] = 0; + flow_record.xlate_src_ip.V6[1] = 0; + inet_pton(PF_INET6, "fe80::2110:abcd:1235:fffe", flow_record.xlate_dst_ip.V6); + flow_record.xlate_dst_ip.V6[0] = ntohll(flow_record.xlate_dst_ip.V6[0]); + flow_record.xlate_dst_ip.V6[1] = ntohll(flow_record.xlate_dst_ip.V6[1]); ret = check_filter_block("dst nip fe80::2110:abcd:1235:fffe", &flow_record, 1); ret = check_filter_block("dst nip fe80::2110:abcd:1235:fffc", &flow_record, 0); diff --git a/bin/pack.pcap b/bin/pack.pcap deleted file mode 100644 index e0bb70a47d71248085d70e6aea7ef28bdf75d645..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 479666 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%0D$Qg`cBYlR-R`xe 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%0DPRoMX3sChGB%p2oI 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�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�u|%hS~p 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 Pp2zH|Go-t{mOTFlF@x~0 diff --git a/bin/sfcapd.c b/bin/sfcapd.c index cb90b34..e2ea145 100644 --- a/bin/sfcapd.c +++ b/bin/sfcapd.c @@ -91,7 +91,7 @@ #include "expire.h" -#include "sflow.h" +#include "sflow_nfdump.h" #define DEFAULTSFLOWPORT "6343" diff --git a/bin/sflow.c b/bin/sflow.c deleted file mode 100644 index 26e57d4..0000000 --- a/bin/sflow.c +++ /dev/null @@ -1,2751 +0,0 @@ -/* - * Copyright (c) 2017, Peter Haag - * Copyright (c) 2016, Peter Haag - * Copyright (c) 2014, Peter Haag - * Copyright (c) 2009, Peter Haag - * Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the author nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Author: haag $ - * - * $Id: sflow.c 69 2010-09-09 07:17:43Z haag $ - * - * $LastChangedRevision: 69 $ - * - * - */ - -/* - * sfcapd makes use of code originated from sflowtool by InMon Corp. - * Those parts of the code are distributed under the InMon Public License below. - * All other/additional code is pubblished under BSD license. - */ - - -/* - * ----------------------------------------------------------------------- - * Copyright (c) 2001-2002 InMon Corp. All rights reserved. - * ----------------------------------------------------------------------- - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes sFlow(TM), freely available from - * http://www.inmon.com/". - * - * 4. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes sFlow(TM), freely available from - * http://www.inmon.com/". - * - * 5. InMon Corp. may publish revised and/or new versions - * of the license from time to time. Each version will be given a - * distinguishing version number. Once covered code has been - * published under a particular version of the license, you may - * always continue to use it under the terms of that version. You - * may also choose to use such covered code under the terms of any - * subsequent version of the license published by InMon Corp. - * No one other than the InMon Corp. has the right to modify the terms - * applicable to covered code created under this License. - * - * 6. The name "sFlow" must not be used to endorse or promote products - * derived from this software without prior written permission - * from InMon Corp. This does not apply to add-on libraries or tools - * that work in conjunction with sFlow. In such a case the sFlow name - * may be used to indicate that the product supports sFlow. - * - * 7. Products derived from this software may not be called "sFlow", - * nor may "sFlow" appear in their name, without prior written - * permission of InMon Corp. - * - * - * THIS SOFTWARE IS PROVIDED BY INMON CORP. ``AS IS'' AND - * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * INMON CORP. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * -------------------------------------------------------------------- - * - * This software consists of voluntary contributions made by many - * individuals on behalf of InMon Corp. - * - * InMon Corp. can be contacted via Email at info@inmon.com. - * - * For more information on InMon Corp. and sFlow, - * please see http://www.inmon.com/. - * - * InMon Public License Version 1.0 written May 31, 2001 - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_STDINT_H -#include -#endif - -#include "nffile.h" -#include "nfx.h" -#include "nf_common.h" -#include "util.h" -#include "bookkeeper.h" -#include "collector.h" -#include "sflow.h" -#include "sflow_proto.h" // sFlow v5 - -/* -#ifdef DARWIN -#include -#define bswap_16(x) NXSwapShort(x) -#define bswap_32(x) NXSwapInt(x) -#else -#include -#endif -*/ - -#ifndef DEVEL -# define dbg_printf(...) /* printf(__VA_ARGS__) */ -#else -# define dbg_printf(...) printf(__VA_ARGS__) -#endif - -#define MAX_SFLOW_EXTENSIONS 8 - -typedef struct exporter_sflow_s { - // link chain - struct exporter_sflow_s *next; - - // generic exporter information - exporter_info_record_t info; - - uint64_t packets; // number of packets sent by this exporter - uint64_t flows; // number of flow records sent by this exporter - uint32_t sequence_failure; // number of sequence failues - - generic_sampler_t *sampler; - - // extension map - // extension maps are common for all exporters - extension_info_t sflow_extension_info[MAX_SFLOW_EXTENSIONS]; - -} exporter_sflow_t; - -extern extension_descriptor_t extension_descriptor[]; -extern FlowSource_t *FlowSource; - -/* module limited globals */ - -/* - * As sflow has no templates, we need to have an extension map for each possible - * combination of IPv4/IPv6 addresses in all ip fields - * - * index id: - * 0 : EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v4 - * 1 : EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v4 - * 2 : EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v4 - * 3 : EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v4 - * 4 : EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v6 - * 5 : EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v6 - * 6 : EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v6 - * 7 : EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v6 - */ -static uint16_t sflow_output_record_size[MAX_SFLOW_EXTENSIONS]; - -// All available extensions for sflow -static uint16_t sflow_extensions[] = { - EX_IO_SNMP_4, - EX_AS_4, - EX_MULIPLE, - EX_VLAN, - EX_MAC_1, - EX_RECEIVED, - 0 // final token -}; -static int Num_enabled_extensions; - -static struct sflow_ip_extensions_s { - int next_hop; - int next_hop_bgp; - int router_ip; -} sflow_ip_extensions[] = { - { EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v4 }, - { EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v4 }, - { EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v4 }, - { EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v4 }, - { EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v6 }, - { EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v6 }, - { EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v6 }, - { EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v6 }, -}; - -#define SFLOW_NEXT_HOP 1 -#define SFLOW_NEXT_HOP_BGP 2 -#define SFLOW_ROUTER_IP 4 -static int IP_extension_mask = 0; - -static inline exporter_sflow_t *GetExporter(FlowSource_t *fs, uint32_t agentSubId, uint32_t meanSkipCount); - -/* - * unused -// -static uint32_t MyByteSwap32(uint32_t n) { - return (((n & 0x000000FF)<<24) + - ((n & 0x0000FF00)<<8) + - ((n & 0x00FF0000)>>8) + - ((n & 0xFF000000)>>24)); -} - -static uint16_t MyByteSwap16(uint16_t n) { - return ((n >> 8) | (n << 8)); -} -*/ - -#define YES 1 -#define NO 0 - -/* define my own IP header struct - to ease portability */ -struct myiphdr { - uint8_t version_and_headerLen; - uint8_t tos; - uint16_t tot_len; - uint16_t id; - uint16_t frag_off; - uint8_t ttl; - uint8_t protocol; - uint16_t check; - uint32_t saddr; - uint32_t daddr; -}; - -/* same for tcp */ -struct mytcphdr { - uint16_t th_sport; /* source port */ - uint16_t th_dport; /* destination port */ - uint32_t th_seq; /* sequence number */ - uint32_t th_ack; /* acknowledgement number */ - uint8_t th_off_and_unused; - uint8_t th_flags; - uint16_t th_win; /* window */ - uint16_t th_sum; /* checksum */ - uint16_t th_urp; /* urgent pointer */ -}; - -/* and UDP */ -struct myudphdr { - uint16_t uh_sport; /* source port */ - uint16_t uh_dport; /* destination port */ - uint16_t uh_ulen; /* udp length */ - uint16_t uh_sum; /* udp checksum */ -}; - -/* and ICMP */ -struct myicmphdr { - uint8_t type; /* message type */ - uint8_t code; /* type sub-code */ - /* ignore the rest */ -}; - -typedef struct _SFForwardingTarget { - struct _SFForwardingTarget *nxt; - struct in_addr host; - uint32_t port; - struct sockaddr_in addr; - int sock; -} SFForwardingTarget; - -typedef enum { SFLFMT_FULL=0, SFLFMT_PCAP, SFLFMT_LINE } EnumSFLFormat; - -typedef struct _SFConfig { - uint16_t netFlowPeerAS; - int disableNetFlowScale; -} SFConfig; - -/* make the options structure global to the program */ -static SFConfig sfConfig; - -typedef struct _SFSample { - struct in_addr sourceIP; // EX_ROUTER_IP_v4 - SFLAddress agent_addr; - uint32_t agentSubId; - - /* the raw pdu */ - u_char *rawSample; - uint32_t rawSampleLen; - u_char *endp; - - /* decode cursor */ - uint32_t *datap; - - uint32_t datagramVersion; - uint32_t sampleType; - uint32_t ds_class; - uint32_t ds_index; - - /* generic interface counter sample */ - SFLIf_counters ifCounters; - - /* sample stream info */ - uint32_t sysUpTime; - uint32_t sequenceNo; - uint32_t sampledPacketSize; - uint32_t samplesGenerated; - uint32_t meanSkipCount; - uint32_t samplePool; - uint32_t dropEvents; - - /* exception handler context */ - jmp_buf env; - - /* the sampled header */ - uint32_t packet_data_tag; - uint32_t headerProtocol; - u_char *header; - int headerLen; - uint32_t stripped; - - /* header decode */ - int gotIPV4; - int offsetToIPV4; - int gotIPV6; // v6 flag - int offsetToIPV6; - struct in_addr dcd_srcIP; // Common (v4) - struct in_addr dcd_dstIP; // Common (v4) - uint32_t dcd_ipProtocol; // Common - uint32_t dcd_ipTos; // EX_MULIPLE - uint32_t dcd_ipTTL; - uint32_t dcd_sport; // Common - uint32_t dcd_dport; // Common - uint32_t dcd_tcpFlags; // Common - uint32_t ip_fragmentOffset; - uint32_t udp_pduLen; - - /* ports */ - uint32_t inputPortFormat; - uint32_t outputPortFormat; - uint32_t inputPort; // EX_IO_SNMP_4 - uint32_t outputPort; // EX_IO_SNMP_4 - - /* ethernet */ - uint32_t eth_type; - uint32_t eth_len; - u_char eth_src[8]; // EX_MAC_1 - u_char eth_dst[8]; // EX_MAC_1 - - /* vlan */ - uint32_t in_vlan; // EX_VLAN - uint32_t in_priority; - uint32_t internalPriority; - uint32_t out_vlan; // EX_VLAN - uint32_t out_priority; - - /* extended data fields */ - uint32_t num_extended; - uint32_t extended_data_tag; -#define SASAMPLE_EXTENDED_DATA_SWITCH 1 -#define SASAMPLE_EXTENDED_DATA_ROUTER 4 -#define SASAMPLE_EXTENDED_DATA_GATEWAY 8 -#define SASAMPLE_EXTENDED_DATA_USER 16 -#define SASAMPLE_EXTENDED_DATA_URL 32 -#define SASAMPLE_EXTENDED_DATA_MPLS 64 -#define SASAMPLE_EXTENDED_DATA_NAT 128 -#define SASAMPLE_EXTENDED_DATA_MPLS_TUNNEL 256 -#define SASAMPLE_EXTENDED_DATA_MPLS_VC 512 -#define SASAMPLE_EXTENDED_DATA_MPLS_FTN 1024 -#define SASAMPLE_EXTENDED_DATA_MPLS_LDP_FEC 2048 -#define SASAMPLE_EXTENDED_DATA_VLAN_TUNNEL 4096 - - /* IP forwarding info */ - SFLAddress nextHop; // EX_NEXT_HOP_v4, EX_NEXT_HOP_v6 - uint32_t srcMask; // EX_MULIPLE - uint32_t dstMask; // EX_MULIPLE - - /* BGP info */ - SFLAddress bgp_nextHop; // EX_NEXT_HOP_BGP_v4, EX_NEXT_HOP_BGP_v6 - uint32_t my_as; - uint32_t src_as; // EX_AS_4 - uint32_t src_peer_as; - uint32_t dst_as_path_len; - uint32_t *dst_as_path; - /* note: version 4 dst as path segments just get printed, not stored here, however - * the dst_peer and dst_as are filled in, since those are used for netflow encoding - */ - uint32_t dst_peer_as; - uint32_t dst_as; // EX_AS_4 - - uint32_t communities_len; - uint32_t *communities; - uint32_t localpref; - - /* user id */ -#define SA_MAX_EXTENDED_USER_LEN 200 - uint32_t src_user_charset; - uint32_t src_user_len; - char src_user[SA_MAX_EXTENDED_USER_LEN+1]; - uint32_t dst_user_charset; - uint32_t dst_user_len; - char dst_user[SA_MAX_EXTENDED_USER_LEN+1]; - - /* url */ -#define SA_MAX_EXTENDED_URL_LEN 200 -#define SA_MAX_EXTENDED_HOST_LEN 200 - uint32_t url_direction; - uint32_t url_len; - char url[SA_MAX_EXTENDED_URL_LEN+1]; - uint32_t host_len; - char host[SA_MAX_EXTENDED_HOST_LEN+1]; - - /* mpls */ - SFLAddress mpls_nextHop; - - /* nat */ - SFLAddress nat_src; - SFLAddress nat_dst; - - /* counter blocks */ - uint32_t statsSamplingInterval; - uint32_t counterBlockVersion; - -#define SFABORT(s, r) longjmp((s)->env, (r)) -#define SF_ABORT_EOS 1 -#define SF_ABORT_DECODE_ERROR 2 -#define SF_ABORT_LENGTH_ERROR 3 - - SFLAddress ipsrc; // Common (v6) - SFLAddress ipdst; // Common (v6) -} SFSample; - -int Setup_Extension_Info(FlowSource_t *fs, exporter_sflow_t *exporter, int num); - -static int printHex(const u_char *a, int len, char *buf, int bufLen, int marker, int bytesPerOutputLine); - -static char *IP_to_a(uint32_t ipaddr, char *buf, int buflen); - -static inline uint32_t getData32(SFSample *sample); - -static inline uint32_t getData32_nobswap(SFSample *sample); - -static inline uint64_t getData64(SFSample *sample); - -static void writeCountersLine(SFSample *sample); - -static void receiveError(SFSample *sample, char *errm, int hexdump) __attribute__ ((noreturn)); - -static inline void skipBytes(SFSample *sample, int skip); - -static inline uint32_t sf_log_next32(SFSample *sample, char *fieldName); - -static inline uint64_t sf_log_next64(SFSample *sample, char *fieldName); - -static inline void sf_log_percentage(SFSample *sample, char *fieldName); - -static inline uint32_t getString(SFSample *sample, char *buf, int bufLen); - -static inline uint32_t getAddress(SFSample *sample, SFLAddress *address); - -static inline void skipTLVRecord(SFSample *sample, uint32_t tag, uint32_t len, char *description); - -static inline void readSFlowDatagram(SFSample *sample, FlowSource_t *fs); - -static inline void readFlowSample(SFSample *sample, int expanded, FlowSource_t *fs); - -static inline void readCountersSample(SFSample *sample, int expanded, FlowSource_t *fs); - -static inline void readFlowSample_v2v4(SFSample *sample, FlowSource_t *fs); - -static inline void readCountersSample_v2v4(SFSample *sample, FlowSource_t *fs); - -static inline void StoreSflowRecord(SFSample *sample, FlowSource_t *fs); - -extern int verbose; - -#ifdef DEVEL -static inline char *printTag(uint32_t tag, char *buf, int bufLen); - -static inline char *printTag(uint32_t tag, char *buf, int bufLen) { - snprintf(buf, bufLen, "%u:%u", (tag >> 12), (tag & 0x00000FFF)); - return buf; -} // End of printTag - -#endif - - -/*_________________---------------------------__________________ - _________________ printHex __________________ - -----------------___________________________------------------ -*/ - -static u_char bin2hex(int nib) { return (nib < 10) ? ('0' + nib) : ('A' - 10 + nib); } - -static int printHex(const u_char *a, int len, char *buf, int bufLen, int marker, int bytesPerOutputLine) { - int b = 0, i = 0; - for(; i < len; i++) { - u_char byte; - if(b > (bufLen - 10)) break; - if(marker > 0 && i == marker) { - buf[b++] = '<'; - buf[b++] = '*'; - buf[b++] = '>'; - buf[b++] = '-'; - } - byte = a[i]; - buf[b++] = bin2hex(byte >> 4); - buf[b++] = bin2hex(byte & 0x0f); - if(i > 0 && (i % bytesPerOutputLine) == 0) buf[b++] = '\n'; - else { - // separate the bytes with a dash - if (i < (len - 1)) buf[b++] = '-'; - } - } - buf[b] = '\0'; - return b; -} - -/*_________________---------------------------__________________ - _________________ IP_to_a __________________ - -----------------___________________________------------------ -*/ - -static char *IP_to_a(uint32_t ipaddr, char *buf, int buflen) { - u_char *ip = (u_char *)&ipaddr; - snprintf(buf, buflen, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); - buf[buflen-1] = '\0'; - return buf; -} - -static char *printAddress(SFLAddress *address, char *buf, int bufLen) { - if(address->type == SFLADDRESSTYPE_IP_V4) - IP_to_a(address->address.ip_v4.s_addr, buf, bufLen); - else { - u_char *b = address->address.ip_v6.s6_addr; - snprintf(buf, bufLen, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", - b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7],b[8],b[9],b[10],b[11],b[12],b[13],b[14],b[15]); - } - return buf; -} - -/*_________________---------------------------__________________ - _________________ writeFlowLine __________________ - -----------------___________________________------------------ -*/ - -static void writeFlowLine(SFSample *sample) { -char agentIP[51], srcIP[51], dstIP[51]; - // source - printf("FLOW,%s,%d,%d,", - printAddress(&sample->agent_addr, agentIP, 50), - sample->inputPort, - sample->outputPort); - // layer 2 - printf("%02x%02x%02x%02x%02x%02x,%02x%02x%02x%02x%02x%02x,0x%04x,%d,%d", - sample->eth_src[0], - sample->eth_src[1], - sample->eth_src[2], - sample->eth_src[3], - sample->eth_src[4], - sample->eth_src[5], - sample->eth_dst[0], - sample->eth_dst[1], - sample->eth_dst[2], - sample->eth_dst[3], - sample->eth_dst[4], - sample->eth_dst[5], - sample->eth_type, - sample->in_vlan, - sample->out_vlan); - // layer 3/4 - printf(",IP: %s,%s,%d,0x%02x,%d,%d,%d,0x%02x", - IP_to_a(sample->dcd_srcIP.s_addr, srcIP, 51), - IP_to_a(sample->dcd_dstIP.s_addr, dstIP, 51), - sample->dcd_ipProtocol, - sample->dcd_ipTos, - sample->dcd_ipTTL, - sample->dcd_sport, - sample->dcd_dport, - sample->dcd_tcpFlags); - // bytes - printf(",%d,%d,%d\n", - sample->sampledPacketSize, - sample->sampledPacketSize - sample->stripped - sample->offsetToIPV4, - sample->meanSkipCount); -} - -/*_________________---------------------------__________________ - _________________ writeCountersLine __________________ - -----------------___________________________------------------ -*/ - -static void writeCountersLine(SFSample *sample) -{ - // source - char agentIP[51]; - printf("CNTR,%s,", printAddress(&sample->agent_addr, agentIP, 50)); - printf("%u,%u,%llu,%u,%u,%llu,%u,%u,%u,%u,%u,%u,%llu,%u,%u,%u,%u,%u,%u\n", - sample->ifCounters.ifIndex, - sample->ifCounters.ifType, - (unsigned long long)sample->ifCounters.ifSpeed, - sample->ifCounters.ifDirection, - sample->ifCounters.ifStatus, - (unsigned long long)sample->ifCounters.ifInOctets, - sample->ifCounters.ifInUcastPkts, - sample->ifCounters.ifInMulticastPkts, - sample->ifCounters.ifInBroadcastPkts, - sample->ifCounters.ifInDiscards, - sample->ifCounters.ifInErrors, - sample->ifCounters.ifInUnknownProtos, - (unsigned long long)sample->ifCounters.ifOutOctets, - sample->ifCounters.ifOutUcastPkts, - sample->ifCounters.ifOutMulticastPkts, - sample->ifCounters.ifOutBroadcastPkts, - sample->ifCounters.ifOutDiscards, - sample->ifCounters.ifOutErrors, - sample->ifCounters.ifPromiscuousMode); -} - -/*_________________---------------------------__________________ - _________________ receiveError __________________ - -----------------___________________________------------------ -*/ - -static void receiveError(SFSample *sample, char *errm, int hexdump) -{ - char ipbuf[51]; - char scratch[6000]; - char *msg = ""; - char *hex = ""; - uint32_t markOffset = (u_char *)sample->datap - sample->rawSample; - if(errm) msg = errm; - if(hexdump) { - printHex(sample->rawSample, sample->rawSampleLen, scratch, 6000, markOffset, 16); - hex = scratch; - } - LogError("SFLOW: %s (source IP = %s) %s", msg, IP_to_a(sample->sourceIP.s_addr, ipbuf, 51), hex); - - SFABORT(sample, SF_ABORT_DECODE_ERROR); - -} - -/*_________________---------------------------__________________ - _________________ lengthCheck __________________ - -----------------___________________________------------------ -*/ - -static void lengthCheck(SFSample *sample, char *description, u_char *start, int len) { - uint32_t actualLen = (u_char *)sample->datap - start; - uint32_t adjustedLen = ((len + 3) >> 2) << 2; - if(actualLen != adjustedLen) { - dbg_printf("%s length error (expected %d, found %d)\n", description, len, actualLen); - LogError("SFLOW: %s length error (expected %d, found %d)", description, len, actualLen); - SFABORT(sample, SF_ABORT_LENGTH_ERROR); - } - -} - -/*_________________---------------------------__________________ - _________________ decodeLinkLayer __________________ - -----------------___________________________------------------ - store the offset to the start of the ipv4 header in the sequence_number field - or -1 if not found. Decode the 802.1d if it's there. -*/ - -#define NFT_ETHHDR_SIZ 14 -#define NFT_8022_SIZ 3 -#define NFT_MAX_8023_LEN 1500 - -#define NFT_MIN_SIZ (NFT_ETHHDR_SIZ + sizeof(struct myiphdr)) - -static void decodeLinkLayer(SFSample *sample) -{ - u_char *start = (u_char *)sample->header; - u_char *end = start + sample->headerLen; - u_char *ptr = start; - uint16_t type_len; - - /* assume not found */ - sample->gotIPV4 = NO; - - if(sample->headerLen < NFT_ETHHDR_SIZ) return; /* not enough for an Ethernet header */ - - dbg_printf("dstMAC %02x%02x%02x%02x%02x%02x\n", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); - memcpy(sample->eth_dst, ptr, 6); - ptr += 6; - - dbg_printf("srcMAC %02x%02x%02x%02x%02x%02x\n", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); - memcpy(sample->eth_src, ptr, 6); - ptr += 6; - type_len = (ptr[0] << 8) + ptr[1]; - ptr += 2; - - if(type_len == 0x8100) { - /* VLAN - next two bytes */ - uint32_t vlanData = (ptr[0] << 8) + ptr[1]; - uint32_t vlan = vlanData & 0x0fff; -#ifdef DEVEL - uint32_t priority = vlanData >> 13; -#endif - ptr += 2; - /* _____________________________________ */ - /* | pri | c | vlan-id | */ - /* ------------------------------------- */ - /* [priority = 3bits] [Canonical Format Flag = 1bit] [vlan-id = 12 bits] */ - dbg_printf("decodedVLAN %u\n", vlan); - dbg_printf("decodedPriority %u\n", priority); - sample->in_vlan = vlan; - /* now get the type_len again (next two bytes) */ - type_len = (ptr[0] << 8) + ptr[1]; - ptr += 2; - } - - /* now we're just looking for IP */ - if(sample->headerLen < NFT_MIN_SIZ) return; /* not enough for an IPv4 header */ - - /* peek for IPX */ - if(type_len == 0x0200 || type_len == 0x0201 || type_len == 0x0600) { -#define IPX_HDR_LEN 30 -#define IPX_MAX_DATA 546 - int ipxChecksum = (ptr[0] == 0xff && ptr[1] == 0xff); - int ipxLen = (ptr[2] << 8) + ptr[3]; - if(ipxChecksum && - ipxLen >= IPX_HDR_LEN && - ipxLen <= (IPX_HDR_LEN + IPX_MAX_DATA)) - /* we don't do anything with IPX here */ - return; - } - - if(type_len <= NFT_MAX_8023_LEN) { - /* assume 802.3+802.2 header */ - /* check for SNAP */ - if(ptr[0] == 0xAA && - ptr[1] == 0xAA && - ptr[2] == 0x03) { - ptr += 3; - if(ptr[0] != 0 || - ptr[1] != 0 || - ptr[2] != 0) { - dbg_printf("VSNAP_OUI %02X-%02X-%02X\n", ptr[0], ptr[1], ptr[2]); - return; /* no further decode for vendor-specific protocol */ - } - ptr += 3; - /* OUI == 00-00-00 means the next two bytes are the ethernet type (RFC 2895) */ - type_len = (ptr[0] << 8) + ptr[1]; - ptr += 2; - } - else { - if (ptr[0] == 0x06 && - ptr[1] == 0x06 && - (ptr[2] & 0x01)) { - /* IP over 8022 */ - ptr += 3; - /* force the type_len to be IP so we can inline the IP decode below */ - type_len = 0x0800; - } - else return; - } - } - - /* assume type_len is an ethernet-type now */ - sample->eth_type = type_len; - - if(type_len == 0x0800) { - /* IPV4 */ - if((end - ptr) < sizeof(struct myiphdr)) return; - /* look at first byte of header.... */ - /* ___________________________ */ - /* | version | hdrlen | */ - /* --------------------------- */ - if((*ptr >> 4) != 4) return; /* not version 4 */ - if((*ptr & 15) < 5) return; /* not IP (hdr len must be 5 quads or more) */ - /* survived all the tests - store the offset to the start of the ip header */ - sample->gotIPV4 = YES; - sample->offsetToIPV4 = (ptr - start); - } - - if(type_len == 0x86DD) { - /* IPV6 */ - /* look at first byte of header.... */ - if((*ptr >> 4) != 6) return; /* not version 6 */ - /* survived all the tests - store the offset to the start of the ip6 header */ - sample->gotIPV6 = YES; - sample->offsetToIPV6 = (ptr - start); - } -} - - -/*_________________---------------------------__________________ - _________________ decodeIPLayer4 __________________ - -----------------___________________________------------------ -*/ - -static void decodeIPLayer4(SFSample *sample, u_char *ptr, uint32_t ipProtocol) { - u_char *end = sample->header + sample->headerLen; - if(ptr > (end - 8)) return; // not enough header bytes left - switch(ipProtocol) { - case 1: /* ICMP */ - case 58: /* ICMP6 */ - { - struct myicmphdr icmp; - memcpy(&icmp, ptr, sizeof(icmp)); - dbg_printf("ICMPType %u\n", icmp.type); - dbg_printf("ICMPCode %u\n", icmp.code); - sample->dcd_sport = icmp.type; - sample->dcd_dport = icmp.code; - } - break; - case 6: /* TCP */ - { - struct mytcphdr tcp; - memcpy(&tcp, ptr, sizeof(tcp)); - sample->dcd_sport = ntohs(tcp.th_sport); - sample->dcd_dport = ntohs(tcp.th_dport); - sample->dcd_tcpFlags = tcp.th_flags; - dbg_printf("TCPSrcPort %u\n", sample->dcd_sport); - dbg_printf("TCPDstPort %u\n",sample->dcd_dport); - dbg_printf("TCPFlags %u\n", sample->dcd_tcpFlags); - if(sample->dcd_dport == 80) { - int bytesLeft; - int headerBytes = (tcp.th_off_and_unused >> 4) * 4; - ptr += headerBytes; - bytesLeft = sample->header + sample->headerLen - ptr; - } - } - break; - case 17: /* UDP */ - { - struct myudphdr udp; - memcpy(&udp, ptr, sizeof(udp)); - sample->dcd_sport = ntohs(udp.uh_sport); - sample->dcd_dport = ntohs(udp.uh_dport); - sample->udp_pduLen = ntohs(udp.uh_ulen); - dbg_printf("UDPSrcPort %u\n", sample->dcd_sport); - dbg_printf("UDPDstPort %u\n", sample->dcd_dport); - dbg_printf("UDPBytes %u\n", sample->udp_pduLen); - } - break; - default: /* some other protcol */ - break; - } -} - -/*_________________---------------------------__________________ - _________________ decodeIPV4 __________________ - -----------------___________________________------------------ -*/ - -static void decodeIPV4(SFSample *sample) -{ - if(sample->gotIPV4) { -#ifdef DEVEL - char buf[51]; -#endif - u_char *ptr = sample->header + sample->offsetToIPV4; - /* Create a local copy of the IP header (cannot overlay structure in case it is not quad-aligned...some - platforms would core-dump if we tried that). It's OK coz this probably performs just as well anyway. */ - struct myiphdr ip; - memcpy(&ip, ptr, sizeof(ip)); - /* Value copy all ip elements into sample */ - sample->dcd_srcIP.s_addr = ip.saddr; - sample->dcd_dstIP.s_addr = ip.daddr; - sample->dcd_ipProtocol = ip.protocol; - sample->dcd_ipTos = ip.tos; - sample->dcd_ipTTL = ip.ttl; - dbg_printf("ip.tot_len %d\n", ntohs(ip.tot_len)); - /* Log out the decoded IP fields */ - dbg_printf("srcIP %s\n", IP_to_a(sample->dcd_srcIP.s_addr, buf, 51)); - dbg_printf("dstIP %s\n", IP_to_a(sample->dcd_dstIP.s_addr, buf, 51)); - dbg_printf("IPProtocol %u\n", sample->dcd_ipProtocol); - dbg_printf("IPTOS %u\n", sample->dcd_ipTos); - dbg_printf("IPTTL %u\n", sample->dcd_ipTTL); - /* check for fragments */ - sample->ip_fragmentOffset = ntohs(ip.frag_off) & 0x1FFF; - if(sample->ip_fragmentOffset > 0) { - dbg_printf("IPFragmentOffset %u\n", sample->ip_fragmentOffset); - } - else { - dbg_printf("Unfragmented\n"); - /* advance the pointer to the next protocol layer */ - /* ip headerLen is expressed as a number of quads */ - ptr += (ip.version_and_headerLen & 0x0f) * 4; - decodeIPLayer4(sample, ptr, ip.protocol); - } - } -} - -/*_________________---------------------------__________________ - _________________ decodeIPV6 __________________ - -----------------___________________________------------------ -*/ - -static void decodeIPV6(SFSample *sample) -{ - uint16_t payloadLen; - uint32_t label; - uint32_t nextHeader; - u_char *end = sample->header + sample->headerLen; - - if(sample->gotIPV6) { - u_char *ptr = sample->header + sample->offsetToIPV6; - - // check the version - { - int ipVersion = (*ptr >> 4); - if(ipVersion != 6) { - dbg_printf("header decode error: unexpected IP version: %d\n", ipVersion); - return; - } - } - - // get the tos (priority) - sample->dcd_ipTos = *ptr++ & 15; - dbg_printf("IPTOS %u\n", sample->dcd_ipTos); - // 24-bit label - label = *ptr++; - label <<= 8; - label += *ptr++; - label <<= 8; - label += *ptr++; - dbg_printf("IP6_label 0x%x\n", label); - // payload - payloadLen = (ptr[0] << 8) + ptr[1]; - ptr += 2; - // if payload is zero, that implies a jumbo payload - if(payloadLen == 0) dbg_printf("IPV6_payloadLen \n"); - else dbg_printf("IPV6_payloadLen %u\n", payloadLen); - - // next header - nextHeader = *ptr++; - - // TTL - sample->dcd_ipTTL = *ptr++; - dbg_printf("IPTTL %u\n", sample->dcd_ipTTL); - - {// src and dst address -#ifdef DEVEL - char buf[101]; -#endif - sample->ipsrc.type = SFLADDRESSTYPE_IP_V6; - memcpy(&sample->ipsrc.address, ptr, 16); - ptr +=16; - dbg_printf("srcIP6 %s\n", printAddress(&sample->ipsrc, buf, 100)); - sample->ipdst.type = SFLADDRESSTYPE_IP_V6; - memcpy(&sample->ipdst.address, ptr, 16); - ptr +=16; - dbg_printf("dstIP6 %s\n", printAddress(&sample->ipdst, buf, 100)); - } - - // skip over some common header extensions... - // http://searchnetworking.techtarget.com/originalContent/0,289142,sid7_gci870277,00.html - while(nextHeader == 0 || // hop - nextHeader == 43 || // routing - nextHeader == 44 || // fragment - // nextHeader == 50 || // encryption - don't bother coz we'll not be able to read any further - nextHeader == 51 || // auth - nextHeader == 60) { // destination options - uint32_t optionLen, skip; - dbg_printf("IP6HeaderExtension: %d\n", nextHeader); - nextHeader = ptr[0]; - optionLen = 8 * (ptr[1] + 1); // second byte gives option len in 8-byte chunks, not counting first 8 - skip = optionLen - 2; - ptr += skip; - if(ptr > end) return; // ran off the end of the header - } - - // now that we have eliminated the extension headers, nextHeader should have what we want to - // remember as the ip protocol... - sample->dcd_ipProtocol = nextHeader; - dbg_printf("IPProtocol %u\n", sample->dcd_ipProtocol); - decodeIPLayer4(sample, ptr, sample->dcd_ipProtocol); - } -} - - -#include "inline.c" -#include "nffile_inline.c" -#include "collector_inline.c" - -/*_________________---------------------------__________________ - _________________ StoreSflowRecord __________________ - -----------------___________________________------------------ -*/ - -static inline void StoreSflowRecord(SFSample *sample, FlowSource_t *fs) { -common_record_t *common_record; -stat_record_t *stat_record = fs->nffile->stat_record; -exporter_sflow_t *exporter; -extension_map_t *extension_map; -struct timeval now; -void *next_data; -value32_t *val; -uint32_t bytes, j, id, ipsize, ip_flags; -uint64_t _bytes, _packets, _t; // tmp buffers - - dbg_printf("StoreSflowRecord\n"); - - gettimeofday(&now, NULL); - - if( sample->ip_fragmentOffset > 0 ) { - sample->dcd_sport = 0; - sample->dcd_dport = 0; - } - - bytes = sample->sampledPacketSize; - - ip_flags = 0; - if ( sample->nextHop.type == SFLADDRESSTYPE_IP_V6 ) - SetFlag(ip_flags, SFLOW_NEXT_HOP); - - if ( sample->bgp_nextHop.type == SFLADDRESSTYPE_IP_V6 ) - SetFlag(ip_flags, SFLOW_NEXT_HOP_BGP); - - if ( fs->sa_family == AF_INET6 ) - SetFlag(ip_flags, SFLOW_ROUTER_IP); - - ip_flags &= IP_extension_mask; - - if ( ip_flags >= MAX_SFLOW_EXTENSIONS ) { - LogError("SFLOW: Corrupt ip_flags: %u", ip_flags); - } - exporter = GetExporter(fs, sample->agentSubId, sample->meanSkipCount); - if ( !exporter ) { - LogError("SFLOW: Exporter NULL: Abort sflow record processing"); - return; - } - exporter->packets++; - - // get appropriate extension map - extension_map = exporter->sflow_extension_info[ip_flags].map; - if ( !extension_map ) { - LogInfo("SFLOW: setup extension map: %u", ip_flags); - if ( !Setup_Extension_Info(fs, exporter, ip_flags ) ) { - LogError("SFLOW: Extension map: NULL: Abort sflow record processing"); - return; - } - extension_map = exporter->sflow_extension_info[ip_flags].map; - LogInfo("SFLOW: setup extension map: %u done", ip_flags); - } - - // output buffer size check - // IPv6 needs 2 x 16 bytes, IPv4 2 x 4 bytes - ipsize = sample->gotIPV6 ? 32 : 8; - if ( !CheckBufferSpace(fs->nffile, sflow_output_record_size[ip_flags] + ipsize )) { - // fishy! - should never happen. maybe disk full? - LogError("SFLOW: output buffer size error. Abort sflow record processing"); - return; - } - - dbg_printf("Fill Record\n"); - common_record = (common_record_t *)fs->nffile->buff_ptr; - - common_record->size = sflow_output_record_size[ip_flags] + ipsize; - common_record->type = CommonRecordType; - common_record->flags = 0; - SetFlag(common_record->flags, FLAG_SAMPLED); - - common_record->exporter_sysid = exporter->info.sysid; - common_record->ext_map = extension_map->map_id; - - common_record->first = now.tv_sec; - common_record->last = common_record->first; - common_record->msec_first = now.tv_usec / 1000; - common_record->msec_last = common_record->msec_first; - _t = 1000LL * now.tv_sec + common_record->msec_first; // tmp buff for first_seen - - common_record->fwd_status = 0; - common_record->reserved = 0; - common_record->tcp_flags = sample->dcd_tcpFlags; - common_record->prot = sample->dcd_ipProtocol; - common_record->tos = sample->dcd_ipTos; - common_record->srcport = (uint16_t)sample->dcd_sport; - common_record->dstport = (uint16_t)sample->dcd_dport; - - if(sample->gotIPV6) { - u_char *b; - uint64_t *u; - ipv6_block_t *ipv6 = (ipv6_block_t *)common_record->data; - SetFlag(common_record->flags, FLAG_IPV6_ADDR); - - b = sample->ipsrc.address.ip_v6.s6_addr; - u = (uint64_t *)b; - ipv6->srcaddr[0] = ntohll(*u); - u = (uint64_t *)&(b[8]); - ipv6->srcaddr[1] = ntohll(*u); - - b = sample->ipdst.address.ip_v6.s6_addr; - u = (uint64_t *)b; - ipv6->dstaddr[0] = ntohll(*u); - u = (uint64_t *)&(b[8]); - ipv6->dstaddr[1] = ntohll(*u); - - next_data = (void *)ipv6->data; - } else { - ipv4_block_t *ipv4 = (ipv4_block_t *)common_record->data; - ipv4->srcaddr = ntohl(sample->dcd_srcIP.s_addr); - ipv4->dstaddr = ntohl(sample->dcd_dstIP.s_addr); - - next_data = (void *)ipv4->data; - } - - // 4 byte Packet value - val = (value32_t *)next_data; - val->val = sample->meanSkipCount; - _packets = val->val; - - // 4 byte Bytes value - val = (value32_t *)val->data; - val->val = sample->meanSkipCount * bytes; - _bytes = val->val; - - next_data = (void *)val->data; - - j = 0; - while ( (id = extension_map->ex_id[j]) != 0 ) { - switch (id) { - case EX_IO_SNMP_4: { // 4 byte input/output interface index - tpl_ext_5_t *tpl = (tpl_ext_5_t *)next_data; - tpl->input = sample->inputPort; - tpl->output = sample->outputPort; - next_data = (void *)tpl->data; - } break; - case EX_AS_4: { // 4 byte src/dst AS number - tpl_ext_7_t *tpl = (tpl_ext_7_t *)next_data; - tpl->src_as = sample->src_as; - tpl->dst_as = sample->dst_as; - next_data = (void *)tpl->data; - } break; - case EX_VLAN: { // 2 byte valn label - tpl_ext_13_t *tpl = (tpl_ext_13_t *)next_data; - tpl->src_vlan = sample->in_vlan; - tpl->dst_vlan = sample->out_vlan; - next_data = (void *)tpl->data; - } break; - case EX_MULIPLE: { // dst tos, direction, src/dst mask - tpl_ext_8_t *tpl = (tpl_ext_8_t *)next_data; - tpl->dst_tos = sample->dcd_ipTos; - tpl->dir = 0; - tpl->src_mask = sample->srcMask; - tpl->dst_mask = sample->dstMask; - next_data = (void *)tpl->data; - } break; - case EX_MAC_1: { // MAC addreses - tpl_ext_20_t *tpl = (tpl_ext_20_t *)next_data; - tpl->in_src_mac = Get_val48((void *)&sample->eth_src); - tpl->out_dst_mac = Get_val48((void *)&sample->eth_dst); - next_data = (void *)tpl->data; - } break; - case EX_NEXT_HOP_v4: { // next hop IPv4 router address - tpl_ext_9_t *tpl = (tpl_ext_9_t *)next_data; - if ( sample->nextHop.type == SFLADDRESSTYPE_IP_V4 ) { - tpl->nexthop = ntohl(sample->nextHop.address.ip_v4.s_addr); - } else { - tpl->nexthop = 0; - } - next_data = (void *)tpl->data; - } break; - case EX_NEXT_HOP_v6: { // next hop IPv6 router address - tpl_ext_10_t *tpl = (tpl_ext_10_t *)next_data; - void *ptr = (void *)sample->nextHop.address.ip_v6.s6_addr; - if ( sample->nextHop.type == SFLADDRESSTYPE_IP_V6 ) { - tpl->nexthop[0] = ntohll(((uint64_t *)ptr)[0]); - tpl->nexthop[1] = ntohll(((uint64_t *)ptr)[1]); - } else { - tpl->nexthop[0] = 0; - tpl->nexthop[1] = 0; - } - SetFlag(common_record->flags, FLAG_IPV6_NH); - next_data = (void *)tpl->data; - } break; - case EX_NEXT_HOP_BGP_v4: { // next hop bgp IPv4 router address - tpl_ext_11_t *tpl = (tpl_ext_11_t *)next_data; - if ( sample->bgp_nextHop.type == SFLADDRESSTYPE_IP_V4 ) { - tpl->bgp_nexthop = ntohl(sample->bgp_nextHop.address.ip_v4.s_addr); - } else { - tpl->bgp_nexthop = 0; - } - next_data = (void *)tpl->data; - } break; - case EX_NEXT_HOP_BGP_v6: { // next hop IPv4 router address - tpl_ext_12_t *tpl = (tpl_ext_12_t *)next_data; - void *ptr = (void *)sample->bgp_nextHop.address.ip_v6.s6_addr; - if ( sample->bgp_nextHop.type == SFLADDRESSTYPE_IP_V6 ) { - tpl->bgp_nexthop[0] = ntohll(((uint64_t *)ptr)[0]); - tpl->bgp_nexthop[1] = ntohll(((uint64_t *)ptr)[1]); - } else { - tpl->bgp_nexthop[0] = 0; - tpl->bgp_nexthop[1] = 0; - } - SetFlag(common_record->flags, FLAG_IPV6_NHB); - next_data = (void *)tpl->data; - } break; - case EX_ROUTER_IP_v4: - case EX_ROUTER_IP_v6: // IPv4/IPv6 router address - if(sample->agent_addr.type == SFLADDRESSTYPE_IP_V4) { - tpl_ext_23_t *tpl = (tpl_ext_23_t *)next_data; - tpl->router_ip = ntohl(sample->agent_addr.address.ip_v4.s_addr); - next_data = (void *)tpl->data; - ClearFlag(common_record->flags, FLAG_IPV6_EXP); - } else { - tpl_ext_24_t *tpl = (tpl_ext_24_t *)next_data; - void *ptr = (void *)sample->agent_addr.address.ip_v6.s6_addr; - tpl->router_ip[0] = ntohll(((uint64_t *)ptr)[0]); - tpl->router_ip[1] = ntohll(((uint64_t *)ptr)[1]); - next_data = (void *)tpl->data; - SetFlag(common_record->flags, FLAG_IPV6_EXP); - } - break; - case EX_RECEIVED: { - tpl_ext_27_t *tpl = (tpl_ext_27_t *)next_data; - tpl->received = (uint64_t)((uint64_t)fs->received.tv_sec * 1000LL) + (uint64_t)((uint64_t)fs->received.tv_usec / 1000LL); - next_data = (void *)tpl->data; - } break; - default: - // this should never happen - LogError("SFLOW: Unexpected extension %i for sflow record. Skip extension", id); - dbg_printf("SFLOW: Unexpected extension %i for sflow record. Skip extension", id); - } - j++; - } - -/* - if(sfConfig.netFlowPeerAS) { - pkt.flow.srcAS = htons((uint16_t)sample->src_peer_as); - pkt.flow.dstAS = htons((uint16_t)sample->dst_peer_as); - } - else { - pkt.flow.srcAS = htons((uint16_t)sample->src_as); - pkt.flow.dstAS = htons((uint16_t)sample->dst_as); - } -*/ - - // update first_seen, last_seen - if ( _t < fs->first_seen ) // the very first time stamp need to be set - fs->first_seen = _t; - fs->last_seen = _t; - - // Update stats - switch (common_record->prot) { - case 1: - stat_record->numflows_icmp++; - stat_record->numpackets_icmp += _packets; - stat_record->numbytes_icmp += _bytes; - break; - case 6: - stat_record->numflows_tcp++; - stat_record->numpackets_tcp += _packets; - stat_record->numbytes_tcp += _bytes; - break; - case 17: - stat_record->numflows_udp++; - stat_record->numpackets_udp += _packets; - stat_record->numbytes_udp += _bytes; - break; - default: - stat_record->numflows_other++; - stat_record->numpackets_other += _packets; - stat_record->numbytes_other += _bytes; - } - exporter->flows++; - stat_record->numflows++; - stat_record->numpackets += _packets; - stat_record->numbytes += _bytes; - - if ( verbose ) { - master_record_t master_record; - char *string; - ExpandRecord_v2((common_record_t *)common_record, &exporter->sflow_extension_info[ip_flags], &(exporter->info), &master_record); - format_file_block_record(&master_record, &string, 0); - printf("%s\n", string); - } - - // update file record size ( -> output buffer size ) - fs->nffile->block_header->NumRecords++; - fs->nffile->block_header->size += (sflow_output_record_size[ip_flags] + ipsize); -#ifdef DEVEL - if ( (next_data - fs->nffile->buff_ptr) != (sflow_output_record_size[ip_flags] + ipsize) ) { - printf("PANIC: Size error. Buffer diff: %llu, Size: %u\n", - (unsigned long long)(next_data - fs->nffile->buff_ptr), - (sflow_output_record_size[ip_flags] + ipsize)); - exit(255); - } -#endif - fs->nffile->buff_ptr = next_data; - -} - -/*_________________---------------------------__________________ - _________________ read data fns __________________ - -----------------___________________________------------------ -*/ - -static inline uint32_t getData32(SFSample *sample) { - if ((u_char *)sample->datap > sample->endp) - SFABORT(sample, SF_ABORT_EOS); - return ntohl(*(sample->datap)++); -} // End of getData32 - -static inline uint32_t getData32_nobswap(SFSample *sample) { - if ((u_char *)sample->datap > sample->endp) - SFABORT(sample, SF_ABORT_EOS); - return *(sample->datap)++; -} // End of getData32_nobswap - -static inline uint64_t getData64(SFSample *sample) { -uint64_t tmpLo, tmpHi; - - tmpHi = getData32(sample); - tmpLo = getData32(sample); - return (tmpHi << 32) + tmpLo; -} // End of getData64 - -static inline void skipBytes(SFSample *sample, int skip) { -int quads = (skip + 3) / 4; - - sample->datap += quads; - if ( (u_char *)sample->datap > sample->endp) - SFABORT(sample, SF_ABORT_EOS); -} // End of skipBytes - -static inline uint32_t sf_log_next32(SFSample *sample, char *fieldName) { -uint32_t val = getData32(sample); - - dbg_printf("%s %u\n", fieldName, val); - return val; -} // End of sf_log_next32 - -static inline uint64_t sf_log_next64(SFSample *sample, char *fieldName) { -uint64_t val64 = getData64(sample); - - dbg_printf("%s %llu\n", fieldName, (unsigned long long)val64); - return val64; -} // End of sf_log_next64 - -static inline void sf_log_percentage(SFSample *sample, char *fieldName) { -uint32_t hundredths = getData32(sample); - - if ( hundredths == (uint32_t)-1) - dbg_printf("%s unknown\n", fieldName); - else { -#ifdef DEVEL - float percent = (float)hundredths / 10.0; -#endif - dbg_printf("%s %.1f\n", fieldName, percent); - } -} // End of sf_log_percentage - - -static inline uint32_t getString(SFSample *sample, char *buf, int bufLen) { -uint32_t len, read_len; - - len = getData32(sample); - // truncate if too long - read_len = (len >= bufLen) ? (bufLen - 1) : len; - memcpy(buf, sample->datap, read_len); - buf[read_len] = '\0'; // null terminate - skipBytes(sample, len); - return len; -} // End of getString - -static inline uint32_t getAddress(SFSample *sample, SFLAddress *address) { - - address->type = getData32(sample); - if(address->type == SFLADDRESSTYPE_IP_V4) - address->address.ip_v4.s_addr = getData32_nobswap(sample); - else { - memcpy(&address->address.ip_v6.s6_addr, sample->datap, 16); - skipBytes(sample, 16); - } - return address->type; -} // End of getAddress - -static inline void skipTLVRecord(SFSample *sample, uint32_t tag, uint32_t len, char *description) { - -#ifdef DEVEL - char buf[51]; - snprintf(buf, 50, "%u:%u", (tag >> 12), (tag & 0x00000FFF)); - printf("skipping unknown %s: 0x%x, %s len=%d\n", description, tag, buf, len); -#endif - - skipBytes(sample, len); -} // End of skipTLVRecord - -/*_________________---------------------------__________________ - _________________ readExtendedSwitch __________________ - -----------------___________________________------------------ -*/ - -static void readExtendedSwitch(SFSample *sample) -{ - dbg_printf("extendedType SWITCH\n"); - sample->in_vlan = getData32(sample); - sample->in_priority = getData32(sample); - sample->out_vlan = getData32(sample); - sample->out_priority = getData32(sample); - - sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_SWITCH; - - dbg_printf("in_vlan %u\n", sample->in_vlan); - dbg_printf("in_priority %u\n", sample->in_priority); - dbg_printf("out_vlan %u\n", sample->out_vlan); - dbg_printf("out_priority %u\n", sample->out_priority); -} - -/*_________________---------------------------__________________ - _________________ readExtendedRouter __________________ - -----------------___________________________------------------ -*/ - -static void readExtendedRouter(SFSample *sample) -{ -#ifdef DEVEL -char buf[51]; -#endif - - dbg_printf("extendedType ROUTER\n"); - getAddress(sample, &sample->nextHop); - sample->srcMask = getData32(sample); - sample->dstMask = getData32(sample); - - sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_ROUTER; - - dbg_printf("nextHop %s\n", printAddress(&sample->nextHop, buf, 50)); - dbg_printf("srcSubnetMask %u\n", sample->srcMask); - dbg_printf("dstSubnetMask %u\n", sample->dstMask); -} - -/*_________________---------------------------__________________ - _________________ readExtendedGateway_v2 __________________ - -----------------___________________________------------------ -*/ - -static void readExtendedGateway_v2(SFSample *sample) -{ - dbg_printf("extendedType GATEWAY\n"); - - sample->my_as = getData32(sample); - sample->src_as = getData32(sample); - sample->src_peer_as = getData32(sample); - sample->dst_as_path_len = getData32(sample); - /* just point at the dst_as_path array */ - if(sample->dst_as_path_len > 0) { - sample->dst_as_path = sample->datap; - /* and skip over it in the input */ - skipBytes(sample, sample->dst_as_path_len * 4); - // fill in the dst and dst_peer fields too - sample->dst_peer_as = ntohl(sample->dst_as_path[0]); - sample->dst_as = ntohl(sample->dst_as_path[sample->dst_as_path_len - 1]); - } - - sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_GATEWAY; - - dbg_printf("my_as %u\n", sample->my_as); - dbg_printf("src_as %u\n", sample->src_as); - dbg_printf("src_peer_as %u\n", sample->src_peer_as); - dbg_printf("dst_as %u\n", sample->dst_as); - dbg_printf("dst_peer_as %u\n", sample->dst_peer_as); - dbg_printf("dst_as_path_len %u\n", sample->dst_as_path_len); - if(sample->dst_as_path_len > 0) { - uint32_t i = 0; - for(; i < sample->dst_as_path_len; i++) { - if(i == 0) dbg_printf("dst_as_path "); - else dbg_printf("-"); - dbg_printf("%u", ntohl(sample->dst_as_path[i])); - } - dbg_printf("\n"); - } -} - -/*_________________---------------------------__________________ - _________________ readExtendedGateway __________________ - -----------------___________________________------------------ -*/ - -static void readExtendedGateway(SFSample *sample) -{ -#ifdef DEVEL - char buf[51]; -#endif - uint32_t segments; - int seg; - - dbg_printf("extendedType GATEWAY\n"); - - if(sample->datagramVersion >= 5) { - getAddress(sample, &sample->bgp_nextHop); - dbg_printf("bgp_nexthop %s\n", printAddress(&sample->bgp_nextHop, buf, 50)); - } - - sample->my_as = getData32(sample); - sample->src_as = getData32(sample); - sample->src_peer_as = getData32(sample); - dbg_printf("my_as %u\n", sample->my_as); - dbg_printf("src_as %u\n", sample->src_as); - dbg_printf("src_peer_as %u\n", sample->src_peer_as); - segments = getData32(sample); - if(segments > 0) { - dbg_printf("dst_as_path "); - for(seg = 0; seg < segments; seg++) { - uint32_t seg_type; - uint32_t seg_len; - int i; - seg_type = getData32(sample); - seg_len = getData32(sample); - for(i = 0; i < seg_len; i++) { - uint32_t asNumber; - asNumber = getData32(sample); - /* mark the first one as the dst_peer_as */ - if(i == 0 && seg == 0) sample->dst_peer_as = asNumber; - else dbg_printf("-"); - /* make sure the AS sets are in parentheses */ - if(i == 0 && seg_type == SFLEXTENDED_AS_SET) dbg_printf("("); - dbg_printf("%u", asNumber); - /* mark the last one as the dst_as */ - if(seg == (segments - 1) && i == (seg_len - 1)) sample->dst_as = asNumber; - } - if(seg_type == SFLEXTENDED_AS_SET) dbg_printf(")"); - } - dbg_printf("\n"); - } - dbg_printf("dst_as %u\n", sample->dst_as); - dbg_printf("dst_peer_as %u\n", sample->dst_peer_as); - - sample->communities_len = getData32(sample); - /* just point at the communities array */ - if(sample->communities_len > 0) sample->communities = sample->datap; - /* and skip over it in the input */ - skipBytes(sample, sample->communities_len * 4); - - sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_GATEWAY; - if(sample->communities_len > 0) { - int j = 0; - for(; j < sample->communities_len; j++) { - if(j == 0) dbg_printf("BGP_communities "); - else dbg_printf("-"); - dbg_printf("%u", ntohl(sample->communities[j])); - } - dbg_printf("\n"); - } - - sample->localpref = getData32(sample); - dbg_printf("BGP_localpref %u\n", sample->localpref); - -} - -/*_________________---------------------------__________________ - _________________ readExtendedUser __________________ - -----------------___________________________------------------ -*/ - -static void readExtendedUser(SFSample *sample) -{ - dbg_printf("extendedType USER\n"); - - if(sample->datagramVersion >= 5) { - sample->src_user_charset = getData32(sample); - dbg_printf("src_user_charset %d\n", sample->src_user_charset); - } - - sample->src_user_len = getString(sample, sample->src_user, SA_MAX_EXTENDED_USER_LEN); - - if(sample->datagramVersion >= 5) { - sample->dst_user_charset = getData32(sample); - dbg_printf("dst_user_charset %d\n", sample->dst_user_charset); - } - - sample->dst_user_len = getString(sample, sample->dst_user, SA_MAX_EXTENDED_USER_LEN); - - sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_USER; - - dbg_printf("src_user %s\n", sample->src_user); - dbg_printf("dst_user %s\n", sample->dst_user); -} - -/*_________________---------------------------__________________ - _________________ readExtendedUrl __________________ - -----------------___________________________------------------ -*/ - -static void readExtendedUrl(SFSample *sample) -{ - dbg_printf("extendedType URL\n"); - - sample->url_direction = getData32(sample); - dbg_printf("url_direction %u\n", sample->url_direction); - sample->url_len = getString(sample, sample->url, SA_MAX_EXTENDED_URL_LEN); - dbg_printf("url %s\n", sample->url); - if(sample->datagramVersion >= 5) { - sample->host_len = getString(sample, sample->host, SA_MAX_EXTENDED_HOST_LEN); - dbg_printf("host %s\n", sample->host); - } - sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_URL; -} - - -/*_________________---------------------------__________________ - _________________ mplsLabelStack __________________ - -----------------___________________________------------------ -*/ - -static void mplsLabelStack(SFSample *sample, char *fieldName) -{ - SFLLabelStack lstk; - uint32_t lab; - lstk.depth = getData32(sample); - /* just point at the lablelstack array */ - if(lstk.depth > 0) - lstk.stack = (uint32_t *)sample->datap; - else - lstk.stack = NULL; - /* and skip over it in the input */ - skipBytes(sample, lstk.depth * 4); - - if(lstk.depth > 0) { - int j = 0; - for(; j < lstk.depth; j++) { - if(j == 0) dbg_printf("%s ", fieldName); - else dbg_printf("-"); - lab = ntohl(lstk.stack[j]); - dbg_printf("%u.%u.%u.%u", - (lab >> 12), // label - (lab >> 9) & 7, // experimental - (lab >> 8) & 1, // bottom of stack - (lab & 255)); // TTL - } - dbg_printf("\n"); - } -} - -/*_________________---------------------------__________________ - _________________ readExtendedMpls __________________ - -----------------___________________________------------------ -*/ - -static void readExtendedMpls(SFSample *sample) -{ -#ifdef DEVEL - char buf[51]; -#endif - dbg_printf("extendedType MPLS\n"); - getAddress(sample, &sample->mpls_nextHop); - dbg_printf("mpls_nexthop %s\n", printAddress(&sample->mpls_nextHop, buf, 50)); - - mplsLabelStack(sample, "mpls_input_stack"); - mplsLabelStack(sample, "mpls_output_stack"); - - sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_MPLS; -} - -/*_________________---------------------------__________________ - _________________ readExtendedNat __________________ - -----------------___________________________------------------ -*/ - -static void readExtendedNat(SFSample *sample) -{ -#ifdef DEVEL - char buf[51]; -#endif - dbg_printf("extendedType NAT\n"); - getAddress(sample, &sample->nat_src); - dbg_printf("nat_src %s\n", printAddress(&sample->nat_src, buf, 50)); - getAddress(sample, &sample->nat_dst); - dbg_printf("nat_dst %s\n", printAddress(&sample->nat_dst, buf, 50)); - sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_NAT; -} - - -/*_________________---------------------------__________________ - _________________ readExtendedMplsTunnel __________________ - -----------------___________________________------------------ -*/ - -static void readExtendedMplsTunnel(SFSample *sample) -{ -#define SA_MAX_TUNNELNAME_LEN 100 - char tunnel_name[SA_MAX_TUNNELNAME_LEN+1]; - uint32_t tunnel_id, tunnel_cos; - - if(getString(sample, tunnel_name, SA_MAX_TUNNELNAME_LEN) > 0) - dbg_printf("mpls_tunnel_lsp_name %s\n", tunnel_name); - tunnel_id = getData32(sample); - dbg_printf("mpls_tunnel_id %u\n", tunnel_id); - tunnel_cos = getData32(sample); - dbg_printf("mpls_tunnel_cos %u\n", tunnel_cos); - sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_MPLS_TUNNEL; -} - -/*_________________---------------------------__________________ - _________________ readExtendedMplsVC __________________ - -----------------___________________________------------------ -*/ - -static void readExtendedMplsVC(SFSample *sample) -{ -#define SA_MAX_VCNAME_LEN 100 - char vc_name[SA_MAX_VCNAME_LEN+1]; - uint32_t vll_vc_id, vc_cos; - if(getString(sample, vc_name, SA_MAX_VCNAME_LEN) > 0) - dbg_printf("mpls_vc_name %s\n", vc_name); - vll_vc_id = getData32(sample); - dbg_printf("mpls_vll_vc_id %u\n", vll_vc_id); - vc_cos = getData32(sample); - dbg_printf("mpls_vc_cos %u\n", vc_cos); - sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_MPLS_VC; -} - -/*_________________---------------------------__________________ - _________________ readExtendedMplsFTN __________________ - -----------------___________________________------------------ -*/ - -static void readExtendedMplsFTN(SFSample *sample) -{ -#define SA_MAX_FTN_LEN 100 - char ftn_descr[SA_MAX_FTN_LEN+1]; - uint32_t ftn_mask; - if(getString(sample, ftn_descr, SA_MAX_FTN_LEN) > 0) - dbg_printf("mpls_ftn_descr %s\n", ftn_descr); - ftn_mask = getData32(sample); - dbg_printf("mpls_ftn_mask %u\n", ftn_mask); - sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_MPLS_FTN; -} - -/*_________________---------------------------__________________ - _________________ readExtendedMplsLDP_FEC __________________ - -----------------___________________________------------------ -*/ - -static void readExtendedMplsLDP_FEC(SFSample *sample) -{ -#ifdef DEVEL - uint32_t fec_addr_prefix_len = getData32(sample); -#endif - dbg_printf("mpls_fec_addr_prefix_len %u\n", fec_addr_prefix_len); - sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_MPLS_LDP_FEC; -} - -/*_________________---------------------------__________________ - _________________ readExtendedVlanTunnel __________________ - -----------------___________________________------------------ -*/ - -static void readExtendedVlanTunnel(SFSample *sample) -{ - uint32_t lab; - SFLLabelStack lstk; - lstk.depth = getData32(sample); - /* just point at the lablelstack array */ - if(lstk.depth > 0) - lstk.stack = (uint32_t *)sample->datap; - else - lstk.stack = NULL; - /* and skip over it in the input */ - skipBytes(sample, lstk.depth * 4); - - if(lstk.depth > 0) { - int j = 0; - for(; j < lstk.depth; j++) { - if(j == 0) dbg_printf("vlan_tunnel "); - else dbg_printf("-"); - lab = ntohl(lstk.stack[j]); - dbg_printf("0x%04x.%u.%u.%u", - (lab >> 16), // TPI - (lab >> 13) & 7, // priority - (lab >> 12) & 1, // CFI - (lab & 4095)); // VLAN - } - dbg_printf("\n"); - } - sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_VLAN_TUNNEL; -} - -/*_________________---------------------------__________________ - _________________ readExtendedProcess __________________ - -----------------___________________________------------------ -*/ - -static void readExtendedProcess(SFSample *sample) -{ - char pname[51]; - uint32_t num_processes, i; - dbg_printf("extendedType process\n"); - num_processes = getData32(sample); - for(i = 0; i < num_processes; i++) { -#ifdef DEVEL - uint32_t pid = getData32(sample); -#endif - if(getString(sample, pname, 50) > 0) dbg_printf("pid %u %s\n", pid, pname); - else dbg_printf("pid %u \n", pid); - } -} - -/*_________________---------------------------__________________ - _________________ readFlowSample_header __________________ - -----------------___________________________------------------ -*/ - -static void readFlowSample_header(SFSample *sample) { - dbg_printf("flowSampleType HEADER\n"); - sample->headerProtocol = getData32(sample); - dbg_printf("headerProtocol %u\n", sample->headerProtocol); - sample->sampledPacketSize = getData32(sample); - dbg_printf("sampledPacketSize %u\n", sample->sampledPacketSize); - if(sample->datagramVersion > 4) { - // stripped count introduced in sFlow version 5 - sample->stripped = getData32(sample); - dbg_printf("strippedBytes %u\n", sample->stripped); - } - sample->headerLen = getData32(sample); - dbg_printf("headerLen %u\n", sample->headerLen); - - sample->header = (u_char *)sample->datap; /* just point at the header */ - skipBytes(sample, sample->headerLen); - { - char scratch[2000]; - printHex(sample->header, sample->headerLen, scratch, 2000, 0, 2000); - dbg_printf("headerBytes %s\n", scratch); - } - - switch(sample->headerProtocol) { - /* the header protocol tells us where to jump into the decode */ - case SFLHEADER_ETHERNET_ISO8023: - decodeLinkLayer(sample); - break; - case SFLHEADER_IPv4: - sample->gotIPV4 = YES; - sample->offsetToIPV4 = 0; - break; - case SFLHEADER_ISO88024_TOKENBUS: - case SFLHEADER_ISO88025_TOKENRING: - case SFLHEADER_FDDI: - case SFLHEADER_FRAME_RELAY: - case SFLHEADER_X25: - case SFLHEADER_PPP: - case SFLHEADER_SMDS: - case SFLHEADER_AAL5: - case SFLHEADER_AAL5_IP: - case SFLHEADER_IPv6: - case SFLHEADER_MPLS: - dbg_printf("NO_DECODE headerProtocol=%d\n", sample->headerProtocol); - break; - default: - LogError("SFLOW: undefined headerProtocol = %d", sample->headerProtocol); - exit(-12); - } - - if(sample->gotIPV4) { - // report the size of the original IPPdu (including the IP header) - dbg_printf("IPSize %d\n", sample->sampledPacketSize - sample->stripped - sample->offsetToIPV4); - decodeIPV4(sample); - } - else if(sample->gotIPV6) { - // report the size of the original IPPdu (including the IP header) - dbg_printf("IPSize %d\n", sample->sampledPacketSize - sample->stripped - sample->offsetToIPV6); - decodeIPV6(sample); - } - -} - -/*_________________---------------------------__________________ - _________________ readFlowSample_ethernet __________________ - -----------------___________________________------------------ -*/ - -static void readFlowSample_ethernet(SFSample *sample) -{ - u_char *p; - dbg_printf("flowSampleType ETHERNET\n"); - sample->eth_len = getData32(sample); - memcpy(sample->eth_src, sample->datap, 6); - skipBytes(sample, 6); - memcpy(sample->eth_dst, sample->datap, 6); - skipBytes(sample, 6); - sample->eth_type = getData32(sample); - dbg_printf("ethernet_type %u\n", sample->eth_type); - dbg_printf("ethernet_len %u\n", sample->eth_len); - p = sample->eth_src; - dbg_printf("ethernet_src %02x%02x%02x%02x%02x%02x\n", p[0], p[1], p[2], p[3], p[4], p[5]); - p = sample->eth_dst; - dbg_printf("ethernet_dst %02x%02x%02x%02x%02x%02x\n", p[0], p[1], p[2], p[3], p[4], p[5]); -} - - -/*_________________---------------------------__________________ - _________________ readFlowSample_IPv4 __________________ - -----------------___________________________------------------ -*/ - -static void readFlowSample_IPv4(SFSample *sample) -{ - dbg_printf("flowSampleType IPV4\n"); - sample->headerLen = sizeof(SFLSampled_ipv4); - sample->header = (u_char *)sample->datap; /* just point at the header */ - skipBytes(sample, sample->headerLen); - { -#ifdef DEVEL - char buf[51]; -#endif - SFLSampled_ipv4 nfKey; - memcpy(&nfKey, sample->header, sizeof(nfKey)); - sample->sampledPacketSize = ntohl(nfKey.length); - dbg_printf("sampledPacketSize %u\n", sample->sampledPacketSize); - dbg_printf("IPSize %d\n", sample->sampledPacketSize); - sample->dcd_srcIP = nfKey.src_ip; - sample->dcd_dstIP = nfKey.dst_ip; - sample->dcd_ipProtocol = ntohl(nfKey.protocol); - sample->dcd_ipTos = ntohl(nfKey.tos); - dbg_printf("srcIP %s\n", IP_to_a(sample->dcd_srcIP.s_addr, buf, 51)); - dbg_printf("dstIP %s\n", IP_to_a(sample->dcd_dstIP.s_addr, buf, 51)); - dbg_printf("IPProtocol %u\n", sample->dcd_ipProtocol); - dbg_printf("IPTOS %u\n", sample->dcd_ipTos); - sample->dcd_sport = ntohl(nfKey.src_port); - sample->dcd_dport = ntohl(nfKey.dst_port); - switch(sample->dcd_ipProtocol) { - case 1: /* ICMP */ - dbg_printf("ICMPType %u\n", sample->dcd_dport); - /* not sure about the dest port being icmp type - - might be that src port is icmp type and dest - port is icmp code. Still, have seen some - implementations where src port is 0 and dst - port is the type, so it may be safer to - assume that the destination port has the type */ - break; - case 6: /* TCP */ - dbg_printf("TCPSrcPort %u\n", sample->dcd_sport); - dbg_printf("TCPDstPort %u\n", sample->dcd_dport); - sample->dcd_tcpFlags = ntohl(nfKey.tcp_flags); - dbg_printf("TCPFlags %u\n", sample->dcd_tcpFlags); - break; - case 17: /* UDP */ - dbg_printf("UDPSrcPort %u\n", sample->dcd_sport); - dbg_printf("UDPDstPort %u\n", sample->dcd_dport); - break; - default: /* some other protcol */ - break; - } - } -} - -/*_________________---------------------------__________________ - _________________ readFlowSample_IPv6 __________________ - -----------------___________________________------------------ -*/ - -static void readFlowSample_IPv6(SFSample *sample) -{ - dbg_printf("flowSampleType IPV6\n"); - sample->header = (u_char *)sample->datap; /* just point at the header */ - sample->headerLen = sizeof(SFLSampled_ipv6); - skipBytes(sample, sample->headerLen); - { - SFLSampled_ipv6 nfKey6; - memcpy(&nfKey6, sample->header, sizeof(nfKey6)); - sample->sampledPacketSize = ntohl(nfKey6.length); - dbg_printf("sampledPacketSize %u\n", sample->sampledPacketSize); - } - /* bug: more decode to do here */ -} - -/*_________________---------------------------__________________ - _________________ readFlowSample_v2v4 __________________ - -----------------___________________________------------------ -*/ - -static void readFlowSample_v2v4(SFSample *sample, FlowSource_t *fs) { - dbg_printf("sampleType FLOWSAMPLE\n"); - - sample->samplesGenerated = getData32(sample); - dbg_printf("sampleSequenceNo %u\n", sample->samplesGenerated); - { - uint32_t samplerId = getData32(sample); - sample->ds_class = samplerId >> 24; - sample->ds_index = samplerId & 0x00ffffff; - dbg_printf("sourceId %u:%u\n", sample->ds_class, sample->ds_index); - } - - sample->meanSkipCount = getData32(sample); - sample->samplePool = getData32(sample); - sample->dropEvents = getData32(sample); - sample->inputPort = getData32(sample); - sample->outputPort = getData32(sample); - dbg_printf("meanSkipCount %u\n", sample->meanSkipCount); - dbg_printf("samplePool %u\n", sample->samplePool); - dbg_printf("dropEvents %u\n", sample->dropEvents); - dbg_printf("inputPort %u\n", sample->inputPort); - if(sample->outputPort & 0x80000000) { - uint32_t numOutputs = sample->outputPort & 0x7fffffff; - if(numOutputs > 0) dbg_printf("outputPort multiple %d\n", numOutputs); - else dbg_printf("outputPort multiple >1\n"); - } - else dbg_printf("outputPort %u\n", sample->outputPort); - - sample->packet_data_tag = getData32(sample); - - switch(sample->packet_data_tag) { - - case INMPACKETTYPE_HEADER: readFlowSample_header(sample); break; - case INMPACKETTYPE_IPV4: readFlowSample_IPv4(sample); break; - case INMPACKETTYPE_IPV6: readFlowSample_IPv6(sample); break; - default: receiveError(sample, "unexpected packet_data_tag", YES); break; - } - - sample->extended_data_tag = 0; - { - uint32_t x; - sample->num_extended = getData32(sample); - for(x = 0; x < sample->num_extended; x++) { - uint32_t extended_tag; - extended_tag = getData32(sample); - switch(extended_tag) { - case INMEXTENDED_SWITCH: - readExtendedSwitch(sample); break; - case INMEXTENDED_ROUTER: - readExtendedRouter(sample); break; - case INMEXTENDED_GATEWAY: - if(sample->datagramVersion == 2) - readExtendedGateway_v2(sample); - else - readExtendedGateway(sample); - break; - case INMEXTENDED_USER: - readExtendedUser(sample); break; - case INMEXTENDED_URL: - readExtendedUrl(sample); break; - default: - LogError("Unrecognized extended data tag: %u", extended_tag); - receiveError(sample, "unrecognized extended data tag", YES); - break; - } - } - } - - if(sample->gotIPV4 || sample->gotIPV6) - StoreSflowRecord(sample, fs); - - /* if we are writing tcpdump format, write the next packet record now */ - /* or line-by-line output... */ - if ( verbose ) - writeFlowLine(sample); -} - -/*_________________---------------------------__________________ - _________________ readFlowSample __________________ - -----------------___________________________------------------ -*/ - -static void readFlowSample(SFSample *sample, int expanded, FlowSource_t *fs) { - uint32_t num_elements, sampleLength; - u_char *sampleStart; - - dbg_printf("sampleType FLOWSAMPLE\n"); - sampleLength = getData32(sample); - sampleStart = (u_char *)sample->datap; - sample->samplesGenerated = getData32(sample); - dbg_printf("sampleSequenceNo %u\n", sample->samplesGenerated); - if(expanded) { - sample->ds_class = getData32(sample); - sample->ds_index = getData32(sample); - } - else { - uint32_t samplerId = getData32(sample); - sample->ds_class = samplerId >> 24; - sample->ds_index = samplerId & 0x00ffffff; - } - dbg_printf("sourceId %u:%u\n", sample->ds_class, sample->ds_index); - - sample->meanSkipCount = getData32(sample); - sample->samplePool = getData32(sample); - sample->dropEvents = getData32(sample); - dbg_printf("meanSkipCount %u\n", sample->meanSkipCount); - dbg_printf("samplePool %u\n", sample->samplePool); - dbg_printf("dropEvents %u\n", sample->dropEvents); - if(expanded) { - sample->inputPortFormat = getData32(sample); - sample->inputPort = getData32(sample); - sample->outputPortFormat = getData32(sample); - sample->outputPort = getData32(sample); - } - else { - uint32_t inp, outp; - inp = getData32(sample); - outp = getData32(sample); - sample->inputPortFormat = inp >> 30; - sample->outputPortFormat = outp >> 30; - sample->inputPort = inp & 0x3fffffff; - sample->outputPort = outp & 0x3fffffff; - } - if(sample->inputPortFormat == 3) dbg_printf("inputPort format==3 %u\n", sample->inputPort); - else if(sample->inputPortFormat == 2) dbg_printf("inputPort multiple %u\n", sample->inputPort); - else if(sample->inputPortFormat == 1) dbg_printf("inputPort dropCode %u\n", sample->inputPort); - else if(sample->inputPortFormat == 0) dbg_printf("inputPort %u\n", sample->inputPort); - if(sample->outputPortFormat == 3) dbg_printf("outputPort format==3 %u\n", sample->outputPort); - else if(sample->outputPortFormat == 2) dbg_printf("outputPort multiple %u\n", sample->outputPort); - else if(sample->outputPortFormat == 1) dbg_printf("outputPort dropCode %u\n", sample->outputPort); - else if(sample->outputPortFormat == 0) dbg_printf("outputPort %u\n", sample->outputPort); - - num_elements = getData32(sample); - { - int el; - for(el = 0; el < num_elements; el++) { -#ifdef DEVEL - char buf[51]; -#endif - uint32_t tag, length; - u_char *start; - tag = getData32(sample); - dbg_printf("flowBlock_tag %s\n", printTag(tag, buf, 50)); - length = getData32(sample); - start = (u_char *)sample->datap; - - switch(tag) { - case SFLFLOW_HEADER: readFlowSample_header(sample); break; - case SFLFLOW_ETHERNET: readFlowSample_ethernet(sample); break; - case SFLFLOW_IPV4: readFlowSample_IPv4(sample); break; - case SFLFLOW_IPV6: readFlowSample_IPv6(sample); break; - case SFLFLOW_EX_SWITCH: readExtendedSwitch(sample); break; - case SFLFLOW_EX_ROUTER: readExtendedRouter(sample); break; - case SFLFLOW_EX_GATEWAY: readExtendedGateway(sample); break; - case SFLFLOW_EX_USER: readExtendedUser(sample); break; - case SFLFLOW_EX_URL: readExtendedUrl(sample); break; - case SFLFLOW_EX_MPLS: readExtendedMpls(sample); break; - case SFLFLOW_EX_NAT: readExtendedNat(sample); break; - case SFLFLOW_EX_MPLS_TUNNEL: readExtendedMplsTunnel(sample); break; - case SFLFLOW_EX_MPLS_VC: readExtendedMplsVC(sample); break; - case SFLFLOW_EX_MPLS_FTN: readExtendedMplsFTN(sample); break; - case SFLFLOW_EX_MPLS_LDP_FEC: readExtendedMplsLDP_FEC(sample); break; - case SFLFLOW_EX_VLAN_TUNNEL: readExtendedVlanTunnel(sample); break; - case SFLFLOW_EX_PROCESS: readExtendedProcess(sample); break; - default: skipTLVRecord(sample, tag, length, "flow_sample_element"); break; - } - lengthCheck(sample, "flow_sample_element", start, length); - } - } - lengthCheck(sample, "flow_sample", sampleStart, sampleLength); - - if ( sample->gotIPV4 || sample->gotIPV6 ) - StoreSflowRecord(sample, fs); - - /* or line-by-line output... */ - if ( verbose ) - writeFlowLine(sample); -} - -/*_________________---------------------------__________________ - _________________ readCounters_generic __________________ - -----------------___________________________------------------ -*/ - -static void readCounters_generic(SFSample *sample) -{ - /* the first part of the generic counters block is really just more info about the interface. */ - sample->ifCounters.ifIndex = sf_log_next32(sample, "ifIndex"); - sample->ifCounters.ifType = sf_log_next32(sample, "networkType"); - sample->ifCounters.ifSpeed = sf_log_next64(sample, "ifSpeed"); - sample->ifCounters.ifDirection = sf_log_next32(sample, "ifDirection"); - sample->ifCounters.ifStatus = sf_log_next32(sample, "ifStatus"); - /* the generic counters always come first */ - sample->ifCounters.ifInOctets = sf_log_next64(sample, "ifInOctets"); - sample->ifCounters.ifInUcastPkts = sf_log_next32(sample, "ifInUcastPkts"); - sample->ifCounters.ifInMulticastPkts = sf_log_next32(sample, "ifInMulticastPkts"); - sample->ifCounters.ifInBroadcastPkts = sf_log_next32(sample, "ifInBroadcastPkts"); - sample->ifCounters.ifInDiscards = sf_log_next32(sample, "ifInDiscards"); - sample->ifCounters.ifInErrors = sf_log_next32(sample, "ifInErrors"); - sample->ifCounters.ifInUnknownProtos = sf_log_next32(sample, "ifInUnknownProtos"); - sample->ifCounters.ifOutOctets = sf_log_next64(sample, "ifOutOctets"); - sample->ifCounters.ifOutUcastPkts = sf_log_next32(sample, "ifOutUcastPkts"); - sample->ifCounters.ifOutMulticastPkts = sf_log_next32(sample, "ifOutMulticastPkts"); - sample->ifCounters.ifOutBroadcastPkts = sf_log_next32(sample, "ifOutBroadcastPkts"); - sample->ifCounters.ifOutDiscards = sf_log_next32(sample, "ifOutDiscards"); - sample->ifCounters.ifOutErrors = sf_log_next32(sample, "ifOutErrors"); - sample->ifCounters.ifPromiscuousMode = sf_log_next32(sample, "ifPromiscuousMode"); -} - -/*_________________---------------------------__________________ - _________________ readCounters_ethernet __________________ - -----------------___________________________------------------ -*/ - -static void readCounters_ethernet(SFSample *sample) -{ - sf_log_next32(sample, "dot3StatsAlignmentErrors"); - sf_log_next32(sample, "dot3StatsFCSErrors"); - sf_log_next32(sample, "dot3StatsSingleCollisionFrames"); - sf_log_next32(sample, "dot3StatsMultipleCollisionFrames"); - sf_log_next32(sample, "dot3StatsSQETestErrors"); - sf_log_next32(sample, "dot3StatsDeferredTransmissions"); - sf_log_next32(sample, "dot3StatsLateCollisions"); - sf_log_next32(sample, "dot3StatsExcessiveCollisions"); - sf_log_next32(sample, "dot3StatsInternalMacTransmitErrors"); - sf_log_next32(sample, "dot3StatsCarrierSenseErrors"); - sf_log_next32(sample, "dot3StatsFrameTooLongs"); - sf_log_next32(sample, "dot3StatsInternalMacReceiveErrors"); - sf_log_next32(sample, "dot3StatsSymbolErrors"); -} - - -/*_________________---------------------------__________________ - _________________ readCounters_tokenring __________________ - -----------------___________________________------------------ -*/ - -static void readCounters_tokenring(SFSample *sample) -{ - sf_log_next32(sample, "dot5StatsLineErrors"); - sf_log_next32(sample, "dot5StatsBurstErrors"); - sf_log_next32(sample, "dot5StatsACErrors"); - sf_log_next32(sample, "dot5StatsAbortTransErrors"); - sf_log_next32(sample, "dot5StatsInternalErrors"); - sf_log_next32(sample, "dot5StatsLostFrameErrors"); - sf_log_next32(sample, "dot5StatsReceiveCongestions"); - sf_log_next32(sample, "dot5StatsFrameCopiedErrors"); - sf_log_next32(sample, "dot5StatsTokenErrors"); - sf_log_next32(sample, "dot5StatsSoftErrors"); - sf_log_next32(sample, "dot5StatsHardErrors"); - sf_log_next32(sample, "dot5StatsSignalLoss"); - sf_log_next32(sample, "dot5StatsTransmitBeacons"); - sf_log_next32(sample, "dot5StatsRecoverys"); - sf_log_next32(sample, "dot5StatsLobeWires"); - sf_log_next32(sample, "dot5StatsRemoves"); - sf_log_next32(sample, "dot5StatsSingles"); - sf_log_next32(sample, "dot5StatsFreqErrors"); -} - - -/*_________________---------------------------__________________ - _________________ readCounters_vg __________________ - -----------------___________________________------------------ -*/ - -static void readCounters_vg(SFSample *sample) -{ - sf_log_next32(sample, "dot12InHighPriorityFrames"); - sf_log_next64(sample, "dot12InHighPriorityOctets"); - sf_log_next32(sample, "dot12InNormPriorityFrames"); - sf_log_next64(sample, "dot12InNormPriorityOctets"); - sf_log_next32(sample, "dot12InIPMErrors"); - sf_log_next32(sample, "dot12InOversizeFrameErrors"); - sf_log_next32(sample, "dot12InDataErrors"); - sf_log_next32(sample, "dot12InNullAddressedFrames"); - sf_log_next32(sample, "dot12OutHighPriorityFrames"); - sf_log_next64(sample, "dot12OutHighPriorityOctets"); - sf_log_next32(sample, "dot12TransitionIntoTrainings"); - sf_log_next64(sample, "dot12HCInHighPriorityOctets"); - sf_log_next64(sample, "dot12HCInNormPriorityOctets"); - sf_log_next64(sample, "dot12HCOutHighPriorityOctets"); -} - - - -/*_________________---------------------------__________________ - _________________ readCounters_vlan __________________ - -----------------___________________________------------------ -*/ - -static void readCounters_vlan(SFSample *sample) -{ - sample->in_vlan = getData32(sample); - dbg_printf("in_vlan %u\n", sample->in_vlan); - sf_log_next64(sample, "octets"); - sf_log_next32(sample, "ucastPkts"); - sf_log_next32(sample, "multicastPkts"); - sf_log_next32(sample, "broadcastPkts"); - sf_log_next32(sample, "discards"); -} - -/*_________________---------------------------__________________ - _________________ readCounters_processor __________________ - -----------------___________________________------------------ -*/ - -static void readCounters_processor(SFSample *sample) -{ - sf_log_percentage(sample, "5s_cpu"); - sf_log_percentage(sample, "1m_cpu"); - sf_log_percentage(sample, "5m_cpu"); - sf_log_next64(sample, "total_memory_bytes"); - sf_log_next64(sample, "free_memory_bytes"); -} - -/*_________________---------------------------__________________ - _________________ readCountersSample_v2v4 __________________ - -----------------___________________________------------------ -*/ - -static void readCountersSample_v2v4(SFSample *sample, FlowSource_t *fs) -{ - dbg_printf("sampleType COUNTERSSAMPLE\n"); - sample->samplesGenerated = getData32(sample); - dbg_printf("sampleSequenceNo %u\n", sample->samplesGenerated); - { - uint32_t samplerId = getData32(sample); - sample->ds_class = samplerId >> 24; - sample->ds_index = samplerId & 0x00ffffff; - } - dbg_printf("sourceId %u:%u\n", sample->ds_class, sample->ds_index); - - - sample->statsSamplingInterval = getData32(sample); - dbg_printf("statsSamplingInterval %u\n", sample->statsSamplingInterval); - /* now find out what sort of counter blocks we have here... */ - sample->counterBlockVersion = getData32(sample); - dbg_printf("counterBlockVersion %u\n", sample->counterBlockVersion); - - /* first see if we should read the generic stats */ - switch(sample->counterBlockVersion) { - case INMCOUNTERSVERSION_GENERIC: - case INMCOUNTERSVERSION_ETHERNET: - case INMCOUNTERSVERSION_TOKENRING: - case INMCOUNTERSVERSION_FDDI: - case INMCOUNTERSVERSION_VG: - case INMCOUNTERSVERSION_WAN: readCounters_generic(sample); break; - case INMCOUNTERSVERSION_VLAN: break; - default: receiveError(sample, "unknown stats version", YES); break; - } - - /* now see if there are any specific counter blocks to add */ - switch(sample->counterBlockVersion) { - case INMCOUNTERSVERSION_GENERIC: /* nothing more */ break; - case INMCOUNTERSVERSION_ETHERNET: readCounters_ethernet(sample); break; - case INMCOUNTERSVERSION_TOKENRING:readCounters_tokenring(sample); break; - case INMCOUNTERSVERSION_FDDI: break; - case INMCOUNTERSVERSION_VG: readCounters_vg(sample); break; - case INMCOUNTERSVERSION_WAN: break; - case INMCOUNTERSVERSION_VLAN: readCounters_vlan(sample); break; - default: receiveError(sample, "unknown INMCOUNTERSVERSION", YES); break; - } - /* line-by-line output... */ - if ( verbose ) - writeCountersLine(sample); -} - -/*_________________---------------------------__________________ - _________________ readCountersSample __________________ - -----------------___________________________------------------ -*/ - -static void readCountersSample(SFSample *sample, int expanded, FlowSource_t *fs) { - uint32_t sampleLength; - uint32_t num_elements; - u_char *sampleStart; - dbg_printf("sampleType COUNTERSSAMPLE\n"); - sampleLength = getData32(sample); - sampleStart = (u_char *)sample->datap; - sample->samplesGenerated = getData32(sample); - - dbg_printf("sampleSequenceNo %u\n", sample->samplesGenerated); - if(expanded) { - sample->ds_class = getData32(sample); - sample->ds_index = getData32(sample); - } - else { - uint32_t samplerId = getData32(sample); - sample->ds_class = samplerId >> 24; - sample->ds_index = samplerId & 0x00ffffff; - } - dbg_printf("sourceId %u:%u\n", sample->ds_class, sample->ds_index); - - num_elements = getData32(sample); - { - int el; - for(el = 0; el < num_elements; el++) { -#ifdef DEVEL - char buf[51]; -#endif - uint32_t tag, length; - u_char *start; - tag = getData32(sample); - dbg_printf("counterBlock_tag %s\n", printTag(tag, buf, 50)); - length = getData32(sample); - start = (u_char *)sample->datap; - - switch(tag) { - case SFLCOUNTERS_GENERIC: readCounters_generic(sample); break; - case SFLCOUNTERS_ETHERNET: readCounters_ethernet(sample); break; - case SFLCOUNTERS_TOKENRING:readCounters_tokenring(sample); break; - case SFLCOUNTERS_VG: readCounters_vg(sample); break; - case SFLCOUNTERS_VLAN: readCounters_vlan(sample); break; - case SFLCOUNTERS_PROCESSOR: readCounters_processor(sample); break; - default: skipTLVRecord(sample, tag, length, "counters_sample_element"); break; - } - lengthCheck(sample, "counters_sample_element", start, length); - } - } - lengthCheck(sample, "counters_sample", sampleStart, sampleLength); - /* line-by-line output... */ - if ( verbose ) - writeCountersLine(sample); - -} - -/*_________________---------------------------__________________ - _________________ readSFlowDatagram __________________ - -----------------___________________________------------------ -*/ - -static inline void readSFlowDatagram(SFSample *sample, FlowSource_t *fs) { -uint32_t samplesInPacket; -uint32_t samp = 0; -struct timeval now; -#ifdef DEVEL -char buf[51]; -#endif - - /* log some datagram info */ - now.tv_sec = time(NULL); - now.tv_usec = 0; - dbg_printf("datagramSourceIP %s\n", IP_to_a(sample->sourceIP.s_addr, buf, 51)); - dbg_printf("datagramSize %u\n", sample->rawSampleLen); - dbg_printf("unixSecondsUTC %llu\n", (unsigned long long)now.tv_sec); - - /* check the version */ - sample->datagramVersion = getData32(sample); - dbg_printf("datagramVersion %d\n", sample->datagramVersion); - if(sample->datagramVersion != 2 && - sample->datagramVersion != 4 && - sample->datagramVersion != 5) { - receiveError(sample, "unexpected datagram version number\n", YES); - } - - /* get the agent address */ - getAddress(sample, &sample->agent_addr); - - /* version 5 has an agent sub-id as well */ - if(sample->datagramVersion >= 5) { - sample->agentSubId = getData32(sample); - dbg_printf("agentSubId %u\n", sample->agentSubId); - } - - sample->sequenceNo = getData32(sample); /* this is the packet sequence number */ - sample->sysUpTime = getData32(sample); - samplesInPacket = getData32(sample); - dbg_printf("agent %s\n", printAddress(&sample->agent_addr, buf, 50)); - dbg_printf("packetSequenceNo %u\n", sample->sequenceNo); - dbg_printf("sysUpTime %u\n", sample->sysUpTime); - dbg_printf("samplesInPacket %u\n", samplesInPacket); - - /* now iterate and pull out the flows and counters samples */ - for(; samp < samplesInPacket; samp++) { - memset(&sample->packet_data_tag, 0, - sizeof(*sample) - ((void *)&sample->packet_data_tag - (void *)sample)); - - // just read the tag, then call the approriate decode fn - sample->sampleType = getData32(sample); - dbg_printf("startSample ----------------------\n"); - dbg_printf("sampleType_tag %s\n", printTag(sample->sampleType, buf, 50)); - if(sample->datagramVersion >= 5) { - switch(sample->sampleType) { - case SFLFLOW_SAMPLE: readFlowSample(sample, NO, fs); - break; - case SFLCOUNTERS_SAMPLE: readCountersSample(sample, NO, fs); - break; - case SFLFLOW_SAMPLE_EXPANDED: readFlowSample(sample, YES, fs); - break; - case SFLCOUNTERS_SAMPLE_EXPANDED: readCountersSample(sample, YES, fs); - break; - default: skipTLVRecord(sample, sample->sampleType, getData32(sample), "sample"); - break; - } - } else { - switch(sample->sampleType) { - case FLOWSAMPLE: readFlowSample_v2v4(sample, fs); - break; - case COUNTERSSAMPLE: readCountersSample_v2v4(sample, fs); - break; - default: receiveError(sample, "unexpected sample type", YES); - break; - } - } - dbg_printf("endSample ----------------------\n"); - } -} // readSFlowDatagram - - -void Init_sflow(void) { -int i, id; - - sfConfig.disableNetFlowScale = 0; - sfConfig.netFlowPeerAS = 0; - - i=0; - Num_enabled_extensions = 0; - while ( (id = sflow_extensions[i]) != 0 ) { - if ( extension_descriptor[id].enabled ) { - dbg_printf("Enabled extension: %i\n", id); - Num_enabled_extensions++; - } - i++; - } - - IP_extension_mask = 0; - i=0; - while ( extension_descriptor[i].description != NULL ) { - switch (extension_descriptor[i].id) { - case EX_NEXT_HOP_v4: - // case EX_NEXT_HOP_v6: - not really needed - if ( extension_descriptor[i].enabled ) { - SetFlag(IP_extension_mask, SFLOW_NEXT_HOP); - Num_enabled_extensions++; - } break; - case EX_NEXT_HOP_BGP_v4: - // case EX_NEXT_HOP_BGP_v6: - not really needed - if ( extension_descriptor[i].enabled ) { - SetFlag(IP_extension_mask, SFLOW_NEXT_HOP_BGP); - Num_enabled_extensions++; - } break; - case EX_ROUTER_IP_v4: - // case EX_ROUTER_IP_v6: - not really needed - if ( extension_descriptor[i].enabled ) { - SetFlag(IP_extension_mask, SFLOW_ROUTER_IP); - Num_enabled_extensions++; - } break; - } - i++; - } - - dbg_printf("Num enabled Extensions: %i\n", Num_enabled_extensions); - -} // End of Init_sflow - -int Setup_Extension_Info(FlowSource_t *fs, exporter_sflow_t *exporter, int num) { -int i, id, extension_size, map_size, map_index; - - dbg_printf("Setup Extension ID 0x%x\n", num); - LogInfo("SFLOW: setup extension map %u", num); - - // prepare sflow extension map - exporter->sflow_extension_info[num].map = NULL; - extension_size = 0; - - // calculate the full extension map size - map_size = Num_enabled_extensions * sizeof(uint16_t) + sizeof(extension_map_t); - - // align 32 bits - if ( ( map_size & 0x3 ) != 0 ) - map_size += 2; - - - // Create a generic sflow extension map - exporter->sflow_extension_info[num].map = (extension_map_t *)malloc((size_t)map_size); - if ( !exporter->sflow_extension_info[num].map ) { - LogError("malloc() allocation error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) ); - return 0; - } - - // calclate the extension size - i=0; - map_index = 0; - while ( (id = sflow_extensions[i]) != 0 ) { - if ( extension_descriptor[id].enabled ) { - extension_size += extension_descriptor[id].size; - exporter->sflow_extension_info[num].map->ex_id[map_index++] = id; - } - i++; - } - - if ( TestFlag(IP_extension_mask, SFLOW_NEXT_HOP)) { - id = sflow_ip_extensions[num].next_hop; - extension_size += extension_descriptor[id].size; - exporter->sflow_extension_info[num].map->ex_id[map_index++] = id; - } - - if ( TestFlag(IP_extension_mask, SFLOW_NEXT_HOP_BGP)) { - id = sflow_ip_extensions[num].next_hop_bgp; - extension_size += extension_descriptor[id].size; - exporter->sflow_extension_info[num].map->ex_id[map_index++] = id; - } - - if ( TestFlag(IP_extension_mask, SFLOW_ROUTER_IP)) { - id = sflow_ip_extensions[num].router_ip; - extension_size += extension_descriptor[id].size; - exporter->sflow_extension_info[num].map->ex_id[map_index++] = id; - } - - // terminating null record - exporter->sflow_extension_info[num].map->ex_id[map_index] = 0; - - dbg_printf("Extension size: %i\n", extension_size); - - // caculate the basic record size: without IP addr space ( v4/v6 dependant ) - // byte/packet counters are 32bit -> 2 x uint32_t - // extension_size contains the sum of all optional extensions - sflow_output_record_size[num] = COMMON_RECORD_DATA_SIZE + 2*sizeof(uint32_t) + extension_size; - - dbg_printf("Record size: %i\n", sflow_output_record_size[num]); - - exporter->sflow_extension_info[num].map->type = ExtensionMapType; - exporter->sflow_extension_info[num].map->size = map_size; - exporter->sflow_extension_info[num].map->map_id = INIT_ID; - exporter->sflow_extension_info[num].map->extension_size = extension_size; - - LogInfo("Extension size: %i", extension_size); - LogInfo("Extension map size: %i", map_size); - - if ( !AddExtensionMap(fs, exporter->sflow_extension_info[num].map) ) { - // bad - we must free this map and fail - otherwise data can not be read any more - free(exporter->sflow_extension_info[num].map); - exporter->sflow_extension_info[num].map = NULL; - return 0; - } - dbg_printf("New Extension map ID %i\n", exporter->sflow_extension_info[num].map->map_id); - LogInfo("New extension map id: %i", exporter->sflow_extension_info[num].map->map_id); - - return 1; - -} // End of Setup_Extension_Info - -static inline exporter_sflow_t *GetExporter(FlowSource_t *fs, uint32_t agentSubId, uint32_t meanSkipCount) { -exporter_sflow_t **e = (exporter_sflow_t **)&(fs->exporter_data); -generic_sampler_t *sampler; -#define IP_STRING_LEN 40 -char ipstr[IP_STRING_LEN]; -int i; - - // search the appropriate exporter engine - while ( *e ) { - if ( (*e)->info.id == agentSubId && (*e)->info.version == SFLOW_VERSION && - (*e)->info.ip.v6[0] == fs->ip.v6[0] && (*e)->info.ip.v6[1] == fs->ip.v6[1]) - return *e; - e = &((*e)->next); - } - - if ( fs->sa_family == AF_INET ) { - uint32_t _ip = htonl(fs->ip.v4); - inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr)); - } else if ( fs->sa_family == AF_INET6 ) { - uint64_t _ip[2]; - _ip[0] = htonll(fs->ip.v6[0]); - _ip[1] = htonll(fs->ip.v6[1]); - inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr)); - } else { - strncpy(ipstr, "", IP_STRING_LEN); - } - - // nothing found - LogInfo("SFLOW: New exporter" ); - - *e = (exporter_sflow_t *)malloc(sizeof(exporter_sflow_t)); - if ( !(*e)) { - LogError("SFLOW: malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror (errno)); - return NULL; - } - memset((void *)(*e), 0, sizeof(exporter_sflow_t)); - (*e)->next = NULL; - (*e)->info.header.type = ExporterInfoRecordType; - (*e)->info.header.size = sizeof(exporter_info_record_t); - (*e)->info.version = SFLOW_VERSION; - (*e)->info.id = agentSubId; - (*e)->info.ip = fs->ip; - (*e)->info.sa_family = fs->sa_family; - (*e)->sequence_failure = 0; - (*e)->packets = 0; - (*e)->flows = 0; - for (i=0; isflow_extension_info[i].map = NULL; - } - - sampler = (generic_sampler_t *)malloc(sizeof(generic_sampler_t)); - if ( !sampler ) { - LogError("SFLOW: malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror (errno)); - return NULL; - } - (*e)->sampler = sampler; - - sampler->info.header.type = SamplerInfoRecordype; - sampler->info.header.size = sizeof(sampler_info_record_t); - sampler->info.id = -1; - sampler->info.mode = 0; - sampler->info.interval = meanSkipCount; - sampler->next = NULL; - - FlushInfoExporter(fs, &((*e)->info)); - sampler->info.exporter_sysid = (*e)->info.sysid; - FlushInfoSampler(fs, &(sampler->info)); - - dbg_printf("SFLOW: New exporter: SysID: %u, agentSubId: %u, MeanSkipCount: %u, IP: %s\n", - (*e)->info.sysid, agentSubId, meanSkipCount, ipstr); - LogInfo("SFLOW: New exporter: SysID: %u, agentSubId: %u, MeanSkipCount: %u, IP: %s", - (*e)->info.sysid, agentSubId, meanSkipCount, ipstr); - - return (*e); - -} // End of GetExporter - -void Process_sflow(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs) { - -SFSample sample; -int exceptionVal; - - memset(&sample, 0, sizeof(sample)); - sample.rawSample = in_buff; - sample.rawSampleLen = in_buff_cnt; - sample.sourceIP.s_addr = fs->sa_family == PF_INET ? htonl(fs->ip.v4) : 0;; - - dbg_printf("startDatagram =================================\n"); - if((exceptionVal = setjmp(sample.env)) == 0) { - // TRY - sample.datap = (uint32_t *)sample.rawSample; - sample.endp = (u_char *)sample.rawSample + sample.rawSampleLen; - readSFlowDatagram(&sample, fs ); - } else { - // CATCH - dbg_printf("SFLOW: caught exception: %d\n", exceptionVal); - LogError("SFLOW: caught exception: %d", exceptionVal); - } - dbg_printf("endDatagram =================================\n"); - -} // End of Process_sflow diff --git a/bin/sflow.h b/bin/sflow.h index 272b785..1fa8a0f 100644 --- a/bin/sflow.h +++ b/bin/sflow.h @@ -1,306 +1,703 @@ -/* - * Copyright (c) 2014, Peter Haag - * Copyright (c) 2009, Peter Haag - * Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the author nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Author: haag $ - * - * $Id: sflow.h 39 2009-11-25 08:11:15Z haag $ - * - * $LastChangedRevision: 39 $ - * - * - */ - -#ifndef _SFLOW_H -#define _SFLOW_H 1 - -/* - * sfcapd makes use of code originated from sflowtool by InMon Corp. - * Those parts of the code are distributed under the InMon Public License below. - * All other/additional code is pubblished under BSD license. - */ - +/* Copyright (c) 2002-2011 InMon Corp. Licensed under the terms of the InMon sFlow licence: */ +/* http://www.inmon.com/technology/sflowlicense.txt */ /* - * ----------------------------------------------------------------------- - * Copyright (c) 2001-2002 InMon Corp. All rights reserved. - * ----------------------------------------------------------------------- - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes sFlow(TM), freely available from - * http://www.inmon.com/". - * - * 4. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes sFlow(TM), freely available from - * http://www.inmon.com/". - * - * 5. InMon Corp. may publish revised and/or new versions - * of the license from time to time. Each version will be given a - * distinguishing version number. Once covered code has been - * published under a particular version of the license, you may - * always continue to use it under the terms of that version. You - * may also choose to use such covered code under the terms of any - * subsequent version of the license published by InMon Corp. - * No one other than the InMon Corp. has the right to modify the terms - * applicable to covered code created under this License. - * - * 6. The name "sFlow" must not be used to endorse or promote products - * derived from this software without prior written permission - * from InMon Corp. This does not apply to add-on libraries or tools - * that work in conjunction with sFlow. In such a case the sFlow name - * may be used to indicate that the product supports sFlow. - * - * 7. Products derived from this software may not be called "sFlow", - * nor may "sFlow" appear in their name, without prior written - * permission of InMon Corp. - * - * - * THIS SOFTWARE IS PROVIDED BY INMON CORP. ``AS IS'' AND - * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * INMON CORP. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * -------------------------------------------------------------------- - * - * This software consists of voluntary contributions made by many - * individuals on behalf of InMon Corp. - * - * InMon Corp. can be contacted via Email at info@inmon.com. - * - * For more information on InMon Corp. and sFlow, - * please see http://www.inmon.com/. - * - * InMon Public License Version 1.0 written May 31, 2001 - * - */ +///////////////////////////////////////////////////////////////////////////////// +/////////////////////// sFlow Sampling Packet Data Types //////////////////////// +///////////////////////////////////////////////////////////////////////////////// +*/ +#ifndef SFLOW_H +#define SFLOW_H 1 -enum INMAddress_type { - INMADDRESSTYPE_IP_V4 = 1, - INMADDRESSTYPE_IP_V6 = 2 +#if defined(__cplusplus) +extern "C" { +#endif + +typedef struct { + uint32_t addr; +} SFLIPv4; + +typedef struct { + uint8_t addr[16]; +} SFLIPv6; + +typedef union _SFLAddress_value { + SFLIPv4 ip_v4; + SFLIPv6 ip_v6; +} SFLAddress_value; + +enum SFLAddress_type { + SFLADDRESSTYPE_UNDEFINED = 0, + SFLADDRESSTYPE_IP_V4 = 1, + SFLADDRESSTYPE_IP_V6 = 2 }; -typedef union _INMAddress_value { - struct in_addr ip_v4; - struct in6_addr ip_v6; -} INMAddress_value; - -typedef struct _INMAddress { - uint32_t type; /* enum INMAddress_type */ - INMAddress_value address; -} INMAddress; +typedef struct _SFLAddress { + uint32_t type; /* enum SFLAddress_type */ + SFLAddress_value address; +} SFLAddress; /* Packet header data */ -#define INM_MAX_HEADER_SIZE 256 /* The maximum sampled header size. */ -#define INM_DEFAULT_HEADER_SIZE 128 -#define INM_DEFAULT_COLLECTOR_PORT 6343 -#define INM_DEFAULT_SAMPLING_RATE 400 +#define SFL_DEFAULT_HEADER_SIZE 128 +#define SFL_DEFAULT_COLLECTOR_PORT 6343 +#define SFL_DEFAULT_SAMPLING_RATE 400 /* The header protocol describes the format of the sampled header */ -enum INMHeader_protocol { - INMHEADER_ETHERNET_ISO8023 = 1, - INMHEADER_ISO88024_TOKENBUS = 2, - INMHEADER_ISO88025_TOKENRING = 3, - INMHEADER_FDDI = 4, - INMHEADER_FRAME_RELAY = 5, - INMHEADER_X25 = 6, - INMHEADER_PPP = 7, - INMHEADER_SMDS = 8, - INMHEADER_AAL5 = 9, - INMHEADER_AAL5_IP = 10, /* e.g. Cisco AAL5 mux */ - INMHEADER_IPv4 = 11, - INMHEADER_IPv6 = 12 +enum SFLHeader_protocol { + SFLHEADER_ETHERNET_ISO8023 = 1, + SFLHEADER_ISO88024_TOKENBUS = 2, + SFLHEADER_ISO88025_TOKENRING = 3, + SFLHEADER_FDDI = 4, + SFLHEADER_FRAME_RELAY = 5, + SFLHEADER_X25 = 6, + SFLHEADER_PPP = 7, + SFLHEADER_SMDS = 8, + SFLHEADER_AAL5 = 9, + SFLHEADER_AAL5_IP = 10, /* e.g. Cisco AAL5 mux */ + SFLHEADER_IPv4 = 11, + SFLHEADER_IPv6 = 12, + SFLHEADER_MPLS = 13, + SFLHEADER_POS = 14, + SFLHEADER_IEEE80211MAC = 15, + SFLHEADER_IEEE80211_AMPDU = 16, + SFLHEADER_IEEE80211_AMSDU_SUBFRAME = 17 }; -typedef struct _INMSampled_header { - uint32_t header_protocol; /* (enum INMHeader_protocol) */ +/* raw sampled header */ + +typedef struct _SFLSampled_header { + uint32_t header_protocol; /* (enum SFLHeader_protocol) */ uint32_t frame_length; /* Original length of packet before sampling */ + uint32_t stripped; /* header/trailer bytes stripped by sender */ uint32_t header_length; /* length of sampled header bytes to follow */ - uint8_t header[INM_MAX_HEADER_SIZE]; /* Header bytes */ -} INMSampled_header; + uint8_t *header_bytes; /* Header bytes */ +} SFLSampled_header; -/* Packet IP version 4 data */ +/* decoded ethernet header */ -typedef struct _INMSampled_ipv4 { +typedef struct _SFLSampled_ethernet { + uint32_t eth_len; /* The length of the MAC packet excluding + lower layer encapsulations */ + uint8_t src_mac[8]; /* 6 bytes + 2 pad */ + uint8_t dst_mac[8]; + uint32_t eth_type; +} SFLSampled_ethernet; + +/* decoded IP version 4 header */ + +typedef struct _SFLSampled_ipv4 { uint32_t length; /* The length of the IP packet excluding lower layer encapsulations */ uint32_t protocol; /* IP Protocol type (for example, TCP = 6, UDP = 17) */ - struct in_addr src_ip; /* Source IP Address */ - struct in_addr dst_ip; /* Destination IP Address */ + SFLIPv4 src_ip; /* Source IP Address */ + SFLIPv4 dst_ip; /* Destination IP Address */ uint32_t src_port; /* TCP/UDP source port number or equivalent */ uint32_t dst_port; /* TCP/UDP destination port number or equivalent */ uint32_t tcp_flags; /* TCP flags */ uint32_t tos; /* IP type of service */ -} INMSampled_ipv4; +} SFLSampled_ipv4; -/* Packet IP version 6 data */ +/* decoded IP version 6 data */ -typedef struct _INMSampled_ipv6 { +typedef struct _SFLSampled_ipv6 { uint32_t length; /* The length of the IP packet excluding lower layer encapsulations */ uint32_t protocol; /* IP Protocol type (for example, TCP = 6, UDP = 17) */ - struct in6_addr src_ip; /* Source IP Address */ - struct in6_addr dst_ip; /* Destination IP Address */ + SFLIPv6 src_ip; /* Source IP Address */ + SFLIPv6 dst_ip; /* Destination IP Address */ uint32_t src_port; /* TCP/UDP source port number or equivalent */ uint32_t dst_port; /* TCP/UDP destination port number or equivalent */ uint32_t tcp_flags; /* TCP flags */ - uint32_t tos; /* IP type of service */ -} INMSampled_ipv6; - - -/* Packet data */ - -enum INMPacket_information_type { - INMPACKETTYPE_HEADER = 1, /* Packet headers are sampled */ - INMPACKETTYPE_IPV4 = 2, /* IP version 4 data */ - INMPACKETTYPE_IPV6 = 3 /* IP version 4 data */ -}; - -typedef union _INMPacket_data_type { - INMSampled_header header; - INMSampled_ipv4 ipv4; - INMSampled_ipv6 ipv6; -} INMPacket_data_type; + uint32_t priority; /* IP priority */ +} SFLSampled_ipv6; /* Extended data types */ /* Extended switch data */ -typedef struct _INMExtended_switch { +typedef struct _SFLExtended_switch { uint32_t src_vlan; /* The 802.1Q VLAN id of incomming frame */ uint32_t src_priority; /* The 802.1p priority */ uint32_t dst_vlan; /* The 802.1Q VLAN id of outgoing frame */ uint32_t dst_priority; /* The 802.1p priority */ -} INMExtended_switch; +} SFLExtended_switch; /* Extended router data */ -typedef struct _INMExtended_router { - INMAddress nexthop; /* IP address of next hop router */ +typedef struct _SFLExtended_router { + SFLAddress nexthop; /* IP address of next hop router */ uint32_t src_mask; /* Source address prefix mask bits */ uint32_t dst_mask; /* Destination address prefix mask bits */ -} INMExtended_router; +} SFLExtended_router; /* Extended gateway data */ - -enum INMExtended_as_path_segment_type { - INMEXTENDED_AS_SET = 1, /* Unordered set of ASs */ - INMEXTENDED_AS_SEQUENCE = 2 /* Ordered sequence of ASs */ +enum SFLExtended_as_path_segment_type { + SFLEXTENDED_AS_SET = 1, /* Unordered set of ASs */ + SFLEXTENDED_AS_SEQUENCE = 2 /* Ordered sequence of ASs */ }; - -typedef struct _INMExtended_as_path_segment { - uint32_t type; /* enum INMExtended_as_path_segment_type */ + +typedef struct _SFLExtended_as_path_segment { + uint32_t type; /* enum SFLExtended_as_path_segment_type */ uint32_t length; /* number of AS numbers in set/sequence */ union { uint32_t *set; uint32_t *seq; } as; -} INMExtended_as_path_segment; +} SFLExtended_as_path_segment; -/* note: the INMExtended_gateway structure has changed between v2 and v4. - Here is the old version first... */ - -typedef struct _INMExtended_gateway_v2 { - uint32_t as; /* AS number for this gateway */ - uint32_t src_as; /* AS number of source (origin) */ - uint32_t src_peer_as; /* AS number of source peer */ - uint32_t dst_as_path_length; /* number of AS numbers in path */ - uint32_t *dst_as_path; -} INMExtended_gateway_v2; - -/* now here is the new version... */ - -typedef struct _INMExtended_gateway_v4 { +typedef struct _SFLExtended_gateway { + SFLAddress nexthop; /* Address of the border router that should + be used for the destination network */ uint32_t as; /* AS number for this gateway */ uint32_t src_as; /* AS number of source (origin) */ uint32_t src_peer_as; /* AS number of source peer */ uint32_t dst_as_path_segments; /* number of segments in path */ - INMExtended_as_path_segment *dst_as_path; /* list of seqs or sets */ + SFLExtended_as_path_segment *dst_as_path; /* list of seqs or sets */ uint32_t communities_length; /* number of communities */ uint32_t *communities; /* set of communities */ uint32_t localpref; /* LocalPref associated with this route */ -} INMExtended_gateway_v4; +} SFLExtended_gateway; + +typedef struct _SFLString { + uint32_t len; + char *str; +} SFLString; /* Extended user data */ -typedef struct _INMExtended_user { - uint32_t src_user_len; - char *src_user; - uint32_t dst_user_len; - char *dst_user; -} INMExtended_user; -enum INMExtended_url_direction { - INMEXTENDED_URL_SRC = 1, /* URL is associated with source address */ - INMEXTENDED_URL_DST = 2 /* URL is associated with destination address */ + +typedef struct _SFLExtended_user { + uint32_t src_charset; /* MIBEnum value of character set used to encode a string - See RFC 2978 + Where possible UTF-8 encoding (MIBEnum=106) should be used. A value + of zero indicates an unknown encoding. */ + SFLString src_user; + uint32_t dst_charset; + SFLString dst_user; +} SFLExtended_user; + +/* Extended URL data */ + +enum SFLExtended_url_direction { + SFLEXTENDED_URL_SRC = 1, /* URL is associated with source address */ + SFLEXTENDED_URL_DST = 2 /* URL is associated with destination address */ }; -typedef struct _INMExtended_url { - uint32_t direction; /* enum INMExtended_url_direction */ - uint32_t url_len; - char *url; -} INMExtended_url; +typedef struct _SFLExtended_url { + uint32_t direction; /* enum SFLExtended_url_direction */ + SFLString url; /* URL associated with the packet flow. + Must be URL encoded */ + SFLString host; /* The host field from the HTTP header */ +} SFLExtended_url; -/* Extended data */ +/* Extended MPLS data */ -enum INMExtended_information_type { - INMEXTENDED_SWITCH = 1, /* Extended switch information */ - INMEXTENDED_ROUTER = 2, /* Extended router information */ - INMEXTENDED_GATEWAY = 3, /* Extended gateway router information */ - INMEXTENDED_USER = 4, /* Extended TACAS/RADIUS user information */ - INMEXTENDED_URL = 5 /* Extended URL information */ +typedef struct _SFLLabelStack { + uint32_t depth; + uint32_t *stack; /* first entry is top of stack - see RFC 3032 for encoding */ +} SFLLabelStack; + +typedef struct _SFLExtended_mpls { + SFLAddress nextHop; /* Address of the next hop */ + SFLLabelStack in_stack; + SFLLabelStack out_stack; +} SFLExtended_mpls; + + /* Extended NAT data + Packet header records report addresses as seen at the sFlowDataSource. + The extended_nat structure reports on translated source and/or destination + addesses for this packet. If an address was not translated it should + be equal to that reported for the header. */ + +typedef struct _SFLExtended_nat { + SFLAddress src; /* Source address */ + SFLAddress dst; /* Destination address */ +} SFLExtended_nat; + +typedef struct _SFLExtended_nat_port { + uint32_t src_port; + uint32_t dst_port; +} SFLExtended_nat_port; + + /* additional Extended MPLS stucts */ + +typedef struct _SFLExtended_mpls_tunnel { + SFLString tunnel_lsp_name; /* Tunnel name */ + uint32_t tunnel_id; /* Tunnel ID */ + uint32_t tunnel_cos; /* Tunnel COS value */ +} SFLExtended_mpls_tunnel; + +typedef struct _SFLExtended_mpls_vc { + SFLString vc_instance_name; /* VC instance name */ + uint32_t vll_vc_id; /* VLL/VC instance ID */ + uint32_t vc_label_cos; /* VC Label COS value */ +} SFLExtended_mpls_vc; + +/* Extended MPLS FEC + - Definitions from MPLS-FTN-STD-MIB mplsFTNTable */ + +typedef struct _SFLExtended_mpls_FTN { + SFLString mplsFTNDescr; + uint32_t mplsFTNMask; +} SFLExtended_mpls_FTN; + +/* Extended MPLS LVP FEC + - Definition from MPLS-LDP-STD-MIB mplsFecTable + Note: mplsFecAddrType, mplsFecAddr information available + from packet header */ + +typedef struct _SFLExtended_mpls_LDP_FEC { + uint32_t mplsFecAddrPrefixLength; +} SFLExtended_mpls_LDP_FEC; + +/* Extended VLAN tunnel information + Record outer VLAN encapsulations that have + been stripped. extended_vlantunnel information + should only be reported if all the following conditions are satisfied: + 1. The packet has nested vlan tags, AND + 2. The reporting device is VLAN aware, AND + 3. One or more VLAN tags have been stripped, either + because they represent proprietary encapsulations, or + because switch hardware automatically strips the outer VLAN + encapsulation. + Reporting extended_vlantunnel information is not a substitute for + reporting extended_switch information. extended_switch data must + always be reported to describe the ingress/egress VLAN information + for the packet. The extended_vlantunnel information only applies to + nested VLAN tags, and then only when one or more tags has been + stripped. */ + +typedef SFLLabelStack SFLVlanStack; +typedef struct _SFLExtended_vlan_tunnel { + SFLVlanStack stack; /* List of stripped 802.1Q TPID/TCI layers. Each + TPID,TCI pair is represented as a single 32 bit + integer. Layers listed from outermost to + innermost. */ +} SFLExtended_vlan_tunnel; + +/* + ////////////////// IEEE 802.11 Extension structs //////////////////// + + The 4-byte cipher_suite identifier follows the format of the cipher suite + selector value from the 802.11i (TKIP/CCMP amendment to 802.11i) + The most significant three bytes contain the OUI and the least significant + byte contains the Suite Type. + + The currently assigned values are: + + OUI |Suite type |Meaning + ---------------------------------------------------- + 00-0F-AC | 0 | Use group cipher suite + 00-0F-AC | 1 | WEP-40 + 00-0F-AC | 2 | TKIP + 00-0F-AC | 3 | Reserved + 00-0F-AC | 4 | CCMP + 00-0F-AC | 5 | WEP-104 + 00-0F-AC | 6-255 | Reserved + Vendor OUI | Other | Vendor specific + Other | Any | Reserved + ---------------------------------------------------- +*/ + +typedef uint32_t SFLCipherSuite; + +/* Extended wifi Payload + Used to provide unencrypted version of 802.11 MAC data. If the + MAC data is not encrypted then the agent must not include an + extended_wifi_payload structure. + If 802.11 MAC data is encrypted then the sampled_header structure + should only contain the MAC header (since encrypted data cannot + be decoded by the sFlow receiver). If the sFlow agent has access to + the unencrypted payload, it should add an extended_wifi_payload + structure containing the unencrypted data bytes from the sampled + packet header, starting at the beginning of the 802.2 LLC and not + including any trailing encryption footers. */ +/* opaque = flow_data; enterprise = 0; format = 1013 */ + +typedef struct _SFLExtended_wifi_payload { + SFLCipherSuite cipherSuite; + SFLSampled_header header; +} SFLExtended_wifi_payload; + +typedef enum { + IEEE80211_A=1, + IEEE80211_B=2, + IEEE80211_G=3, + IEEE80211_N=4, +} SFL_IEEE80211_version; + +/* opaque = flow_data; enterprise = 0; format = 1014 */ + +#define SFL_MAX_SSID_LEN 256 + +typedef struct _SFLExtended_wifi_rx { + uint32_t ssid_len; + char *ssid; + char bssid[6]; /* BSSID */ + SFL_IEEE80211_version version; /* version */ + uint32_t channel; /* channel number */ + uint64_t speed; + uint32_t rsni; /* received signal to noise ratio, see dot11FrameRprtRSNI */ + uint32_t rcpi; /* received channel power, see dot11FrameRprtLastRCPI */ + uint32_t packet_duration_us; /* amount of time that the successfully received pkt occupied RF medium.*/ +} SFLExtended_wifi_rx; + +/* opaque = flow_data; enterprise = 0; format = 1015 */ + +typedef struct _SFLExtended_wifi_tx { + uint32_t ssid_len; + char *ssid; /* SSID string */ + char bssid[6]; /* BSSID */ + SFL_IEEE80211_version version; /* version */ + uint32_t transmissions; /* number of transmissions for sampled + packet. + 0 = unkown + 1 = packet was successfully transmitted + on first attempt + n > 1 = n - 1 retransmissions */ + uint32_t packet_duration_us; /* amount of time that the successfully + transmitted packet occupied the + RF medium */ + uint32_t retrans_duration_us; /* amount of time that failed transmission + attempts occupied the RF medium */ + uint32_t channel; /* channel number */ + uint64_t speed; + uint32_t power_mw; /* transmit power in mW. */ +} SFLExtended_wifi_tx; + +/* Extended 802.11 Aggregation Data */ +/* A flow_sample of an aggregated frame would consist of a packet + header for the whole frame + any other extended structures that + apply (e.g. 80211_tx/rx etc.) + an extended_wifi_aggregation + structure which would contain an array of pdu structures (one + for each PDU in the aggregate). A pdu is simply an array of + flow records, in the simplest case a packet header for each PDU, + but extended structures could be included as well. */ + +/* opaque = flow_data; enterprise = 0; format = 1016 */ + +struct _SFLFlow_Pdu; /* forward decl */ + +typedef struct _SFLExtended_aggregation { + uint32_t num_pdus; + struct _SFFlow_Pdu *pdus; +} SFLExtended_aggregation; +/* TCP connection state */ +/* Based on struct tcp_info in /usr/include/linux/tcp.h */ +/* opaque = flow_data; enterprise=0; format=2209 */ + +typedef enum { + PKTDIR_unknown = 0, + PKTDIR_received = 1, + PKTDIR_sent = 2 +} EnumPktDirection; + +typedef struct _SFLExtended_TCP_info { + uint32_t dirn; /* EnumPktDirection: Sampled packet direction */ + uint32_t snd_mss; /* Cached effective mss, not including SACKS */ + uint32_t rcv_mss; /* Max. recv. segment size */ + uint32_t unacked; /* Packets which are "in flight" */ + uint32_t lost; /* Lost packets */ + uint32_t retrans; /* Retransmitted packets */ + uint32_t pmtu; /* Last pmtu seen by socket */ + uint32_t rtt; /* smoothed RTT (microseconds) */ + uint32_t rttvar; /* RTT variance (microseconds) */ + uint32_t snd_cwnd; /* Sending congestion window */ + uint32_t reordering; /* Reordering */ + uint32_t min_rtt; /* Minimum RTT (microseconds) */ +} SFLExtended_TCP_info; + +#define XDRSIZ_SFLEXTENDED_TCP_INFO 48 + +/* Extended socket information, + Must be filled in for all application transactions associated with a network socket + Omit if transaction associated with non-network IPC */ + +/* IPv4 Socket */ +/* opaque = flow_data; enterprise = 0; format = 2100 */ +typedef struct _SFLExtended_socket_ipv4 { + uint32_t protocol; /* IP Protocol (e.g. TCP = 6, UDP = 17) */ + SFLIPv4 local_ip; /* local IP address */ + SFLIPv4 remote_ip; /* remote IP address */ + uint32_t local_port; /* TCP/UDP local port number or equivalent */ + uint32_t remote_port; /* TCP/UDP remote port number of equivalent */ +} SFLExtended_socket_ipv4; + +#define XDRSIZ_SFLEXTENDED_SOCKET4 20 + +/* IPv6 Socket */ +/* opaque = flow_data; enterprise = 0; format = 2101 */ +typedef struct _SFLExtended_socket_ipv6 { + uint32_t protocol; /* IP Protocol (e.g. TCP = 6, UDP = 17) */ + SFLIPv6 local_ip; /* local IP address */ + SFLIPv6 remote_ip; /* remote IP address */ + uint32_t local_port; /* TCP/UDP local port number or equivalent */ + uint32_t remote_port; /* TCP/UDP remote port number of equivalent */ +} SFLExtended_socket_ipv6; + +#define XDRSIZ_SFLEXTENDED_SOCKET6 44 + +typedef enum { + MEMCACHE_PROT_OTHER = 0, + MEMCACHE_PROT_ASCII = 1, + MEMCACHE_PROT_BINARY = 2 +} SFLMemcache_prot; + +typedef enum { + MEMCACHE_CMD_OTHER = 0, + MEMCACHE_CMD_SET = 1, + MEMCACHE_CMD_ADD = 2, + MEMCACHE_CMD_REPLACE = 3, + MEMCACHE_CMD_APPEND = 4, + MEMCACHE_CMD_PREPEND = 5, + MEMCACHE_CMD_CAS = 6, + MEMCACHE_CMD_GET = 7, + MEMCACHE_CMD_GETS = 8, + MEMCACHE_CMD_INCR = 9, + MEMCACHE_CMD_DECR = 10, + MEMCACHE_CMD_DELETE = 11, + MEMCACHE_CMD_STATS = 12, + MEMCACHE_CMD_FLUSH = 13, + MEMCACHE_CMD_VERSION = 14, + MEMCACHE_CMD_QUIT = 15, + MEMCACHE_CMD_TOUCH = 16 +} SFLMemcache_cmd; + +enum SFLMemcache_operation_status { + MEMCACHE_OP_UNKNOWN = 0, + MEMCACHE_OP_OK = 1, + MEMCACHE_OP_ERROR = 2, + MEMCACHE_OP_CLIENT_ERROR = 3, + MEMCACHE_OP_SERVER_ERROR = 4, + MEMCACHE_OP_STORED = 5, + MEMCACHE_OP_NOT_STORED = 6, + MEMCACHE_OP_EXISTS = 7, + MEMCACHE_OP_NOT_FOUND = 8, + MEMCACHE_OP_DELETED = 9 }; -/* Format of a single sample */ +#define SFL_MAX_MEMCACHE_KEY 255 -typedef struct _INMFlow_sample { +typedef struct _SFLSampled_memcache { + uint32_t protocol; /* SFLMemcache_prot */ + uint32_t command; /* SFLMemcache_cmd */ + SFLString key; /* up to 255 chars */ + uint32_t nkeys; + uint32_t value_bytes; + uint32_t duration_uS; + uint32_t status; /* SFLMemcache_operation_status */ +} SFLSampled_memcache; + +typedef enum { + SFHTTP_OTHER = 0, + SFHTTP_OPTIONS = 1, + SFHTTP_GET = 2, + SFHTTP_HEAD = 3, + SFHTTP_POST = 4, + SFHTTP_PUT = 5, + SFHTTP_DELETE = 6, + SFHTTP_TRACE = 7, + SFHTTP_CONNECT = 8 +} SFLHTTP_method; + +#define SFL_MAX_HTTP_URI 255 +#define SFL_MAX_HTTP_HOST 64 +#define SFL_MAX_HTTP_REFERRER 255 +#define SFL_MAX_HTTP_USERAGENT 128 +#define SFL_MAX_HTTP_XFF 64 +#define SFL_MAX_HTTP_AUTHUSER 32 +#define SFL_MAX_HTTP_MIMETYPE 64 + +typedef struct _SFLSampled_http { + SFLHTTP_method method; + uint32_t protocol; /* 1.1=1001 */ + SFLString uri; /* URI exactly as it came from the client (up to 255 bytes) */ + SFLString host; /* Host value from request header (<= 64 bytes) */ + SFLString referrer; /* Referer value from request header (<=255 bytes) */ + SFLString useragent; /* User-Agent value from request header (<= 128 bytes)*/ + SFLString xff; /* X-Forwarded-For value from request header (<= 64 bytes)*/ + SFLString authuser; /* RFC 1413 identity of user (<=32 bytes)*/ + SFLString mimetype; /* Mime-Type (<=64 bytes) */ + uint64_t req_bytes; /* Content-Length of request */ + uint64_t resp_bytes; /* Content-Length of response */ + uint32_t uS; /* duration of the operation (microseconds) */ + uint32_t status; /* HTTP status code */ +} SFLSampled_http; + + +typedef enum { + SFLAPP_SUCCESS = 0, + SFLAPP_OTHER = 1, + SFLAPP_TIMEOUT = 2, + SFLAPP_INTERNAL_ERROR = 3, + SFLAPP_BAD_REQUEST = 4, + SFLAPP_FORBIDDEN = 5, + SFLAPP_TOO_LARGE = 6, + SFLAPP_NOT_IMPLEMENTED = 7, + SFLAPP_NOT_FOUND = 8, + SFLAPP_UNAVAILABLE = 9, + SFLAPP_UNAUTHORIZED = 10, + SFLAPP_NUM_STATUS_CODES +} EnumSFLAPPStatus; + + static const char *SFL_APP_STATUS_names[] = { "SUCCESS", + "OTHER", + "TIMEOUT", + "INTERNAL_ERROR", + "BAD_REQUEST", + "FORBIDDEN", + "TOO_LARGE", + "NOT_IMPLEMENTED", + "NOT_FOUND", + "UNAVAILABLE", + "UNATHORIZED" }; + +/* Operation context */ +typedef struct { + SFLString application; + SFLString operation; /* type of operation (e.g. authorization, payment) */ + SFLString attributes; /* specific attributes associated operation */ +} SFLSampled_APP_CTXT; + +#define SFLAPP_MAX_APPLICATION_LEN 32 +#define SFLAPP_MAX_OPERATION_LEN 32 +#define SFLAPP_MAX_ATTRIBUTES_LEN 255 + +/* Sampled Enterprise Operation */ +/* opaque = flow_data; enterprise = 0; format = 2202 */ +typedef struct { + SFLSampled_APP_CTXT context; /* attributes describing the operation */ + SFLString status_descr; /* additional text describing status (e.g. "unknown client") */ + uint64_t req_bytes; /* size of request body (exclude headers) */ + uint64_t resp_bytes; /* size of response body (exclude headers) */ + uint32_t duration_uS; /* duration of the operation (microseconds) */ + EnumSFLAPPStatus status; /* status code */ +} SFLSampled_APP; + +#define SFLAPP_MAX_STATUS_LEN 32 + +typedef struct { + SFLString actor; +} SFLSampled_APP_ACTOR; + +#define SFLAPP_MAX_ACTOR_LEN 64 + +typedef struct _SFLExtended_vni { + uint32_t vni; /* virtual network identifier */ +} SFLExtended_vni; + +typedef struct _SFLExtended_decap { + uint32_t innerHeaderOffset; +} SFLExtended_decap; + +enum SFLFlow_type_tag { + /* enterprise = 0, format = ... */ + SFLFLOW_HEADER = 1, /* Packet headers are sampled */ + SFLFLOW_ETHERNET = 2, /* MAC layer information */ + SFLFLOW_IPV4 = 3, /* IP version 4 data */ + SFLFLOW_IPV6 = 4, /* IP version 6 data */ + SFLFLOW_EX_SWITCH = 1001, /* Extended switch information */ + SFLFLOW_EX_ROUTER = 1002, /* Extended router information */ + SFLFLOW_EX_GATEWAY = 1003, /* Extended gateway router information */ + SFLFLOW_EX_USER = 1004, /* Extended TACAS/RADIUS user information */ + SFLFLOW_EX_URL = 1005, /* Extended URL information */ + SFLFLOW_EX_MPLS = 1006, /* Extended MPLS information */ + SFLFLOW_EX_NAT = 1007, /* Extended NAT information */ + SFLFLOW_EX_MPLS_TUNNEL = 1008, /* additional MPLS information */ + SFLFLOW_EX_MPLS_VC = 1009, + SFLFLOW_EX_MPLS_FTN = 1010, + SFLFLOW_EX_MPLS_LDP_FEC = 1011, + SFLFLOW_EX_VLAN_TUNNEL = 1012, /* VLAN stack */ + SFLFLOW_EX_80211_PAYLOAD = 1013, + SFLFLOW_EX_80211_RX = 1014, + SFLFLOW_EX_80211_TX = 1015, + SFLFLOW_EX_AGGREGATION = 1016, + SFLFLOW_EX_NAT_PORT = 1020, /* Extended NAT port information */ + SFLFLOW_EX_L2_TUNNEL_OUT = 1021, /* http://sflow.org/sflow_tunnels.txt */ + SFLFLOW_EX_L2_TUNNEL_IN = 1022, + SFLFLOW_EX_IPV4_TUNNEL_OUT = 1023, + SFLFLOW_EX_IPV4_TUNNEL_IN = 1024, + SFLFLOW_EX_IPV6_TUNNEL_OUT = 1025, + SFLFLOW_EX_IPV6_TUNNEL_IN = 1026, + SFLFLOW_EX_DECAP_OUT = 1027, + SFLFLOW_EX_DECAP_IN = 1028, + SFLFLOW_EX_VNI_OUT = 1029, + SFLFLOW_EX_VNI_IN = 1030, + SFLFLOW_EX_SOCKET4 = 2100, + SFLFLOW_EX_SOCKET6 = 2101, + SFLFLOW_EX_PROXYSOCKET4 = 2102, + SFLFLOW_EX_PROXYSOCKET6 = 2103, + SFLFLOW_MEMCACHE = 2200, + SFLFLOW_HTTP = 2201, + SFLFLOW_APP = 2202, /* transaction sample */ + SFLFLOW_APP_CTXT = 2203, /* enclosing server context */ + SFLFLOW_APP_ACTOR_INIT = 2204, /* initiator */ + SFLFLOW_APP_ACTOR_TGT = 2205, /* target */ + SFLFLOW_HTTP2 = 2206, + SFLFLOW_EX_TCP_INFO = 2209, +}; + +typedef union _SFLFlow_type { + SFLSampled_header header; + SFLSampled_ethernet ethernet; + SFLSampled_ipv4 ipv4; + SFLSampled_ipv6 ipv6; + SFLSampled_memcache memcache; + SFLSampled_http http; + SFLSampled_APP app; + SFLSampled_APP_CTXT appCtxt; + SFLSampled_APP_ACTOR appActor; + SFLExtended_switch sw; + SFLExtended_router router; + SFLExtended_gateway gateway; + SFLExtended_user user; + SFLExtended_url url; + SFLExtended_mpls mpls; + SFLExtended_nat nat; + SFLExtended_nat_port nat_port; + SFLExtended_mpls_tunnel mpls_tunnel; + SFLExtended_mpls_vc mpls_vc; + SFLExtended_mpls_FTN mpls_ftn; + SFLExtended_mpls_LDP_FEC mpls_ldp_fec; + SFLExtended_vlan_tunnel vlan_tunnel; + SFLExtended_wifi_payload wifi_payload; + SFLExtended_wifi_rx wifi_rx; + SFLExtended_wifi_tx wifi_tx; + SFLExtended_aggregation aggregation; + SFLExtended_socket_ipv4 socket4; + SFLExtended_socket_ipv6 socket6; + SFLExtended_vni tunnel_vni; + SFLExtended_decap tunnel_decap; +} SFLFlow_type; + +typedef struct _SFLFlow_sample_element { + struct _SFLFlow_sample_element *nxt; + uint32_t tag; /* SFLFlow_type_tag */ + uint32_t length; + SFLFlow_type flowType; +} SFLFlow_sample_element; + +enum SFL_sample_tag { + SFLFLOW_SAMPLE = 1, /* enterprise = 0 : format = 1 */ + SFLCOUNTERS_SAMPLE = 2, /* enterprise = 0 : format = 2 */ + SFLFLOW_SAMPLE_EXPANDED = 3, /* enterprise = 0 : format = 3 */ + SFLCOUNTERS_SAMPLE_EXPANDED = 4, /* enterprise = 0 : format = 4 */ + SFLRTMETRIC = ((4300 << 12) + 1002), + SFLRTFLOW = ((4300 << 12) + 1003) +}; + +typedef struct _SFLFlow_Pdu { + struct _SFLFlow_Pdu *nxt; + uint32_t num_elements; + SFLFlow_sample_element *elements; +} SFLFlow_Pdu; + + +/* Format of a single flow sample */ + +typedef struct _SFLFlow_sample { + /* uint32_t tag; */ /* SFL_sample_tag -- enterprise = 0 : format = 1 */ + /* uint32_t length; */ uint32_t sequence_number; /* Incremented with each flow sample generated */ uint32_t source_id; /* fsSourceId */ @@ -327,37 +724,44 @@ typedef struct _INMFlow_sample { 0x80000000 indicates a packet sent to an unknown number of interfaces greater than 1.*/ - uint32_t packet_data_tag; /* enum INMPacket_information_type */ - INMPacket_data_type packet_data; /* Information about sampled packet */ + uint32_t num_elements; + SFLFlow_sample_element *elements; +} SFLFlow_sample; - /* in the sFlow packet spec the next field is the number of extended objects - followed by the data for each one (tagged with the type). Here we just - provide space for each one, and flags to enable them. The correct format - is then put together by the serialization code */ - int gotSwitch; - INMExtended_switch switchDevice; - int gotRouter; - INMExtended_router router; - int gotGateway; - union { - INMExtended_gateway_v2 sf_v2; /* make the version explicit so that there is */ - INMExtended_gateway_v4 sf_v4; /* less danger of mistakes when upgrading code */ - } gateway; - int gotUser; - INMExtended_user user; - int gotUrl; - INMExtended_url url; -} INMFlow_sample; + /* same thing, but the expanded version (for full 32-bit ifIndex numbers) */ + +typedef struct _SFLFlow_sample_expanded { + /* uint32_t tag; */ /* SFL_sample_tag -- enterprise = 0 : format = 1 */ + /* uint32_t length; */ + uint32_t sequence_number; /* Incremented with each flow sample + generated */ + uint32_t ds_class; /* EXPANDED */ + uint32_t ds_index; /* EXPANDED */ + uint32_t sampling_rate; /* fsPacketSamplingRate */ + uint32_t sample_pool; /* Total number of packets that could have been + sampled (i.e. packets skipped by sampling + process + total number of samples) */ + uint32_t drops; /* Number of times a packet was dropped due to + lack of resources */ + uint32_t inputFormat; /* EXPANDED */ + uint32_t input; /* SNMP ifIndex of input interface. + 0 if interface is not known. */ + uint32_t outputFormat; /* EXPANDED */ + uint32_t output; /* SNMP ifIndex of output interface, + 0 if interface is not known. */ + uint32_t num_elements; + SFLFlow_sample_element *elements; +} SFLFlow_sample_expanded; /* Counter types */ /* Generic interface counters - see RFC 1573, 2233 */ -typedef struct _INMIf_counters { +typedef struct _SFLIf_counters { uint32_t ifIndex; uint32_t ifType; uint64_t ifSpeed; - uint32_t ifDirection; /* Derived from MAU MIB (RFC 2239) + uint32_t ifDirection; /* Derived from MAU MIB (RFC 2668) 0 = unknown, 1 = full-duplex, 2 = half-duplex, 3 = in, 4 = out */ uint32_t ifStatus; /* bit field with the following bits assigned: @@ -377,10 +781,10 @@ typedef struct _INMIf_counters { uint32_t ifOutDiscards; uint32_t ifOutErrors; uint32_t ifPromiscuousMode; -} INMIf_counters; +} SFLIf_counters; /* Ethernet interface counters - see RFC 2358 */ -typedef struct _INMEthernet_specific_counters { +typedef struct _SFLEthernet_counters { uint32_t dot3StatsAlignmentErrors; uint32_t dot3StatsFCSErrors; uint32_t dot3StatsSingleCollisionFrames; @@ -394,21 +798,11 @@ typedef struct _INMEthernet_specific_counters { uint32_t dot3StatsFrameTooLongs; uint32_t dot3StatsInternalMacReceiveErrors; uint32_t dot3StatsSymbolErrors; -} INMEthernet_specific_counters; - -typedef struct _INMEthernet_counters { - INMIf_counters generic; - INMEthernet_specific_counters ethernet; -} INMEthernet_counters; - -/* FDDI interface counters - see RFC 1512 */ -typedef struct _INMFddi_counters { - INMIf_counters generic; -} INMFddi_counters; +} SFLEthernet_counters; /* Token ring counters - see RFC 1748 */ -typedef struct _INMTokenring_specific_counters { +typedef struct _SFLTokenring_counters { uint32_t dot5StatsLineErrors; uint32_t dot5StatsBurstErrors; uint32_t dot5StatsACErrors; @@ -427,16 +821,11 @@ typedef struct _INMTokenring_specific_counters { uint32_t dot5StatsRemoves; uint32_t dot5StatsSingles; uint32_t dot5StatsFreqErrors; -} INMTokenring_specific_counters; - -typedef struct _INMTokenring_counters { - INMIf_counters generic; - INMTokenring_specific_counters tokenring; -} INMTokenring_counters; +} SFLTokenring_counters; /* 100 BaseVG interface counters - see RFC 2020 */ -typedef struct _INMVg_specific_counters { +typedef struct _SFLVg_counters { uint32_t dot12InHighPriorityFrames; uint64_t dot12InHighPriorityOctets; uint32_t dot12InNormPriorityFrames; @@ -451,121 +840,810 @@ typedef struct _INMVg_specific_counters { uint64_t dot12HCInHighPriorityOctets; uint64_t dot12HCInNormPriorityOctets; uint64_t dot12HCOutHighPriorityOctets; -} INMVg_specific_counters; +} SFLVg_counters; -typedef struct _INMVg_counters { - INMIf_counters generic; - INMVg_specific_counters vg; -} INMVg_counters; - -/* WAN counters */ - -typedef struct _INMWan_counters { - INMIf_counters generic; -} INMWan_counters; - -typedef struct _INMVlan_counters { +typedef struct _SFLVlan_counters { uint32_t vlan_id; uint64_t octets; uint32_t ucastPkts; uint32_t multicastPkts; uint32_t broadcastPkts; uint32_t discards; -} INMVlan_counters; +} SFLVlan_counters; + +typedef struct _SFLWifi_counters { + uint32_t dot11TransmittedFragmentCount; + uint32_t dot11MulticastTransmittedFrameCount; + uint32_t dot11FailedCount; + uint32_t dot11RetryCount; + uint32_t dot11MultipleRetryCount; + uint32_t dot11FrameDuplicateCount; + uint32_t dot11RTSSuccessCount; + uint32_t dot11RTSFailureCount; + uint32_t dot11ACKFailureCount; + uint32_t dot11ReceivedFragmentCount; + uint32_t dot11MulticastReceivedFrameCount; + uint32_t dot11FCSErrorCount; + uint32_t dot11TransmittedFrameCount; + uint32_t dot11WEPUndecryptableCount; + uint32_t dot11QoSDiscardedFragmentCount; + uint32_t dot11AssociatedStationCount; + uint32_t dot11QoSCFPollsReceivedCount; + uint32_t dot11QoSCFPollsUnusedCount; + uint32_t dot11QoSCFPollsUnusableCount; + uint32_t dot11QoSCFPollsLostCount; +} SFLWifi_counters; + +/* Processor Information */ +/* opaque = counter_data; enterprise = 0; format = 1001 */ + +typedef struct _SFLProcessor_counters { + uint32_t five_sec_cpu; /* 5 second average CPU utilization */ + uint32_t one_min_cpu; /* 1 minute average CPU utilization */ + uint32_t five_min_cpu; /* 5 minute average CPU utilization */ + uint64_t total_memory; /* total memory (in bytes) */ + uint64_t free_memory; /* free memory (in bytes) */ +} SFLProcessor_counters; + +typedef struct _SFLRadio_counters { + uint32_t elapsed_time; /* elapsed time in ms */ + uint32_t on_channel_time; /* time in ms spent on channel */ + uint32_t on_channel_busy_time; /* time in ms spent on channel and busy */ +} SFLRadio_counters; + + /* host sflow */ + +enum SFLMachine_type { + SFLMT_unknown = 0, + SFLMT_other = 1, + SFLMT_x86 = 2, + SFLMT_x86_64 = 3, + SFLMT_ia64 = 4, + SFLMT_sparc = 5, + SFLMT_alpha = 6, + SFLMT_powerpc = 7, + SFLMT_m68k = 8, + SFLMT_mips = 9, + SFLMT_arm = 10, + SFLMT_hppa = 11, + SFLMT_s390 = 12 +}; + +enum SFLOS_name { + SFLOS_unknown = 0, + SFLOS_other = 1, + SFLOS_linux = 2, + SFLOS_windows = 3, + SFLOS_darwin = 4, + SFLOS_hpux = 5, + SFLOS_aix = 6, + SFLOS_dragonfly = 7, + SFLOS_freebsd = 8, + SFLOS_netbsd = 9, + SFLOS_openbsd = 10, + SFLOS_osf = 11, + SFLOS_solaris = 12 +}; + +typedef struct _SFLMacAddress { + uint8_t mac[8]; +} SFLMacAddress; + +typedef struct _SFLAdaptor { + uint32_t ifIndex; + uint32_t num_macs; + SFLMacAddress macs[1]; +} SFLAdaptor; + +typedef struct _SFLAdaptorList { + uint32_t capacity; + uint32_t num_adaptors; + SFLAdaptor **adaptors; +} SFLAdaptorList; + +typedef struct _SFLHost_parent { + uint32_t dsClass; /* sFlowDataSource class */ + uint32_t dsIndex; /* sFlowDataSource index */ +} SFLHost_parent; + + +#define SFL_MAX_HOSTNAME_LEN 64 +#define SFL_MAX_OSRELEASE_LEN 32 + +typedef struct _SFLHostId { + SFLString hostname; + uint8_t uuid[16]; + uint32_t machine_type; /* enum SFLMachine_type */ + uint32_t os_name; /* enum SFLOS_name */ + SFLString os_release; /* max len 32 bytes */ +} SFLHostId; + +typedef struct _SFLHost_nio_counters { + uint64_t bytes_in; + uint32_t pkts_in; + uint32_t errs_in; + uint32_t drops_in; + uint64_t bytes_out; + uint32_t pkts_out; + uint32_t errs_out; + uint32_t drops_out; +} SFLHost_nio_counters; + +typedef struct _SFLHost_cpu_counters { + float load_one; /* 1 minute load avg. */ + float load_five; /* 5 minute load avg. */ + float load_fifteen; /* 15 minute load avg. */ + uint32_t proc_run; /* running threads */ + uint32_t proc_total; /* total threads */ + uint32_t cpu_num; /* # CPU cores */ + uint32_t cpu_speed; /* speed in MHz of CPU */ + uint32_t uptime; /* seconds since last reboot */ + uint32_t cpu_user; /* time executing in user mode processes (ms) */ + uint32_t cpu_nice; /* time executing niced processs (ms) */ + uint32_t cpu_system; /* time executing kernel mode processes (ms) */ + uint32_t cpu_idle; /* idle time (ms) */ + uint32_t cpu_wio; /* time waiting for I/O to complete (ms) */ + uint32_t cpu_intr; /* time servicing interrupts (ms) */ + uint32_t cpu_sintr; /* time servicing softirqs (ms) */ + uint32_t interrupts; /* interrupt count */ + uint32_t contexts; /* context switch count */ + uint32_t cpu_steal; /* time spent in other OS instances (virtual env) (ms) */ + uint32_t cpu_guest; /* time spent running vcpu for guest OS */ + uint32_t cpu_guest_nice; /* time spent running vcpu for "niced" guest OS */ +} SFLHost_cpu_counters; + +typedef struct _SFLHost_mem_counters { + uint64_t mem_total; /* total bytes */ + uint64_t mem_free; /* free bytes */ + uint64_t mem_shared; /* shared bytes */ + uint64_t mem_buffers; /* buffers bytes */ + uint64_t mem_cached; /* cached bytes */ + uint64_t swap_total; /* swap total bytes */ + uint64_t swap_free; /* swap free bytes */ + uint32_t page_in; /* page in count */ + uint32_t page_out; /* page out count */ + uint32_t swap_in; /* swap in count */ + uint32_t swap_out; /* swap out count */ +} SFLHost_mem_counters; + +typedef struct _SFLHost_dsk_counters { + uint64_t disk_total; + uint64_t disk_free; + uint32_t part_max_used; /* as percent * 100, so 100==1% */ + uint32_t reads; /* reads issued */ + uint64_t bytes_read; /* bytes read */ + uint32_t read_time; /* read time (ms) */ + uint32_t writes; /* writes completed */ + uint64_t bytes_written; /* bytes written */ + uint32_t write_time; /* write time (ms) */ +} SFLHost_dsk_counters; + +/* Virtual Node Statistics */ +/* opaque = counter_data; enterprise = 0; format = 2100 */ + +typedef struct _SFLHost_vrt_node_counters { + uint32_t mhz; /* expected CPU frequency */ + uint32_t cpus; /* the number of active CPUs */ + uint64_t memory; /* memory size in bytes */ + uint64_t memory_free; /* unassigned memory in bytes */ + uint32_t num_domains; /* number of active domains */ +} SFLHost_vrt_node_counters; + +/* Virtual Domain Statistics */ +/* opaque = counter_data; enterprise = 0; format = 2101 */ + +/* virDomainState imported from libvirt.h */ +enum SFLVirDomainState { + SFL_VIR_DOMAIN_NOSTATE = 0, /* no state */ + SFL_VIR_DOMAIN_RUNNING = 1, /* the domain is running */ + SFL_VIR_DOMAIN_BLOCKED = 2, /* the domain is blocked on resource */ + SFL_VIR_DOMAIN_PAUSED = 3, /* the domain is paused by user */ + SFL_VIR_DOMAIN_SHUTDOWN= 4, /* the domain is being shut down */ + SFL_VIR_DOMAIN_SHUTOFF = 5, /* the domain is shut off */ + SFL_VIR_DOMAIN_CRASHED = 6 /* the domain is crashed */ +}; + +typedef struct _SFLHost_vrt_cpu_counters { + uint32_t state; /* virtDomainState */ + uint32_t cpuTime; /* the CPU time used in mS */ + uint32_t cpuCount; /* number of virtual CPUs for the domain */ +} SFLHost_vrt_cpu_counters; + +/* Virtual Domain Memory statistics */ +/* opaque = counter_data; enterprise = 0; format = 2102 */ + +typedef struct _SFLHost_vrt_mem_counters { + uint64_t memory; /* memory in bytes used by domain */ + uint64_t maxMemory; /* memory in bytes allowed */ +} SFLHost_vrt_mem_counters; + +/* Virtual Domain Disk statistics */ +/* opaque = counter_data; enterprise = 0; format = 2103 */ + +typedef struct _SFLHost_vrt_dsk_counters { + uint64_t capacity; /* logical size in bytes */ + uint64_t allocation; /* current allocation in bytes */ + uint64_t available; /* remaining free bytes */ + uint32_t rd_req; /* number of read requests */ + uint64_t rd_bytes; /* number of read bytes */ + uint32_t wr_req; /* number of write requests */ + uint64_t wr_bytes; /* number of written bytes */ + uint32_t errs; /* read/write errors */ +} SFLHost_vrt_dsk_counters; + +/* Virtual Domain Network statistics */ +/* opaque = counter_data; enterprise = 0; format = 2104 */ + +typedef struct _SFLHost_vrt_nio_counters { + uint64_t bytes_in; + uint32_t pkts_in; + uint32_t errs_in; + uint32_t drops_in; + uint64_t bytes_out; + uint32_t pkts_out; + uint32_t errs_out; + uint32_t drops_out; +} SFLHost_vrt_nio_counters; + +/* NVML statistics */ +/* opaque = counter_data; enterprise = 5703, format=1 */ +typedef struct _SFLHost_gpu_nvml { + uint32_t device_count; /* see nvmlGetDeviceCount */ + uint32_t processes; /* see nvmlDeviceGetComputeRunningProcesses */ + uint32_t gpu_time; /* total milliseconds in which one or more kernels was executing on GPU */ + uint32_t mem_time; /* total milliseconds during which global device memory was being read/written */ + uint64_t mem_total; /* bytes. see nvmlDeviceGetMemoryInfo */ + uint64_t mem_free; /* bytes. see nvmlDeviceGetMemoryInfo */ + uint32_t ecc_errors; /* see nvmlDeviceGetTotalEccErrors */ + uint32_t energy; /* mJ. see nvmlDeviceGetPowerUsage */ + uint32_t temperature; /* C. maximum across devices - see nvmlDeviceGetTemperature */ + uint32_t fan_speed; /* %. maximum across devices - see nvmlDeviceGetFanSpeed */ +} SFLHost_gpu_nvml; + +/* Broadcom switch ASIC table utilizations */ +/* opaque = counter_data; enterprise = 4413 (Broadcom); format = 3 */ +typedef struct { + uint32_t bcm_host_entries; + uint32_t bcm_host_entries_max; + uint32_t bcm_ipv4_entries; + uint32_t bcm_ipv4_entries_max; + uint32_t bcm_ipv6_entries; + uint32_t bcm_ipv6_entries_max; + uint32_t bcm_ipv4_ipv6_entries; + uint32_t bcm_ipv4_ipv6_entries_max; + uint32_t bcm_long_ipv6_entries; + uint32_t bcm_long_ipv6_entries_max; + uint32_t bcm_total_routes; + uint32_t bcm_total_routes_max; + uint32_t bcm_ecmp_nexthops; + uint32_t bcm_ecmp_nexthops_max; + uint32_t bcm_mac_entries; + uint32_t bcm_mac_entries_max; + uint32_t bcm_ipv4_neighbors; + uint32_t bcm_ipv6_neighbors; + uint32_t bcm_ipv4_routes; + uint32_t bcm_ipv6_routes; + uint32_t bcm_acl_ingress_entries; + uint32_t bcm_acl_ingress_entries_max; + uint32_t bcm_acl_ingress_counters; + uint32_t bcm_acl_ingress_counters_max; + uint32_t bcm_acl_ingress_meters; + uint32_t bcm_acl_ingress_meters_max; + uint32_t bcm_acl_ingress_slices; + uint32_t bcm_acl_ingress_slices_max; + uint32_t bcm_acl_egress_entries; + uint32_t bcm_acl_egress_entries_max; + uint32_t bcm_acl_egress_counters; + uint32_t bcm_acl_egress_counters_max; + uint32_t bcm_acl_egress_meters; + uint32_t bcm_acl_egress_meters_max; + uint32_t bcm_acl_egress_slices; + uint32_t bcm_acl_egress_slices_max; +} SFLBCM_tables; + + ///////////// TCP/UDP/ICMP from MIB-II /////////////////////// + + /* IP Group - see MIB-II */ + /* opaque = counter_data; enterprise = 0; format = 2007 */ + + typedef struct _SFLHost_IP_counters { + uint32_t ipForwarding; + uint32_t ipDefaultTTL; + uint32_t ipInReceives; + uint32_t ipInHdrErrors; + uint32_t ipInAddrErrors; + uint32_t ipForwDatagrams; + uint32_t ipInUnknownProtos; + uint32_t ipInDiscards; + uint32_t ipInDelivers; + uint32_t ipOutRequests; + uint32_t ipOutDiscards; + uint32_t ipOutNoRoutes; + uint32_t ipReasmTimeout; + uint32_t ipReasmReqds; + uint32_t ipReasmOKs; + uint32_t ipReasmFails; + uint32_t ipFragOKs; + uint32_t ipFragFails; + uint32_t ipFragCreates; + } SFLHost_IP_counters; + + /* ICMP Group - see MIB-II */ + /* opaque = counter_data; enterprise = 0; format = 2008 */ + + typedef struct _SFLHost_ICMP_counters { + uint32_t icmpInMsgs; + uint32_t icmpInErrors; + uint32_t icmpInDestUnreachs; + uint32_t icmpInTimeExcds; + uint32_t icmpInParamProbs; + uint32_t icmpInSrcQuenchs; + uint32_t icmpInRedirects; + uint32_t icmpInEchos; + uint32_t icmpInEchoReps; + uint32_t icmpInTimestamps; + uint32_t icmpInAddrMasks; + uint32_t icmpInAddrMaskReps; + uint32_t icmpOutMsgs; + uint32_t icmpOutErrors; + uint32_t icmpOutDestUnreachs; + uint32_t icmpOutTimeExcds; + uint32_t icmpOutParamProbs; + uint32_t icmpOutSrcQuenchs; + uint32_t icmpOutRedirects; + uint32_t icmpOutEchos; + uint32_t icmpOutEchoReps; + uint32_t icmpOutTimestamps; + uint32_t icmpOutTimestampReps; + uint32_t icmpOutAddrMasks; + uint32_t icmpOutAddrMaskReps; + } SFLHost_ICMP_counters; + + /* TCP Group - see MIB-II */ + /* opaque = counter_data; enterprise = 0; format = 2009 */ + + typedef struct _SFLHost_TCP_counters { + uint32_t tcpRtoAlgorithm; + uint32_t tcpRtoMin; + uint32_t tcpRtoMax; + uint32_t tcpMaxConn; + uint32_t tcpActiveOpens; + uint32_t tcpPassiveOpens; + uint32_t tcpAttemptFails; + uint32_t tcpEstabResets; + uint32_t tcpCurrEstab; + uint32_t tcpInSegs; + uint32_t tcpOutSegs; + uint32_t tcpRetransSegs; + uint32_t tcpInErrs; + uint32_t tcpOutRsts; + uint32_t tcpInCsumErrors; + } SFLHost_TCP_counters; + + /* UDP Group - see MIB-II */ + /* opaque = counter_data; enterprise = 0; format = 2010 */ + + typedef struct _SFLHost_UDP_counters { + uint32_t udpInDatagrams; + uint32_t udpNoPorts; + uint32_t udpInErrors; + uint32_t udpOutDatagrams; + uint32_t udpRcvbufErrors; + uint32_t udpSndbufErrors; + uint32_t udpInCsumErrors; + } SFLHost_UDP_counters; + + /* memcache */ + /* opaque = counter_data; enterprise = 0; format = 2204 */ + +typedef struct _SFLMemcache_counters { + uint32_t uptime; /* not in 2204 */ + uint32_t rusage_user; /* not in 2204 */ + uint32_t rusage_system; /* not in 2204 */ + uint32_t cmd_get; /* not in 2204 */ + uint32_t accepting_conns; /* not in 2204 */ + uint32_t cmd_set; + uint32_t cmd_touch; /* added for 2204 */ + uint32_t cmd_flush; + uint32_t get_hits; + uint32_t get_misses; + uint32_t delete_hits; + uint32_t delete_misses; + uint32_t incr_hits; + uint32_t incr_misses; + uint32_t decr_hits; + uint32_t decr_misses; + uint32_t cas_hits; + uint32_t cas_misses; + uint32_t cas_badval; + uint32_t auth_cmds; + uint32_t auth_errors; + uint32_t threads; + uint32_t conn_yields; + uint32_t listen_disabled_num; + uint32_t curr_connections; + uint32_t rejected_connections; /* added for 2204 */ + uint32_t total_connections; + uint32_t connection_structures; + uint32_t evictions; + uint32_t reclaimed; /* added for 2204 */ + uint32_t curr_items; + uint32_t total_items; + uint64_t bytes_read; + uint64_t bytes_written; + uint64_t bytes; + uint64_t limit_maxbytes; /* converted to 64-bit for structure 2204 */ +} SFLMemcache_counters; + + /* http */ + /* opaque = counter_data; enterprise = 0; format = 2201 */ + +typedef struct _SFLHTTP_counters { + uint32_t method_option_count; + uint32_t method_get_count; + uint32_t method_head_count; + uint32_t method_post_count; + uint32_t method_put_count; + uint32_t method_delete_count; + uint32_t method_trace_count; + uint32_t methd_connect_count; + uint32_t method_other_count; + uint32_t status_1XX_count; + uint32_t status_2XX_count; + uint32_t status_3XX_count; + uint32_t status_4XX_count; + uint32_t status_5XX_count; + uint32_t status_other_count; +} SFLHTTP_counters; + + +/* Enterprise counters */ +/* opaque = counter_data; enterprise = 0; format = 2202 */ +typedef struct _SFLAPP_counters { + SFLString application; + uint32_t status_OK; + uint32_t errors_OTHER; + uint32_t errors_TIMEOUT; + uint32_t errors_INTERNAL_ERROR; + uint32_t errors_BAD_REQUEST; + uint32_t errors_FORBIDDEN; + uint32_t errors_TOO_LARGE; + uint32_t errors_NOT_IMPLEMENTED; + uint32_t errors_NOT_FOUND; + uint32_t errors_UNAVAILABLE; + uint32_t errors_UNAUTHORIZED; +} SFLAPP_counters; + +/* Enterprise resource counters */ +/* opaque = counter_data; enterprise = 0; format = 2203 */ +typedef struct { + uint32_t user_time; /* in milliseconds */ + uint32_t system_time; /* in milliseconds */ + uint64_t mem_used; + uint64_t mem_max; + uint32_t fd_open; + uint32_t fd_max; + uint32_t conn_open; + uint32_t conn_max; +} SFLAPP_resources; + +/* Enterprise application workers */ +/* opaque = counter_data; enterprise = 0; format = 2206 */ + +typedef struct { + uint32_t workers_active; + uint32_t workers_idle; + uint32_t workers_max; + uint32_t req_delayed; + uint32_t req_dropped; +} SFLAPP_workers; + +typedef struct _SFLJVM_ID { + SFLString vm_name; + SFLString vm_vendor; + SFLString vm_version; +} SFLJVM_ID; + +#define SFLJVM_MAX_VMNAME_LEN 64 +#define SFLJVM_MAX_VENDOR_LEN 32 +#define SFLJVM_MAX_VERSION_LEN 32 + +typedef struct _SFLJMX_counters { + uint64_t hmem_initial; + uint64_t hmem_used; + uint64_t hmem_committed; + uint64_t hmem_max; + uint64_t nhmem_initial; + uint64_t nhmem_used; + uint64_t nhmem_committed; + uint64_t nhmem_max; + uint32_t gc_count; + uint32_t gc_ms; + uint32_t cls_loaded; + uint32_t cls_total; + uint32_t cls_unloaded; + uint32_t comp_ms; + uint32_t thread_live; + uint32_t thread_daemon; + uint32_t thread_started; + uint32_t fds_open; + uint32_t fds_max; +} SFLJMX_counters; + +#define XDRSIZ_JMX_COUNTERS 108 + +typedef struct _SFLVdi_counters { + uint32_t sessions_current; /* number of current sessions */ + uint32_t sessions_total; /* total sessions started */ + uint32_t sessions_duration; /* cumulative session time (in seconds) + across all sessions, such that average + session duration = sessions_duration + / sessions_total */ + uint32_t rx_bytes; /* total bytes received */ + uint32_t tx_bytes; /* total bytes sent */ + uint32_t rx_packets; /* total packet received */ + uint32_t tx_packets; /* total packets sent */ + uint32_t rx_packets_lost; /* total received packets lost */ + uint32_t tx_packets_lost; /* total sent packets lost */ + uint32_t rtt_min_ms; /* minimum round trip latency with client + across all current sessions + measured in milliseconds */ + uint32_t rtt_max_ms; /* maximum round trip latency with client + across all current sessions + measured in millisecond */ + uint32_t rtt_avg_ms; /* average round trip latency with client + across all current sessions + measured in milliseconds */ + uint32_t audio_rx_bytes; /* total bytes of audio data received */ + uint32_t audio_tx_bytes; /* total bytes of audio data sent */ + uint32_t audio_tx_limit; /* administrative limit on audio transmission + bandwidth (in bits per second) */ + uint32_t img_rx_bytes; /* total bytes of imaging data recieved */ + uint32_t img_tx_bytes; /* total bytes of imaging data sent */ + uint32_t img_frames; /* total image frames encoded */ + uint32_t img_qual_min; /* minimum image encoding quality across + current sessions, on a scale of 0 to 100 */ + uint32_t img_qual_max; /* best image encoding quality across + current sessions, on a scale of 0 to 100 */ + uint32_t img_qual_avg; /* average image encoding quality across + current sessions, on a scale of 0 to 100 */ + uint32_t usb_rx_bytes; /* total bytes of usb data received */ + uint32_t usb_tx_bytes; /* total bytes of usb data sent */ +} SFLVdi_counters; + + /* LAG Port Statistics - see IEEE8023-LAG-MIB */ + /* opaque = counter_data; enterprise = 0; format = 7 */ +typedef union _SFLLACP_portState { + uint32_t all; + struct { + uint8_t actorAdmin; + uint8_t actorOper; + uint8_t partnerAdmin; + uint8_t partnerOper; + } v; +} SFLLACP_portState; + +typedef struct _SFLLACP_counters { + uint8_t actorSystemID[8]; /* 6 bytes + 2 pad */ + uint8_t partnerSystemID[8]; /* 6 bytes + 2 pad */ + uint32_t attachedAggID; + SFLLACP_portState portState; + uint32_t LACPDUsRx; + uint32_t markerPDUsRx; + uint32_t markerResponsePDUsRx; + uint32_t unknownRx; + uint32_t illegalRx; + uint32_t LACPDUsTx; + uint32_t markerPDUsTx; + uint32_t markerResponsePDUsTx; +} SFLLACP_counters; + +#define XDRSIZ_LACP_COUNTERS 56 + +/* openflow port */ +/* opaque = counter_data; enterprise = 0; format = 1004 */ +typedef struct { + uint64_t datapath_id; + uint32_t port_no; +} SFLOFPort; + +#define XDRSIZ_OFPORT 12 + +/* port name */ +/* opaque = counter_data; enterprise = 0; format = 1005 */ +typedef struct { + SFLString portName; +} SFLPortName; + +#define SFL_MAX_PORTNAME_LEN 255 + +/* OVS datapath stats */ +typedef struct _SFLOVSDP_counters { + uint32_t n_hit; + uint32_t n_missed; + uint32_t n_lost; + uint32_t n_mask_hit; + uint32_t n_flows; + uint32_t n_masks; +} SFLOVSDP_counters; + +#define XDRSIZE_OVSDP 24 + +/* Optical SFP/QSFP metrics */ +/* opaque = counter_data; enterprise = 0; format = 10 */ + +typedef struct { + uint32_t lane_index; /* index of lane in module - starting from 1 */ + uint32_t tx_bias_current; /* microamps */ + uint32_t tx_power; /* microwatts */ + uint32_t tx_power_min; /* microwatts */ + uint32_t tx_power_max; /* microwatts */ + uint32_t tx_wavelength; /* nanometers */ + uint32_t rx_power; /* microwatts */ + uint32_t rx_power_min; /* microwatts */ + uint32_t rx_power_max; /* microwatts */ + uint32_t rx_wavelength; /* nanometers */ +} SFLLane; + +#define XDRSIZ_LANE_COUNTERS 40 + +typedef struct { + uint32_t module_id; + uint32_t module_total_lanes; /* total lanes in module */ + uint32_t module_supply_voltage; /* millivolts */ + int32_t module_temperature; /* signed - in oC / 1000 */ + uint32_t num_lanes; /* number of active lane structs to come */ + SFLLane *lanes; +} SFLSFP_counters; /* Counters data */ -enum INMCounters_version { - INMCOUNTERSVERSION_GENERIC = 1, - INMCOUNTERSVERSION_ETHERNET = 2, - INMCOUNTERSVERSION_TOKENRING = 3, - INMCOUNTERSVERSION_FDDI = 4, - INMCOUNTERSVERSION_VG = 5, - INMCOUNTERSVERSION_WAN = 6, - INMCOUNTERSVERSION_VLAN = 7 +enum SFLCounters_type_tag { + /* enterprise = 0, format = ... */ + SFLCOUNTERS_GENERIC = 1, + SFLCOUNTERS_ETHERNET = 2, + SFLCOUNTERS_TOKENRING = 3, + SFLCOUNTERS_VG = 4, + SFLCOUNTERS_VLAN = 5, + SFLCOUNTERS_80211 = 6, + SFLCOUNTERS_LACP = 7, + SFLCOUNTERS_SFP = 10, + SFLCOUNTERS_PROCESSOR = 1001, + SFLCOUNTERS_RADIO = 1002, + SFLCOUNTERS_OFPORT = 1004, + SFLCOUNTERS_PORTNAME = 1005, + SFLCOUNTERS_HOST_HID = 2000, /* host id */ + SFLCOUNTERS_ADAPTORS = 2001, /* host adaptors */ + SFLCOUNTERS_HOST_PAR = 2002, /* host parent */ + SFLCOUNTERS_HOST_CPU = 2003, /* host cpu */ + SFLCOUNTERS_HOST_MEM = 2004, /* host memory */ + SFLCOUNTERS_HOST_DSK = 2005, /* host storage I/O */ + SFLCOUNTERS_HOST_NIO = 2006, /* host network I/O */ + SFLCOUNTERS_HOST_IP = 2007, + SFLCOUNTERS_HOST_ICMP = 2008, + SFLCOUNTERS_HOST_TCP = 2009, + SFLCOUNTERS_HOST_UDP = 2010, + SFLCOUNTERS_HOST_VRT_NODE = 2100, /* host virt node */ + SFLCOUNTERS_HOST_VRT_CPU = 2101, /* host virt cpu */ + SFLCOUNTERS_HOST_VRT_MEM = 2102, /* host virt mem */ + SFLCOUNTERS_HOST_VRT_DSK = 2103, /* host virt storage */ + SFLCOUNTERS_HOST_VRT_NIO = 2104, /* host virt network I/O */ + SFLCOUNTERS_JVM = 2105, /* java runtime */ + SFLCOUNTERS_JMX = 2106, /* java JMX stats */ + SFLCOUNTERS_MEMCACHE = 2200, /* memcached (deprecated) */ + SFLCOUNTERS_HTTP = 2201, /* http */ + SFLCOUNTERS_APP = 2202, + SFLCOUNTERS_APP_RESOURCE = 2203, + SFLCOUNTERS_MEMCACHE2 = 2204, /* memcached */ + SFLCOUNTERS_VDI = 2205, + SFLCOUNTERS_APP_WORKERS = 2206, + SFLCOUNTERS_OVSDP = 2207, + SFLCOUNTERS_HOST_GPU_NVML = (5703 << 12) + 1, /* = 23359489 */ + SFLCOUNTERS_BCM_TABLES = (4413 << 12) + 3, }; -typedef union _INMCounters_type { - INMIf_counters generic; - INMEthernet_counters ethernet; - INMTokenring_counters tokenring; - INMFddi_counters fddi; - INMVg_counters vg; - INMWan_counters wan; - INMVlan_counters vlan; -} INMCounters_type; +typedef union _SFLCounters_type { + SFLIf_counters generic; + SFLEthernet_counters ethernet; + SFLTokenring_counters tokenring; + SFLVg_counters vg; + SFLVlan_counters vlan; + SFLWifi_counters wifi; + SFLProcessor_counters processor; + SFLRadio_counters radio; + SFLHostId hostId; + SFLAdaptorList *adaptors; + SFLHost_parent host_par; + SFLHost_cpu_counters host_cpu; + SFLHost_mem_counters host_mem; + SFLHost_dsk_counters host_dsk; + SFLHost_nio_counters host_nio; + SFLHost_IP_counters host_ip; + SFLHost_ICMP_counters host_icmp; + SFLHost_TCP_counters host_tcp; + SFLHost_UDP_counters host_udp; + SFLHost_vrt_node_counters host_vrt_node; + SFLHost_vrt_cpu_counters host_vrt_cpu; + SFLHost_vrt_mem_counters host_vrt_mem; + SFLHost_vrt_dsk_counters host_vrt_dsk; + SFLHost_vrt_nio_counters host_vrt_nio; + SFLHost_gpu_nvml host_gpu_nvml; + SFLBCM_tables bcm_tables; + SFLMemcache_counters memcache; + SFLHTTP_counters http; + SFLJVM_ID jvm; + SFLJMX_counters jmx; + SFLAPP_counters app; + SFLAPP_resources appResources; + SFLAPP_workers appWorkers; + SFLVdi_counters vdi; + SFLLACP_counters lacp; + SFLPortName portName; + SFLSFP_counters sfp; + SFLOVSDP_counters ovsdp; +} SFLCounters_type; -typedef struct _INMCounters_sample_hdr { +typedef struct _SFLCounters_sample_element { + struct _SFLCounters_sample_element *nxt; /* linked list */ + uint32_t tag; /* SFLCounters_type_tag */ + uint32_t length; + SFLCounters_type counterBlock; +} SFLCounters_sample_element; + +typedef struct _SFLCounters_sample { + /* uint32_t tag; */ /* SFL_sample_tag -- enterprise = 0 : format = 2 */ + /* uint32_t length; */ uint32_t sequence_number; /* Incremented with each counters sample generated by this source_id */ uint32_t source_id; /* fsSourceId */ - uint32_t sampling_interval; /* fsCounterSamplingInterval */ -} INMCounters_sample_hdr; + uint32_t num_elements; + SFLCounters_sample_element *elements; +} SFLCounters_sample; -typedef struct _INMCounters_sample { - INMCounters_sample_hdr hdr; - uint32_t counters_type_tag; /* Enum INMCounters_version */ - INMCounters_type counters; /* Counter set for this interface type */ -} INMCounters_sample; +/* same thing, but the expanded version, so ds_index can be a full 32 bits */ +typedef struct _SFLCounters_sample_expanded { + /* uint32_t tag; */ /* SFL_sample_tag -- enterprise = 0 : format = 2 */ + /* uint32_t length; */ + uint32_t sequence_number; /* Incremented with each counters sample + generated by this source_id */ + uint32_t ds_class; /* EXPANDED */ + uint32_t ds_index; /* EXPANDED */ + uint32_t num_elements; + SFLCounters_sample_element *elements; +} SFLCounters_sample_expanded; -/* when I turn on optimisation with the Microsoft compiler it seems to change - the values of these enumerated types and break the program - not sure why */ -enum INMSample_types { - FLOWSAMPLE = 1, - COUNTERSSAMPLE = 2 -}; - -typedef union _INMSample_type { - INMFlow_sample flowsample; - INMCounters_sample counterssample; -} INMSample_type; +#define SFLADD_ELEMENT(_sm, _el) do { (_el)->nxt = (_sm)->elements; (_sm)->elements = (_el); } while(0) /* Format of a sample datagram */ -enum INMDatagram_version { - INMDATAGRAM_VERSION2 = 2, - INMDATAGRAM_VERSION4 = 4 +enum SFLDatagram_version { + SFLDATAGRAM_VERSION2 = 2, + SFLDATAGRAM_VERSION4 = 4, + SFLDATAGRAM_VERSION5 = 5 }; -typedef struct _INMSample_datagram_hdr { - uint32_t datagram_version; /* (enum INMDatagram_version) = VERSION4 */ - INMAddress agent_address; /* IP address of sampling agent */ +typedef struct _SFLSample_datagram_hdr { + uint32_t datagram_version; /* (enum SFLDatagram_version) = VERSION5 = 5 */ + SFLAddress agent_address; /* IP address of sampling agent */ + uint32_t sub_agent_id; /* Used to distinguishing between datagram + streams from separate agent sub entities + within an device. */ uint32_t sequence_number; /* Incremented with each sample datagram generated */ uint32_t uptime; /* Current time (in milliseconds since device last booted). Should be set as close to datagram transmission time as possible.*/ - uint32_t num_samples; /* Number of flow and counters samples to follow */ -} INMSample_datagram_hdr; + uint32_t num_records; /* Number of tag-len-val flow/counter records to follow */ +} SFLSample_datagram_hdr; -#define INM_MAX_DATAGRAM_SIZE 1500 -#define INM_MIN_DATAGRAM_SIZE 200 -#define INM_DEFAULT_DATAGRAM_SIZE 1400 +#define SFL_MAX_DATAGRAM_SIZE 1500 +#define SFL_MIN_DATAGRAM_SIZE 200 +#define SFL_DEFAULT_DATAGRAM_SIZE 1400 -#define INM_DATA_PAD 400 - -void Init_sflow(void); - -void Process_sflow(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs); - -/* - * Extension map for sflow ( compatibility for now ) - * - * Required extensions: - * - * 4 byte byte counter - * | 4byte packet counter - * | | IPv4 - * | | | - * xxxx x0 0 0 - * - * Optional extensions: - * - * 4 : 2 byte input/output interface id - * 6 : 2 byte src/dst as - */ - - -#endif //_SFLOW_H +#define SFL_DATA_PAD 400 +#if defined(__cplusplus) +} /* extern "C" */ +#endif +#endif /* SFLOW_H */ diff --git a/bin/sflow_nfdump.c b/bin/sflow_nfdump.c new file mode 100644 index 0000000..1788913 --- /dev/null +++ b/bin/sflow_nfdump.c @@ -0,0 +1,4431 @@ +/* + * Copyright (c) 2017, Peter Haag + * Copyright (c) 2016, Peter Haag + * Copyright (c) 2014, Peter Haag + * Copyright (c) 2009, Peter Haag + * Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the author nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * sfcapd makes use of code originated from sflowtool by InMon Corp. + * Those parts of the code are distributed under the InMon Public License below. + * All other/additional code is pubblished under BSD license. + */ + + +/* + * ----------------------------------------------------------------------- + * Copyright (c) 2001-2002 InMon Corp. All rights reserved. + * ----------------------------------------------------------------------- + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes sFlow(TM), freely available from + * http://www.inmon.com/". + * + * 4. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes sFlow(TM), freely available from + * http://www.inmon.com/". + * + * 5. InMon Corp. may publish revised and/or new versions + * of the license from time to time. Each version will be given a + * distinguishing version number. Once covered code has been + * published under a particular version of the license, you may + * always continue to use it under the terms of that version. You + * may also choose to use such covered code under the terms of any + * subsequent version of the license published by InMon Corp. + * No one other than the InMon Corp. has the right to modify the terms + * applicable to covered code created under this License. + * + * 6. The name "sFlow" must not be used to endorse or promote products + * derived from this software without prior written permission + * from InMon Corp. This does not apply to add-on libraries or tools + * that work in conjunction with sFlow. In such a case the sFlow name + * may be used to indicate that the product supports sFlow. + * + * 7. Products derived from this software may not be called "sFlow", + * nor may "sFlow" appear in their name, without prior written + * permission of InMon Corp. + * + * + * THIS SOFTWARE IS PROVIDED BY INMON CORP. ``AS IS'' AND + * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * INMON CORP. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * -------------------------------------------------------------------- + * + * This software consists of voluntary contributions made by many + * individuals on behalf of InMon Corp. + * + * InMon Corp. can be contacted via Email at info@inmon.com. + * + * For more information on InMon Corp. and sFlow, + * please see http://www.inmon.com/. + * + * InMon Public License Version 1.0 written May 31, 2001 + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_STDINT_H +#include +#endif + +#include "nffile.h" +#include "nfx.h" +#include "nf_common.h" +#include "util.h" +#include "bookkeeper.h" +#include "collector.h" + +#include "sflow.h" /* sFlow v5 */ +#include "sflow_v2v4.h" /* sFlow v2/4 */ +#include "sflow_nfdump.h" + + +/* +#ifdef DARWIN +#include +#define bswap_16(x) NXSwapShort(x) +#define bswap_32(x) NXSwapInt(x) +#else +#include +#endif +*/ + +#ifndef DEVEL +# define dbg_printf(...) /* printf(__VA_ARGS__) */ +#else +# define dbg_printf(...) printf(__VA_ARGS__) +#endif + +#define MAX_SFLOW_EXTENSIONS 8 + +typedef struct exporter_sflow_s { + // link chain + struct exporter_sflow_s *next; + + // generic exporter information + exporter_info_record_t info; + + uint64_t packets; // number of packets sent by this exporter + uint64_t flows; // number of flow records sent by this exporter + uint32_t sequence_failure; // number of sequence failues + + generic_sampler_t *sampler; + + // extension map + // extension maps are common for all exporters + extension_info_t sflow_extension_info[MAX_SFLOW_EXTENSIONS]; + +} exporter_sflow_t; + +extern extension_descriptor_t extension_descriptor[]; +extern FlowSource_t *FlowSource; + +/* module limited globals */ + +/* + * As sflow has no templates, we need to have an extension map for each possible + * combination of IPv4/IPv6 addresses in all ip fields + * + * index id: + * 0 : EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v4 + * 1 : EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v4 + * 2 : EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v4 + * 3 : EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v4 + * 4 : EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v6 + * 5 : EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v6 + * 6 : EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v6 + * 7 : EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v6 + */ +static uint16_t sflow_output_record_size[MAX_SFLOW_EXTENSIONS]; + +// All available extensions for sflow +static uint16_t sflow_extensions[] = { + EX_IO_SNMP_4, + EX_AS_4, + EX_MULIPLE, + EX_VLAN, + EX_MAC_1, + EX_RECEIVED, + 0 // final token +}; +static int Num_enabled_extensions; + +static struct sflow_ip_extensions_s { + int next_hop; + int next_hop_bgp; + int router_ip; +} sflow_ip_extensions[] = { + { EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v4 }, + { EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v4 }, + { EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v4 }, + { EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v4 }, + { EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v6 }, + { EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v4, EX_ROUTER_IP_v6 }, + { EX_NEXT_HOP_v4, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v6 }, + { EX_NEXT_HOP_v6, EX_NEXT_HOP_BGP_v6, EX_ROUTER_IP_v6 }, +}; + +#define SFLOW_NEXT_HOP 1 +#define SFLOW_NEXT_HOP_BGP 2 +#define SFLOW_ROUTER_IP 4 +static int IP_extension_mask = 0; + +static inline exporter_sflow_t *GetExporter(FlowSource_t *fs, uint32_t agentSubId, uint32_t meanSkipCount); + +/* + * unused +// +static uint32_t MyByteSwap32(uint32_t n) { + return (((n & 0x000000FF)<<24) + + ((n & 0x0000FF00)<<8) + + ((n & 0x00FF0000)>>8) + + ((n & 0xFF000000)>>24)); +} + +static uint16_t MyByteSwap16(uint16_t n) { + return ((n >> 8) | (n << 8)); +} +*/ + +#define YES 1 +#define NO 0 + +/* define my own IP header struct - to ease portability */ +struct myiphdr { + uint8_t version_and_headerLen; + uint8_t tos; + uint16_t tot_len; + uint16_t id; + uint16_t frag_off; + uint8_t ttl; + uint8_t protocol; + uint16_t check; + uint32_t saddr; + uint32_t daddr; +}; + +/* ip6 header if no option headers */ +struct myip6hdr { + uint8_t version_and_priority; + uint8_t label1; + uint8_t label2; + uint8_t label3; + uint16_t payloadLength; + uint8_t nextHeader; + uint8_t ttl; + struct in6_addr saddr; + struct in6_addr daddr; +}; + +/* same for tcp */ +struct mytcphdr { + uint16_t th_sport; /* source port */ + uint16_t th_dport; /* destination port */ + uint32_t th_seq; /* sequence number */ + uint32_t th_ack; /* acknowledgement number */ + uint8_t th_off_and_unused; + uint8_t th_flags; + uint16_t th_win; /* window */ + uint16_t th_sum; /* checksum */ + uint16_t th_urp; /* urgent pointer */ +}; + +/* and UDP */ +struct myudphdr { + uint16_t uh_sport; /* source port */ + uint16_t uh_dport; /* destination port */ + uint16_t uh_ulen; /* udp length */ + uint16_t uh_sum; /* udp checksum */ +}; + +/* and ICMP */ +struct myicmphdr { + uint8_t type; /* message type */ + uint8_t code; /* type sub-code */ + /* ignore the rest */ +}; + +typedef struct _SFForwardingTarget { + struct _SFForwardingTarget *nxt; + struct in_addr host; + uint32_t port; + struct sockaddr_in addr; + int sock; +} SFForwardingTarget; + +typedef enum { SFLFMT_FULL=0, SFLFMT_PCAP, SFLFMT_LINE } EnumSFLFormat; + +typedef struct _SFSample { + /* exception handler context */ + jmp_buf env; + + struct in_addr sourceIP; // EX_ROUTER_IP_v4 + + SFLAddress agent_addr; + uint32_t agentSubId; + + /* the raw pdu */ + uint8_t *rawSample; + uint32_t rawSampleLen; + uint8_t *endp; + time_t readTimestamp; + + /* decode cursor */ + uint32_t *datap; + + uint32_t datagramVersion; + uint32_t sampleType; + uint32_t elementType; + uint32_t ds_class; + uint32_t ds_index; + + /* generic interface counter sample */ + SFLIf_counters ifCounters; + + /* sample stream info */ + uint32_t sysUpTime; + uint32_t sequenceNo; + uint32_t sampledPacketSize; + uint32_t samplesGenerated; + uint32_t meanSkipCount; + uint32_t samplePool; + uint32_t dropEvents; + + /* the sampled header */ + uint32_t packet_data_tag; + uint32_t headerProtocol; + uint8_t *header; + uint32_t headerLen; + uint32_t stripped; + + /* header decode */ + int gotIPV4; + int gotIPV4Struct; + int offsetToIPV4; + int gotIPV6; // v6 flag + int gotIPV6Struct; + int offsetToIPV6; + int offsetToPayload; + SFLAddress ipsrc; // Common (v6) + SFLAddress ipdst; // Common (v6) +// XXX + struct in_addr dcd_srcIP; // Common (v4) + struct in_addr dcd_dstIP; // Common (v4) + uint32_t dcd_ipProtocol; // Common + uint32_t dcd_ipTos; // EX_MULIPLE + uint32_t dcd_ipTTL; + uint32_t dcd_sport; // Common + uint32_t dcd_dport; // Common + uint32_t dcd_tcpFlags; // Common + uint32_t ip_fragmentOffset; + uint32_t udp_pduLen; + + /* ports */ + uint32_t inputPortFormat; + uint32_t outputPortFormat; + uint32_t inputPort; // EX_IO_SNMP_4 + uint32_t outputPort; // EX_IO_SNMP_4 + + /* ethernet */ + uint32_t eth_type; + uint32_t eth_len; + u_char eth_src[8]; // EX_MAC_1 + u_char eth_dst[8]; // EX_MAC_1 + + /* vlan */ + uint32_t in_vlan; // EX_VLAN + uint32_t in_priority; + uint32_t internalPriority; + uint32_t out_vlan; // EX_VLAN + uint32_t out_priority; + int vlanFilterReject; + + /* extended data fields */ + uint32_t num_extended; + uint32_t extended_data_tag; +#define SASAMPLE_EXTENDED_DATA_SWITCH 1 +#define SASAMPLE_EXTENDED_DATA_ROUTER 4 +#define SASAMPLE_EXTENDED_DATA_GATEWAY 8 +#define SASAMPLE_EXTENDED_DATA_USER 16 +#define SASAMPLE_EXTENDED_DATA_URL 32 +#define SASAMPLE_EXTENDED_DATA_MPLS 64 +#define SASAMPLE_EXTENDED_DATA_NAT 128 +#define SASAMPLE_EXTENDED_DATA_MPLS_TUNNEL 256 +#define SASAMPLE_EXTENDED_DATA_MPLS_VC 512 +#define SASAMPLE_EXTENDED_DATA_MPLS_FTN 1024 +#define SASAMPLE_EXTENDED_DATA_MPLS_LDP_FEC 2048 +#define SASAMPLE_EXTENDED_DATA_VLAN_TUNNEL 4096 +#define SASAMPLE_EXTENDED_DATA_NAT_PORT 8192 + + /* IP forwarding info */ + SFLAddress nextHop; // EX_NEXT_HOP_v4, EX_NEXT_HOP_v6 + uint32_t srcMask; // EX_MULIPLE + uint32_t dstMask; // EX_MULIPLE + + /* BGP info */ + SFLAddress bgp_nextHop; // EX_NEXT_HOP_BGP_v4, EX_NEXT_HOP_BGP_v6 + uint32_t my_as; + uint32_t src_as; // EX_AS_4 + uint32_t src_peer_as; + uint32_t dst_as_path_len; + uint32_t *dst_as_path; + /* note: version 4 dst as path segments just get printed, not stored here, however + * the dst_peer and dst_as are filled in, since those are used for netflow encoding + */ + uint32_t dst_peer_as; + uint32_t dst_as; // EX_AS_4 + + uint32_t communities_len; + uint32_t *communities; + uint32_t localpref; + + /* user id */ +#define SA_MAX_EXTENDED_USER_LEN 200 + uint32_t src_user_charset; + uint32_t src_user_len; + char src_user[SA_MAX_EXTENDED_USER_LEN+1]; + uint32_t dst_user_charset; + uint32_t dst_user_len; + char dst_user[SA_MAX_EXTENDED_USER_LEN+1]; + + /* url */ +#define SA_MAX_EXTENDED_URL_LEN 200 +#define SA_MAX_EXTENDED_HOST_LEN 200 + uint32_t url_direction; + uint32_t url_len; + char url[SA_MAX_EXTENDED_URL_LEN+1]; + uint32_t host_len; + char host[SA_MAX_EXTENDED_HOST_LEN+1]; + + /* mpls */ + SFLAddress mpls_nextHop; + + /* nat */ + SFLAddress nat_src; + SFLAddress nat_dst; + + /* counter blocks */ + uint32_t statsSamplingInterval; + uint32_t counterBlockVersion; + +#define SFABORT(s, r) longjmp((s)->env, (r)) +#define SF_ABORT_EOS 1 +#define SF_ABORT_DECODE_ERROR 2 +#define SF_ABORT_LENGTH_ERROR 3 + +} SFSample; + +int Setup_Extension_Info(FlowSource_t *fs, exporter_sflow_t *exporter, int num); + +static int printHex(const u_char *a, int len, char *buf, int bufLen, int marker, int bytesPerOutputLine); + +static char *IP_to_a(uint32_t ipaddr, char *buf, int buflen); + +static inline uint32_t getData32(SFSample *sample); + +static inline uint32_t getData32_nobswap(SFSample *sample); + +static inline uint64_t getData64(SFSample *sample); + +static void writeCountersLine(SFSample *sample); + +static void receiveError(SFSample *sample, char *errm, int hexdump) __attribute__ ((noreturn)); + +static inline void skipBytes(SFSample *sample, uint32_t skip); + +static inline uint32_t sf_log_next32(SFSample *sample, char *fieldName); + +static inline uint64_t sf_log_next64(SFSample *sample, char *fieldName); + +static inline void sf_log_nextMAC(SFSample *sample, char *fieldName); + +static inline void sf_log_percentage(SFSample *sample, char *fieldName); + +static inline uint32_t getString(SFSample *sample, char *buf, uint32_t bufLen); + +static inline uint32_t getAddress(SFSample *sample, SFLAddress *address); + +static inline void skipTLVRecord(SFSample *sample, uint32_t tag, uint32_t len, char *description); + +static inline void readSFlowDatagram(SFSample *sample, FlowSource_t *fs); + +static inline void readFlowSample(SFSample *sample, int expanded, FlowSource_t *fs); + +static inline void readCountersSample(SFSample *sample, int expanded, FlowSource_t *fs); + +static inline void readFlowSample_header(SFSample *sample); + +static inline void readFlowSample_v2v4(SFSample *sample, FlowSource_t *fs); + +static inline void readCountersSample_v2v4(SFSample *sample, FlowSource_t *fs); + +static inline void StoreSflowRecord(SFSample *sample, FlowSource_t *fs); + +#ifdef DEVEL +static char *URLEncode(char *in, char *out, int outlen); +#endif + +static int printUUID(const uint8_t *a, char *buf, int bufLen); + +extern int verbose; + +#ifdef DEVEL +static inline char *printTag(uint32_t tag, char *buf, int bufLen); + +static inline char *printTag(uint32_t tag, char *buf, int bufLen) { + snprintf(buf, bufLen, "%u:%u", (tag >> 12), (tag & 0x00000FFF)); + return buf; +} // End of printTag + +#endif + + +/*_________________---------------------------__________________ + _________________ printHex __________________ + -----------------___________________________------------------ +*/ + +static u_char bin2hex(int nib) { return (nib < 10) ? ('0' + nib) : ('A' - 10 + nib); } + +static int printHex(const u_char *a, int len, char *buf, int bufLen, int marker, int bytesPerOutputLine) { + int b = 0, i = 0; + for(; i < len; i++) { + u_char byte; + if(b > (bufLen - 10)) break; + if(marker > 0 && i == marker) { + buf[b++] = '<'; + buf[b++] = '*'; + buf[b++] = '>'; + buf[b++] = '-'; + } + byte = a[i]; + buf[b++] = bin2hex(byte >> 4); + buf[b++] = bin2hex(byte & 0x0f); + if(i > 0 && (i % bytesPerOutputLine) == 0) buf[b++] = '\n'; + else { + // separate the bytes with a dash + if (i < (len - 1)) buf[b++] = '-'; + } + } + buf[b] = '\0'; + return b; +} + +/*_________________---------------------------__________________ + _________________ IP_to_a __________________ + -----------------___________________________------------------ +*/ + +static char *IP_to_a(uint32_t ipaddr, char *buf, int buflen) { + u_char *ip = (u_char *)&ipaddr; + snprintf(buf, buflen, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); + buf[buflen-1] = '\0'; + return buf; +} + +static char *printAddress(SFLAddress *address, char *buf, int bufLen) { + switch(address->type) { + case SFLADDRESSTYPE_IP_V4: + IP_to_a(address->address.ip_v4.addr, buf, bufLen); + break; + case SFLADDRESSTYPE_IP_V6: { + u_char *b = address->address.ip_v6.addr; + snprintf(buf, bufLen, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7],b[8],b[9],b[10],b[11],b[12],b[13],b[14],b[15]); + } break; + default: + sprintf(buf, "-"); + } + return buf; +} + +/*_________________---------------------------__________________ + _________________ writeFlowLine __________________ + -----------------___________________________------------------ +*/ + +static void writeFlowLine(SFSample *sample) { +char agentIP[51], srcIP[51], dstIP[51]; + // source + printf("FLOW,%s,%d,%d,", + printAddress(&sample->agent_addr, agentIP, 50), + sample->inputPort, + sample->outputPort); + // layer 2 + printf("%02x%02x%02x%02x%02x%02x,%02x%02x%02x%02x%02x%02x,0x%04x,%d,%d", + sample->eth_src[0], + sample->eth_src[1], + sample->eth_src[2], + sample->eth_src[3], + sample->eth_src[4], + sample->eth_src[5], + sample->eth_dst[0], + sample->eth_dst[1], + sample->eth_dst[2], + sample->eth_dst[3], + sample->eth_dst[4], + sample->eth_dst[5], + sample->eth_type, + sample->in_vlan, + sample->out_vlan); + // layer 3/4 + printf(",IP: %s,%s,%d,0x%02x,%d,%d,%d,0x%02x", + IP_to_a(sample->dcd_srcIP.s_addr, srcIP, 51), + IP_to_a(sample->dcd_dstIP.s_addr, dstIP, 51), + sample->dcd_ipProtocol, + sample->dcd_ipTos, + sample->dcd_ipTTL, + sample->dcd_sport, + sample->dcd_dport, + sample->dcd_tcpFlags); + // bytes + printf(",%d,%d,%d\n", + sample->sampledPacketSize, + sample->sampledPacketSize - sample->stripped - sample->offsetToIPV4, + sample->meanSkipCount); +} + +/*_________________---------------------------__________________ + _________________ writeCountersLine __________________ + -----------------___________________________------------------ +*/ + +static void writeCountersLine(SFSample *sample) +{ + // source + char agentIP[51]; + printf("CNTR,%s,", printAddress(&sample->agent_addr, agentIP, 50)); + printf("%u,%u,%llu,%u,%u,%llu,%u,%u,%u,%u,%u,%u,%llu,%u,%u,%u,%u,%u,%u\n", + sample->ifCounters.ifIndex, + sample->ifCounters.ifType, + (unsigned long long)sample->ifCounters.ifSpeed, + sample->ifCounters.ifDirection, + sample->ifCounters.ifStatus, + (unsigned long long)sample->ifCounters.ifInOctets, + sample->ifCounters.ifInUcastPkts, + sample->ifCounters.ifInMulticastPkts, + sample->ifCounters.ifInBroadcastPkts, + sample->ifCounters.ifInDiscards, + sample->ifCounters.ifInErrors, + sample->ifCounters.ifInUnknownProtos, + (unsigned long long)sample->ifCounters.ifOutOctets, + sample->ifCounters.ifOutUcastPkts, + sample->ifCounters.ifOutMulticastPkts, + sample->ifCounters.ifOutBroadcastPkts, + sample->ifCounters.ifOutDiscards, + sample->ifCounters.ifOutErrors, + sample->ifCounters.ifPromiscuousMode); +} + +/*_________________---------------------------__________________ + _________________ receiveError __________________ + -----------------___________________________------------------ +*/ + +static void receiveError(SFSample *sample, char *errm, int hexdump) +{ + char ipbuf[51]; + char scratch[6000]; + char *msg = ""; + char *hex = ""; + uint32_t markOffset = (u_char *)sample->datap - sample->rawSample; + if(errm) msg = errm; + if(hexdump) { + printHex(sample->rawSample, sample->rawSampleLen, scratch, 6000, markOffset, 16); + hex = scratch; + } + LogError("SFLOW: %s (source IP = %s) %s", msg, IP_to_a(sample->sourceIP.s_addr, ipbuf, 51), hex); + + SFABORT(sample, SF_ABORT_DECODE_ERROR); + +} + +/*_________________---------------------------__________________ + _________________ lengthCheck __________________ + -----------------___________________________------------------ +*/ + +static void lengthCheck(SFSample *sample, char *description, u_char *start, int len) { + uint32_t actualLen = (u_char *)sample->datap - start; + uint32_t adjustedLen = ((len + 3) >> 2) << 2; + if(actualLen != adjustedLen) { + dbg_printf("%s length error (expected %d, found %d)\n", description, len, actualLen); + LogError("SFLOW: %s length error (expected %d, found %d)", description, len, actualLen); + SFABORT(sample, SF_ABORT_LENGTH_ERROR); + } + +} + +/*_________________---------------------------__________________ + _________________ decodeLinkLayer __________________ + -----------------___________________________------------------ + store the offset to the start of the ipv4 header in the sequence_number field + or -1 if not found. Decode the 802.1d if it's there. +*/ + +#define NFT_ETHHDR_SIZ 14 +#define NFT_8022_SIZ 3 +#define NFT_MAX_8023_LEN 1500 + +#define NFT_MIN_SIZ (NFT_ETHHDR_SIZ + sizeof(struct myiphdr)) + +static void decodeLinkLayer(SFSample *sample) +{ + uint8_t *start = sample->header; + uint8_t *end = start + sample->headerLen; + uint8_t *ptr = start; + uint16_t type_len; + + /* assume not found */ + sample->gotIPV4 = NO; + sample->gotIPV6 = NO; + + if((end - ptr) < NFT_ETHHDR_SIZ) return; /* not enough for an Ethernet header */ + + dbg_printf("dstMAC %02x%02x%02x%02x%02x%02x\n", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); + memcpy(sample->eth_dst, ptr, 6); + ptr += 6; + dbg_printf("srcMAC %02x%02x%02x%02x%02x%02x\n", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); + memcpy(sample->eth_src, ptr, 6); + ptr += 6; + type_len = (ptr[0] << 8) + ptr[1]; + ptr += 2; + + if(type_len == 0x8100) { + if((end - ptr) < 4) return; /* not enough for an 802.1Q header */ + /* VLAN - next two bytes */ + uint32_t vlanData = (ptr[0] << 8) + ptr[1]; + uint32_t vlan = vlanData & 0x0fff; +#ifdef DEVEL + uint32_t priority = vlanData >> 13; +#endif + ptr += 2; + /* _____________________________________ */ + /* | pri | c | vlan-id | */ + /* ------------------------------------- */ + /* [priority = 3bits] [Canonical Format Flag = 1bit] [vlan-id = 12 bits] */ + dbg_printf("decodedVLAN %u\n", vlan); + dbg_printf("decodedPriority %u\n", priority); + sample->in_vlan = vlan; + /* now get the type_len again (next two bytes) */ + type_len = (ptr[0] << 8) + ptr[1]; + ptr += 2; + } + + /* now we're just looking for IP */ + if((end - start) < sizeof(struct myiphdr)) return; /* not enough for an IPv4 header (or IPX, or SNAP) */ + + /* peek for IPX */ + if(type_len == 0x0200 || type_len == 0x0201 || type_len == 0x0600) { +#define IPX_HDR_LEN 30 +#define IPX_MAX_DATA 546 + int ipxChecksum = (ptr[0] == 0xff && ptr[1] == 0xff); + int ipxLen = (ptr[2] << 8) + ptr[3]; + if(ipxChecksum && + ipxLen >= IPX_HDR_LEN && + ipxLen <= (IPX_HDR_LEN + IPX_MAX_DATA)) + /* we don't do anything with IPX here */ + return; + } + if(type_len <= NFT_MAX_8023_LEN) { + /* assume 802.3+802.2 header */ + /* check for SNAP */ + if(ptr[0] == 0xAA && + ptr[1] == 0xAA && + ptr[2] == 0x03) { + ptr += 3; + if(ptr[0] != 0 || + ptr[1] != 0 || + ptr[2] != 0) { + dbg_printf("VSNAP_OUI %02X-%02X-%02X\n", ptr[0], ptr[1], ptr[2]); + return; /* no further decode for vendor-specific protocol */ + } + ptr += 3; + /* OUI == 00-00-00 means the next two bytes are the ethernet type (RFC 2895) */ + type_len = (ptr[0] << 8) + ptr[1]; + ptr += 2; + } + else { + if (ptr[0] == 0x06 && + ptr[1] == 0x06 && + (ptr[2] & 0x01)) { + /* IP over 8022 */ + ptr += 3; + /* force the type_len to be IP so we can inline the IP decode below */ + type_len = 0x0800; + } + else return; + } + } + + /* assume type_len is an ethernet-type now */ + sample->eth_type = type_len; + + if(type_len == 0x0800) { + /* IPV4 - check again that we have enough header bytes */ + if((end - ptr) < sizeof(struct myiphdr)) return; + /* look at first byte of header.... */ + /* ___________________________ */ + /* | version | hdrlen | */ + /* --------------------------- */ + if((*ptr >> 4) != 4) return; /* not version 4 */ + if((*ptr & 15) < 5) return; /* not IP (hdr len must be 5 quads or more) */ + /* survived all the tests - store the offset to the start of the ip header */ + sample->gotIPV4 = YES; + sample->offsetToIPV4 = (ptr - start); + } + + if(type_len == 0x86DD) { + /* IPV6 */ + /* look at first byte of header.... */ + if((*ptr >> 4) != 6) return; /* not version 6 */ + /* survived all the tests - store the offset to the start of the ip6 header */ + sample->gotIPV6 = YES; + sample->offsetToIPV6 = (ptr - start); + } +} + +#define WIFI_MIN_HDR_SIZ 24 + +static void decode80211MAC(SFSample *sample) +{ + uint8_t *start = sample->header; +// uint8_t *end = start + sample->headerLen; + uint8_t *ptr = start; + + /* assume not found */ + sample->gotIPV4 = NO; + sample->gotIPV6 = NO; + + if(sample->headerLen < WIFI_MIN_HDR_SIZ) return; /* not enough for an 80211 MAC header */ + + uint32_t fc = (ptr[1] << 8) + ptr[0]; /* [b7..b0][b15..b8] */ + uint32_t control = (fc >> 2) & 3; + uint32_t toDS = (fc >> 8) & 1; + uint32_t fromDS = (fc >> 9) & 1; +/* not used +uint32_t protocolVersion = fc & 3; +uint32_t subType = (fc >> 4) & 15; +uint32_t moreFrag = (fc >> 10) & 1; +uint32_t retry = (fc >> 11) & 1; +uint32_t pwrMgt = (fc >> 12) & 1; +uint32_t moreData = (fc >> 13) & 1; +uint32_t encrypted = (fc >> 14) & 1; +uint32_t order = fc >> 15; +*/ + ptr += 2; + +// uint32_t duration_id = (ptr[1] << 8) + ptr[0]; /* not in network byte order either? */ + ptr += 2; + + switch(control) { + case 0: /* mgmt */ + case 1: /* ctrl */ + case 3: /* rsvd */ + break; + + case 2: /* data */ + { + + uint8_t *macAddr1 = ptr; + ptr += 6; + uint8_t *macAddr2 = ptr; + ptr += 6; + uint8_t *macAddr3 = ptr; + ptr += 6; + // XXX not used uint32_t sequence = (ptr[0] << 8) + ptr[1]; + ptr += 2; + + /* ToDS FromDS Addr1 Addr2 Addr3 Addr4 + 0 0 DA SA BSSID N/A (ad-hoc) + 0 1 DA BSSID SA N/A + 1 0 BSSID SA DA N/A + 1 1 RA TA DA SA (wireless bridge) */ + + uint8_t *rxMAC = macAddr1; + uint8_t *txMAC = macAddr2; + uint8_t *srcMAC = NULL; + uint8_t *dstMAC = NULL; + + if(toDS) { + dstMAC = macAddr3; + if(fromDS) { + srcMAC = ptr; /* macAddr4. 1,1 => (wireless bridge) */ + ptr += 6; + } + else srcMAC = macAddr2; /* 1,0 */ + } + else { + dstMAC = macAddr1; + if(fromDS) srcMAC = macAddr3; /* 0,1 */ + else srcMAC = macAddr2; /* 0,0 */ + } + + if(srcMAC) { + dbg_printf("srcMAC %02x%02x%02x%02x%02x%02x\n", srcMAC[0], srcMAC[1], srcMAC[2], srcMAC[3], srcMAC[4], srcMAC[5]); + memcpy(sample->eth_src, srcMAC, 6); + } + if(dstMAC) { + dbg_printf("dstMAC %02x%02x%02x%02x%02x%02x\n", dstMAC[0], dstMAC[1], dstMAC[2], dstMAC[3], dstMAC[4], dstMAC[5]); + memcpy(sample->eth_dst, dstMAC, 6); + } + if(txMAC) dbg_printf("txMAC %02x%02x%02x%02x%02x%02x\n", txMAC[0], txMAC[1], txMAC[2], txMAC[3], txMAC[4], txMAC[5]); + if(rxMAC) dbg_printf("rxMAC %02x%02x%02x%02x%02x%02x\n", rxMAC[0], rxMAC[1], rxMAC[2], rxMAC[3], rxMAC[4], rxMAC[5]); + } + } +} + + +/*_________________---------------------------__________________ + _________________ decodeIPLayer4 __________________ + -----------------___________________________------------------ +*/ + +static void decodeIPLayer4(SFSample *sample, uint8_t *ptr) { + uint8_t *end = sample->header + sample->headerLen; + if(ptr > (end - 8)) { + /* not enough header bytes left */ + return; + } + switch(sample->dcd_ipProtocol) { + case 1: /* ICMP */ + { + struct myicmphdr icmp; + memcpy(&icmp, ptr, sizeof(icmp)); + dbg_printf("ICMPType %u\n", icmp.type); + dbg_printf("ICMPCode %u\n", icmp.code); + sample->dcd_sport = icmp.type; + sample->dcd_dport = icmp.code; + sample->offsetToPayload = ptr + sizeof(icmp) - sample->header; + } + break; + case 6: /* TCP */ + { + struct mytcphdr tcp; + int headerBytes; + memcpy(&tcp, ptr, sizeof(tcp)); + sample->dcd_sport = ntohs(tcp.th_sport); + sample->dcd_dport = ntohs(tcp.th_dport); + sample->dcd_tcpFlags = tcp.th_flags; + dbg_printf("TCPSrcPort %u\n", sample->dcd_sport); + dbg_printf("TCPDstPort %u\n",sample->dcd_dport); + dbg_printf("TCPFlags %u\n", sample->dcd_tcpFlags); + headerBytes = (tcp.th_off_and_unused >> 4) * 4; + ptr += headerBytes; + sample->offsetToPayload = ptr - sample->header; + } + break; + case 17: /* UDP */ + { + struct myudphdr udp; + memcpy(&udp, ptr, sizeof(udp)); + sample->dcd_sport = ntohs(udp.uh_sport); + sample->dcd_dport = ntohs(udp.uh_dport); + sample->udp_pduLen = ntohs(udp.uh_ulen); + dbg_printf("UDPSrcPort %u\n", sample->dcd_sport); + dbg_printf("UDPDstPort %u\n", sample->dcd_dport); + dbg_printf("UDPBytes %u\n", sample->udp_pduLen); + sample->offsetToPayload = ptr + sizeof(udp) - sample->header; + } + break; + default: /* some other protcol */ + sample->offsetToPayload = ptr - sample->header; + break; + } +} + + +/*_________________---------------------------__________________ + _________________ decodeIPV4 __________________ + -----------------___________________________------------------ +*/ + +static void decodeIPV4(SFSample *sample) +{ + if(sample->gotIPV4) { +#ifdef DEVEL + char buf[51]; +#endif + uint8_t *end = sample->header + sample->headerLen; + uint8_t *start = sample->header + sample->offsetToIPV4; + uint8_t *ptr = start; + if((end - ptr) < sizeof(struct myiphdr)) return; + + /* Create a local copy of the IP header (cannot overlay structure in case it is not quad-aligned...some + platforms would core-dump if we tried that). It's OK coz this probably performs just as well anyway. */ + struct myiphdr ip; + memcpy(&ip, ptr, sizeof(ip)); + /* Value copy all ip elements into sample */ + sample->ipsrc.type = SFLADDRESSTYPE_IP_V4; + sample->ipsrc.address.ip_v4.addr = ip.saddr; + sample->ipdst.type = SFLADDRESSTYPE_IP_V4; + sample->ipdst.address.ip_v4.addr = ip.daddr; + sample->dcd_srcIP.s_addr = ip.saddr; + sample->dcd_dstIP.s_addr = ip.daddr; + sample->dcd_ipProtocol = ip.protocol; + sample->dcd_ipTos = ip.tos; + sample->dcd_ipTTL = ip.ttl; + dbg_printf("ip.tot_len %d\n", ntohs(ip.tot_len)); + /* Log out the decoded IP fields */ + dbg_printf("srcIP %s\n", IP_to_a(sample->dcd_srcIP.s_addr, buf, 51)); + dbg_printf("dstIP %s\n", IP_to_a(sample->dcd_dstIP.s_addr, buf, 51)); + dbg_printf("IPProtocol %u\n", sample->dcd_ipProtocol); + dbg_printf("IPTOS %u\n", sample->dcd_ipTos); + dbg_printf("IPTTL %u\n", sample->dcd_ipTTL); + /* check for fragments */ + sample->ip_fragmentOffset = ntohs(ip.frag_off) & 0x1FFF; + if(sample->ip_fragmentOffset > 0) { + dbg_printf("IPFragmentOffset %u\n", sample->ip_fragmentOffset); + } + else { + dbg_printf("Unfragmented\n"); + /* advance the pointer to the next protocol layer */ + /* ip headerLen is expressed as a number of quads */ + uint32_t headerBytes = (ip.version_and_headerLen & 0x0f) * 4; + if((end - ptr) < headerBytes) return; + ptr += headerBytes; + decodeIPLayer4(sample, ptr); + } + } +} + +/*_________________---------------------------__________________ + _________________ decodeIPV6 __________________ + -----------------___________________________------------------ +*/ + +static void decodeIPV6(SFSample *sample) +{ + uint16_t payloadLen; + uint32_t label; + uint32_t nextHeader; + + uint8_t *end = sample->header + sample->headerLen; + uint8_t *start = sample->header + sample->offsetToIPV6; + uint8_t *ptr = start; + if((end - ptr) < sizeof(struct myip6hdr)) return; + + if(sample->gotIPV6) { + u_char *ptr = sample->header + sample->offsetToIPV6; + // check the version + { + int ipVersion = (*ptr >> 4); + if(ipVersion != 6) { + LogError("SFLOW: decodeIPV6() header decode error: unexpected IP version: %d\n", ipVersion); + return; + } + } + + // get the tos (priority) + sample->dcd_ipTos = *ptr++ & 15; + dbg_printf("IPTOS %u\n", sample->dcd_ipTos); + // 24-bit label + label = *ptr++; + label <<= 8; + label += *ptr++; + label <<= 8; + label += *ptr++; + dbg_printf("IP6_label 0x%x\n", label); + // payload + payloadLen = (ptr[0] << 8) + ptr[1]; + ptr += 2; + // if payload is zero, that implies a jumbo payload + if(payloadLen == 0) dbg_printf("IPV6_payloadLen \n"); + else dbg_printf("IPV6_payloadLen %u\n", payloadLen); + + // next header + nextHeader = *ptr++; + + // TTL + sample->dcd_ipTTL = *ptr++; + dbg_printf("IPTTL %u\n", sample->dcd_ipTTL); + + {// src and dst address +#ifdef DEVEL + char buf[101]; +#endif + sample->ipsrc.type = SFLADDRESSTYPE_IP_V6; + memcpy(&sample->ipsrc.address, ptr, 16); + ptr +=16; + dbg_printf("srcIP6 %s\n", printAddress(&sample->ipsrc, buf, 100)); + sample->ipdst.type = SFLADDRESSTYPE_IP_V6; + memcpy(&sample->ipdst.address, ptr, 16); + ptr +=16; + dbg_printf("dstIP6 %s\n", printAddress(&sample->ipdst, buf, 100)); + } + + // skip over some common header extensions... + // http://searchnetworking.techtarget.com/originalContent/0,289142,sid7_gci870277,00.html + while(nextHeader == 0 || // hop + nextHeader == 43 || // routing + nextHeader == 44 || // fragment + // nextHeader == 50 || // encryption - don't bother coz we'll not be able to read any further + nextHeader == 51 || // auth + nextHeader == 60) { // destination options + uint32_t optionLen, skip; + dbg_printf("IP6HeaderExtension: %d\n", nextHeader); + nextHeader = ptr[0]; + optionLen = 8 * (ptr[1] + 1); // second byte gives option len in 8-byte chunks, not counting first 8 + skip = optionLen - 2; + ptr += skip; + if(ptr > end) return; // ran off the end of the header + } + + // now that we have eliminated the extension headers, nextHeader should have what we want to + // remember as the ip protocol... + sample->dcd_ipProtocol = nextHeader; + dbg_printf("IPProtocol %u\n", sample->dcd_ipProtocol); + decodeIPLayer4(sample, ptr); + } +} + + +#include "inline.c" +#include "nffile_inline.c" +#include "collector_inline.c" + +/*_________________---------------------------__________________ + _________________ StoreSflowRecord __________________ + -----------------___________________________------------------ +*/ + +static inline void StoreSflowRecord(SFSample *sample, FlowSource_t *fs) { +common_record_t *common_record; +stat_record_t *stat_record = fs->nffile->stat_record; +exporter_sflow_t *exporter; +extension_map_t *extension_map; +struct timeval now; +void *next_data; +value32_t *val; +uint32_t bytes, j, id, ipsize, ip_flags; +uint64_t _bytes, _packets, _t; // tmp buffers + + dbg_printf("StoreSflowRecord\n"); + + gettimeofday(&now, NULL); + + if( sample->ip_fragmentOffset > 0 ) { + sample->dcd_sport = 0; + sample->dcd_dport = 0; + } + + bytes = sample->sampledPacketSize; + + ip_flags = 0; + if ( sample->nextHop.type == SFLADDRESSTYPE_IP_V6 ) + SetFlag(ip_flags, SFLOW_NEXT_HOP); + + if ( sample->bgp_nextHop.type == SFLADDRESSTYPE_IP_V6 ) + SetFlag(ip_flags, SFLOW_NEXT_HOP_BGP); + + if ( fs->sa_family == AF_INET6 ) + SetFlag(ip_flags, SFLOW_ROUTER_IP); + + ip_flags &= IP_extension_mask; + + if ( ip_flags >= MAX_SFLOW_EXTENSIONS ) { + LogError("SFLOW: Corrupt ip_flags: %u", ip_flags); + } + exporter = GetExporter(fs, sample->agentSubId, sample->meanSkipCount); + if ( !exporter ) { + LogError("SFLOW: Exporter NULL: Abort sflow record processing"); + return; + } + exporter->packets++; + + // get appropriate extension map + extension_map = exporter->sflow_extension_info[ip_flags].map; + if ( !extension_map ) { + LogInfo("SFLOW: setup extension map: %u", ip_flags); + if ( !Setup_Extension_Info(fs, exporter, ip_flags ) ) { + LogError("SFLOW: Extension map: NULL: Abort sflow record processing"); + return; + } + extension_map = exporter->sflow_extension_info[ip_flags].map; + LogInfo("SFLOW: setup extension map: %u done", ip_flags); + } + + // output buffer size check + // IPv6 needs 2 x 16 bytes, IPv4 2 x 4 bytes + ipsize = sample->gotIPV6 ? 32 : 8; + if ( !CheckBufferSpace(fs->nffile, sflow_output_record_size[ip_flags] + ipsize )) { + // fishy! - should never happen. maybe disk full? + LogError("SFLOW: output buffer size error. Abort sflow record processing"); + return; + } + + dbg_printf("Fill Record\n"); + common_record = (common_record_t *)fs->nffile->buff_ptr; + + common_record->size = sflow_output_record_size[ip_flags] + ipsize; + common_record->type = CommonRecordType; + common_record->flags = 0; + SetFlag(common_record->flags, FLAG_SAMPLED); + + common_record->exporter_sysid = exporter->info.sysid; + common_record->ext_map = extension_map->map_id; + + common_record->first = now.tv_sec; + common_record->last = common_record->first; + common_record->msec_first = now.tv_usec / 1000; + common_record->msec_last = common_record->msec_first; + _t = 1000LL * now.tv_sec + common_record->msec_first; // tmp buff for first_seen + + common_record->fwd_status = 0; + common_record->reserved = 0; + common_record->tcp_flags = sample->dcd_tcpFlags; + common_record->prot = sample->dcd_ipProtocol; + common_record->tos = sample->dcd_ipTos; + common_record->srcport = (uint16_t)sample->dcd_sport; + common_record->dstport = (uint16_t)sample->dcd_dport; + + if(sample->gotIPV6) { + u_char *b; + uint64_t *u; + ipv6_block_t *ipv6 = (ipv6_block_t *)common_record->data; + SetFlag(common_record->flags, FLAG_IPV6_ADDR); + + b = sample->ipsrc.address.ip_v6.addr; + u = (uint64_t *)b; + ipv6->srcaddr[0] = ntohll(*u); + u = (uint64_t *)&(b[8]); + ipv6->srcaddr[1] = ntohll(*u); + + b = sample->ipdst.address.ip_v6.addr; + u = (uint64_t *)b; + ipv6->dstaddr[0] = ntohll(*u); + u = (uint64_t *)&(b[8]); + ipv6->dstaddr[1] = ntohll(*u); + + next_data = (void *)ipv6->data; + } else { + ipv4_block_t *ipv4 = (ipv4_block_t *)common_record->data; + ipv4->srcaddr = ntohl(sample->dcd_srcIP.s_addr); + ipv4->dstaddr = ntohl(sample->dcd_dstIP.s_addr); + + next_data = (void *)ipv4->data; + } + + // 4 byte Packet value + val = (value32_t *)next_data; + val->val = sample->meanSkipCount; + _packets = val->val; + + // 4 byte Bytes value + val = (value32_t *)val->data; + val->val = sample->meanSkipCount * bytes; + _bytes = val->val; + + next_data = (void *)val->data; + + j = 0; + while ( (id = extension_map->ex_id[j]) != 0 ) { + switch (id) { + case EX_IO_SNMP_4: { // 4 byte input/output interface index + tpl_ext_5_t *tpl = (tpl_ext_5_t *)next_data; + tpl->input = sample->inputPort; + tpl->output = sample->outputPort; + next_data = (void *)tpl->data; + } break; + case EX_AS_4: { // 4 byte src/dst AS number + tpl_ext_7_t *tpl = (tpl_ext_7_t *)next_data; + tpl->src_as = sample->src_as; + tpl->dst_as = sample->dst_as; + next_data = (void *)tpl->data; + } break; + case EX_VLAN: { // 2 byte valn label + tpl_ext_13_t *tpl = (tpl_ext_13_t *)next_data; + tpl->src_vlan = sample->in_vlan; + tpl->dst_vlan = sample->out_vlan; + next_data = (void *)tpl->data; + } break; + case EX_MULIPLE: { // dst tos, direction, src/dst mask + tpl_ext_8_t *tpl = (tpl_ext_8_t *)next_data; + tpl->dst_tos = sample->dcd_ipTos; + tpl->dir = 0; + tpl->src_mask = sample->srcMask; + tpl->dst_mask = sample->dstMask; + next_data = (void *)tpl->data; + } break; + case EX_MAC_1: { // MAC addreses + tpl_ext_20_t *tpl = (tpl_ext_20_t *)next_data; + tpl->in_src_mac = Get_val48((void *)&sample->eth_src); + tpl->out_dst_mac = Get_val48((void *)&sample->eth_dst); + next_data = (void *)tpl->data; + } break; + case EX_NEXT_HOP_v4: { // next hop IPv4 router address + tpl_ext_9_t *tpl = (tpl_ext_9_t *)next_data; + if ( sample->nextHop.type == SFLADDRESSTYPE_IP_V4 ) { + tpl->nexthop = ntohl(sample->nextHop.address.ip_v4.addr); + } else { + tpl->nexthop = 0; + } + next_data = (void *)tpl->data; + } break; + case EX_NEXT_HOP_v6: { // next hop IPv6 router address + tpl_ext_10_t *tpl = (tpl_ext_10_t *)next_data; + void *ptr = (void *)sample->nextHop.address.ip_v6.addr; + if ( sample->nextHop.type == SFLADDRESSTYPE_IP_V6 ) { + tpl->nexthop[0] = ntohll(((uint64_t *)ptr)[0]); + tpl->nexthop[1] = ntohll(((uint64_t *)ptr)[1]); + } else { + tpl->nexthop[0] = 0; + tpl->nexthop[1] = 0; + } + SetFlag(common_record->flags, FLAG_IPV6_NH); + next_data = (void *)tpl->data; + } break; + case EX_NEXT_HOP_BGP_v4: { // next hop bgp IPv4 router address + tpl_ext_11_t *tpl = (tpl_ext_11_t *)next_data; + if ( sample->bgp_nextHop.type == SFLADDRESSTYPE_IP_V4 ) { + tpl->bgp_nexthop = ntohl(sample->bgp_nextHop.address.ip_v4.addr); + } else { + tpl->bgp_nexthop = 0; + } + next_data = (void *)tpl->data; + } break; + case EX_NEXT_HOP_BGP_v6: { // next hop IPv4 router address + tpl_ext_12_t *tpl = (tpl_ext_12_t *)next_data; + void *ptr = (void *)sample->bgp_nextHop.address.ip_v6.addr; + if ( sample->bgp_nextHop.type == SFLADDRESSTYPE_IP_V6 ) { + tpl->bgp_nexthop[0] = ntohll(((uint64_t *)ptr)[0]); + tpl->bgp_nexthop[1] = ntohll(((uint64_t *)ptr)[1]); + } else { + tpl->bgp_nexthop[0] = 0; + tpl->bgp_nexthop[1] = 0; + } + SetFlag(common_record->flags, FLAG_IPV6_NHB); + next_data = (void *)tpl->data; + } break; + case EX_ROUTER_IP_v4: + case EX_ROUTER_IP_v6: // IPv4/IPv6 router address + if(sample->agent_addr.type == SFLADDRESSTYPE_IP_V4) { + tpl_ext_23_t *tpl = (tpl_ext_23_t *)next_data; + tpl->router_ip = ntohl(sample->agent_addr.address.ip_v4.addr); + next_data = (void *)tpl->data; + ClearFlag(common_record->flags, FLAG_IPV6_EXP); + } else { + tpl_ext_24_t *tpl = (tpl_ext_24_t *)next_data; + void *ptr = (void *)sample->agent_addr.address.ip_v6.addr; + tpl->router_ip[0] = ntohll(((uint64_t *)ptr)[0]); + tpl->router_ip[1] = ntohll(((uint64_t *)ptr)[1]); + next_data = (void *)tpl->data; + SetFlag(common_record->flags, FLAG_IPV6_EXP); + } + break; + case EX_RECEIVED: { + tpl_ext_27_t *tpl = (tpl_ext_27_t *)next_data; + tpl->received = (uint64_t)((uint64_t)fs->received.tv_sec * 1000LL) + (uint64_t)((uint64_t)fs->received.tv_usec / 1000LL); + next_data = (void *)tpl->data; + } break; + default: + // this should never happen + LogError("SFLOW: Unexpected extension %i for sflow record. Skip extension", id); + dbg_printf("SFLOW: Unexpected extension %i for sflow record. Skip extension", id); + } + j++; + } + + // update first_seen, last_seen + if ( _t < fs->first_seen ) // the very first time stamp need to be set + fs->first_seen = _t; + fs->last_seen = _t; + + // Update stats + switch (common_record->prot) { + case 1: + stat_record->numflows_icmp++; + stat_record->numpackets_icmp += _packets; + stat_record->numbytes_icmp += _bytes; + break; + case 6: + stat_record->numflows_tcp++; + stat_record->numpackets_tcp += _packets; + stat_record->numbytes_tcp += _bytes; + break; + case 17: + stat_record->numflows_udp++; + stat_record->numpackets_udp += _packets; + stat_record->numbytes_udp += _bytes; + break; + default: + stat_record->numflows_other++; + stat_record->numpackets_other += _packets; + stat_record->numbytes_other += _bytes; + } + exporter->flows++; + stat_record->numflows++; + stat_record->numpackets += _packets; + stat_record->numbytes += _bytes; + + if ( verbose ) { + master_record_t master_record; + char *string; + ExpandRecord_v2((common_record_t *)common_record, &exporter->sflow_extension_info[ip_flags], &(exporter->info), &master_record); + format_file_block_record(&master_record, &string, 0); + printf("%s\n", string); + } + + // update file record size ( -> output buffer size ) + fs->nffile->block_header->NumRecords++; + fs->nffile->block_header->size += (sflow_output_record_size[ip_flags] + ipsize); +#ifdef DEVEL + if ( (next_data - fs->nffile->buff_ptr) != (sflow_output_record_size[ip_flags] + ipsize) ) { + printf("PANIC: Size error. Buffer diff: %llu, Size: %u\n", + (unsigned long long)(next_data - fs->nffile->buff_ptr), + (sflow_output_record_size[ip_flags] + ipsize)); + exit(255); + } +#endif + fs->nffile->buff_ptr = next_data; + +} + +void Init_sflow(void) { +int i, id; + + i=0; + Num_enabled_extensions = 0; + while ( (id = sflow_extensions[i]) != 0 ) { + if ( extension_descriptor[id].enabled ) { + dbg_printf("Enabled extension: %i\n", id); + Num_enabled_extensions++; + } + i++; + } + + IP_extension_mask = 0; + i=0; + while ( extension_descriptor[i].description != NULL ) { + switch (extension_descriptor[i].id) { + case EX_NEXT_HOP_v4: + // case EX_NEXT_HOP_v6: - not really needed + if ( extension_descriptor[i].enabled ) { + SetFlag(IP_extension_mask, SFLOW_NEXT_HOP); + Num_enabled_extensions++; + } break; + case EX_NEXT_HOP_BGP_v4: + // case EX_NEXT_HOP_BGP_v6: - not really needed + if ( extension_descriptor[i].enabled ) { + SetFlag(IP_extension_mask, SFLOW_NEXT_HOP_BGP); + Num_enabled_extensions++; + } break; + case EX_ROUTER_IP_v4: + // case EX_ROUTER_IP_v6: - not really needed + if ( extension_descriptor[i].enabled ) { + SetFlag(IP_extension_mask, SFLOW_ROUTER_IP); + Num_enabled_extensions++; + } break; + } + i++; + } + + dbg_printf("Num enabled Extensions: %i\n", Num_enabled_extensions); + +} // End of Init_sflow + +int Setup_Extension_Info(FlowSource_t *fs, exporter_sflow_t *exporter, int num) { +int i, id, extension_size, map_size, map_index; + + dbg_printf("Setup Extension ID 0x%x\n", num); + LogInfo("SFLOW: setup extension map %u", num); + + // prepare sflow extension map + exporter->sflow_extension_info[num].map = NULL; + extension_size = 0; + + // calculate the full extension map size + map_size = Num_enabled_extensions * sizeof(uint16_t) + sizeof(extension_map_t); + + // align 32 bits + if ( ( map_size & 0x3 ) != 0 ) + map_size += 2; + + + // Create a generic sflow extension map + exporter->sflow_extension_info[num].map = (extension_map_t *)malloc((size_t)map_size); + if ( !exporter->sflow_extension_info[num].map ) { + LogError("SFLOW: malloc() allocation error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) ); + return 0; + } + + // calclate the extension size + i=0; + map_index = 0; + while ( (id = sflow_extensions[i]) != 0 ) { + if ( extension_descriptor[id].enabled ) { + extension_size += extension_descriptor[id].size; + exporter->sflow_extension_info[num].map->ex_id[map_index++] = id; + } + i++; + } + + if ( TestFlag(IP_extension_mask, SFLOW_NEXT_HOP)) { + id = sflow_ip_extensions[num].next_hop; + extension_size += extension_descriptor[id].size; + exporter->sflow_extension_info[num].map->ex_id[map_index++] = id; + } + + if ( TestFlag(IP_extension_mask, SFLOW_NEXT_HOP_BGP)) { + id = sflow_ip_extensions[num].next_hop_bgp; + extension_size += extension_descriptor[id].size; + exporter->sflow_extension_info[num].map->ex_id[map_index++] = id; + } + + if ( TestFlag(IP_extension_mask, SFLOW_ROUTER_IP)) { + id = sflow_ip_extensions[num].router_ip; + extension_size += extension_descriptor[id].size; + exporter->sflow_extension_info[num].map->ex_id[map_index++] = id; + } + + // terminating null record + exporter->sflow_extension_info[num].map->ex_id[map_index] = 0; + + dbg_printf("Extension size: %i\n", extension_size); + + // caculate the basic record size: without IP addr space ( v4/v6 dependant ) + // byte/packet counters are 32bit -> 2 x uint32_t + // extension_size contains the sum of all optional extensions + sflow_output_record_size[num] = COMMON_RECORD_DATA_SIZE + 2*sizeof(uint32_t) + extension_size; + + dbg_printf("Record size: %i\n", sflow_output_record_size[num]); + + exporter->sflow_extension_info[num].map->type = ExtensionMapType; + exporter->sflow_extension_info[num].map->size = map_size; + exporter->sflow_extension_info[num].map->map_id = INIT_ID; + exporter->sflow_extension_info[num].map->extension_size = extension_size; + + LogInfo("Extension size: %i", extension_size); + LogInfo("Extension map size: %i", map_size); + + if ( !AddExtensionMap(fs, exporter->sflow_extension_info[num].map) ) { + // bad - we must free this map and fail - otherwise data can not be read any more + free(exporter->sflow_extension_info[num].map); + exporter->sflow_extension_info[num].map = NULL; + return 0; + } + dbg_printf("New Extension map ID %i\n", exporter->sflow_extension_info[num].map->map_id); + LogInfo("New extension map id: %i", exporter->sflow_extension_info[num].map->map_id); + + return 1; + +} // End of Setup_Extension_Info + +static inline exporter_sflow_t *GetExporter(FlowSource_t *fs, uint32_t agentSubId, uint32_t meanSkipCount) { +exporter_sflow_t **e = (exporter_sflow_t **)&(fs->exporter_data); +generic_sampler_t *sampler; +#define IP_STRING_LEN 40 +char ipstr[IP_STRING_LEN]; +int i; + + // search the appropriate exporter engine + while ( *e ) { + if ( (*e)->info.id == agentSubId && (*e)->info.version == SFLOW_VERSION && + (*e)->info.ip.V6[0] == fs->ip.V6[0] && (*e)->info.ip.V6[1] == fs->ip.V6[1]) + return *e; + e = &((*e)->next); + } + + if ( fs->sa_family == AF_INET ) { + uint32_t _ip = htonl(fs->ip.V4); + inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr)); + } else if ( fs->sa_family == AF_INET6 ) { + uint64_t _ip[2]; + _ip[0] = htonll(fs->ip.V6[0]); + _ip[1] = htonll(fs->ip.V6[1]); + inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr)); + } else { + strncpy(ipstr, "", IP_STRING_LEN); + } + + // nothing found + LogInfo("SFLOW: New exporter" ); + + *e = (exporter_sflow_t *)malloc(sizeof(exporter_sflow_t)); + if ( !(*e)) { + LogError("SFLOW: malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror (errno)); + return NULL; + } + memset((void *)(*e), 0, sizeof(exporter_sflow_t)); + (*e)->next = NULL; + (*e)->info.header.type = ExporterInfoRecordType; + (*e)->info.header.size = sizeof(exporter_info_record_t); + (*e)->info.version = SFLOW_VERSION; + (*e)->info.id = agentSubId; + (*e)->info.ip = fs->ip; + (*e)->info.sa_family = fs->sa_family; + (*e)->sequence_failure = 0; + (*e)->packets = 0; + (*e)->flows = 0; + for (i=0; isflow_extension_info[i].map = NULL; + } + + sampler = (generic_sampler_t *)malloc(sizeof(generic_sampler_t)); + if ( !sampler ) { + LogError("SFLOW: malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror (errno)); + return NULL; + } + (*e)->sampler = sampler; + + sampler->info.header.type = SamplerInfoRecordype; + sampler->info.header.size = sizeof(sampler_info_record_t); + sampler->info.id = -1; + sampler->info.mode = 0; + sampler->info.interval = meanSkipCount; + sampler->next = NULL; + + FlushInfoExporter(fs, &((*e)->info)); + sampler->info.exporter_sysid = (*e)->info.sysid; + FlushInfoSampler(fs, &(sampler->info)); + + dbg_printf("SFLOW: New exporter: SysID: %u, agentSubId: %u, MeanSkipCount: %u, IP: %s\n", + (*e)->info.sysid, agentSubId, meanSkipCount, ipstr); + LogInfo("SFLOW: New exporter: SysID: %u, agentSubId: %u, MeanSkipCount: %u, IP: %s", + (*e)->info.sysid, agentSubId, meanSkipCount, ipstr); + + return (*e); + +} // End of GetExporter + +void Process_sflow(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs) { + +SFSample sample; +int exceptionVal; + + memset(&sample, 0, sizeof(sample)); + sample.rawSample = in_buff; + sample.rawSampleLen = in_buff_cnt; + sample.sourceIP.s_addr = fs->sa_family == PF_INET ? htonl(fs->ip.V4) : 0;; + + dbg_printf("startDatagram =================================\n"); + if((exceptionVal = setjmp(sample.env)) == 0) { + // TRY + sample.datap = (uint32_t *)sample.rawSample; + sample.endp = (u_char *)sample.rawSample + sample.rawSampleLen; + readSFlowDatagram(&sample, fs ); + } else { + // CATCH + dbg_printf("SFLOW: caught exception: %d\n", exceptionVal); + LogError("SFLOW: caught exception: %d", exceptionVal); + } + dbg_printf("endDatagram =================================\n"); + +} // End of Process_sflow + + +// include sflow functions +// based on sflowtool https://github.com/sflow/sflowtool +// commit 7322984 on Jul 21 + +/*_________________---------------------------__________________ + _________________ read data fns __________________ + -----------------___________________________------------------ +*/ + +static uint32_t getData32_nobswap(SFSample *sample) { + uint32_t ans = *(sample->datap)++; + /* make sure we didn't run off the end of the datagram. Thanks to + Sven Eschenberg for spotting a bug/overrun-vulnerabilty that was here before. */ + if((uint8_t *)sample->datap > sample->endp) { + SFABORT(sample, SF_ABORT_EOS); + } + return ans; +} + +static uint32_t getData32(SFSample *sample) { + return ntohl(getData32_nobswap(sample)); +} + +static float getFloat(SFSample *sample) { + float fl; + uint32_t reg = getData32(sample); + memcpy(&fl, ®, 4); + return fl; +} + +static uint64_t getData64(SFSample *sample) { + uint64_t tmpLo, tmpHi; + tmpHi = getData32(sample); + tmpLo = getData32(sample); + return (tmpHi << 32) + tmpLo; +} + +static double getDouble(SFSample *sample) { + double dbl; + uint64_t reg = getData64(sample); + memcpy(&dbl, ®, 8); + return dbl; +} + +static void inline skipBytes(SFSample *sample, uint32_t skip) { + int quads = (skip + 3) / 4; + sample->datap += quads; + if(skip > sample->rawSampleLen || (uint8_t *)sample->datap > sample->endp) { + SFABORT(sample, SF_ABORT_EOS); + } +} + +static uint32_t sf_log_next32(SFSample *sample, char *fieldName) { + uint32_t val = getData32(sample); + dbg_printf("%s %u\n", fieldName, val); + return val; +} + +static uint64_t sf_log_next64(SFSample *sample, char *fieldName) { + uint64_t val64 = getData64(sample); + dbg_printf("%s %llu\n", fieldName, (unsigned long long)val64); + return val64; +} + +void sf_log_percentage(SFSample *sample, char *fieldName) +{ + uint32_t hundredths = getData32(sample); + if(hundredths == (uint32_t)-1) dbg_printf("%s unknown\n", fieldName); + else { +#ifdef DEVEL + float percent = (float)hundredths / (float)100.0; + dbg_printf("%s %.2f\n", fieldName, percent); +#endif + } +} + +static float sf_log_nextFloat(SFSample *sample, char *fieldName) { + float val = getFloat(sample); + dbg_printf("%s %.3f\n", fieldName, val); + return val; +} + +static void sf_log_nextMAC(SFSample *sample, char *fieldName) +{ +#ifdef DEVEL + uint8_t *mac = (uint8_t *)sample->datap; +#endif + skipBytes(sample, 6); + dbg_printf("%s %02x%02x%02x%02x%02x%02x\n", fieldName, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +static inline uint32_t getString(SFSample *sample, char *buf, uint32_t bufLen) { + uint32_t len, read_len; + len = getData32(sample); + /* check the bytes are there first */ + uint32_t *dp = sample->datap; + skipBytes(sample, len); + /* truncate if too long */ + read_len = (len >= bufLen) ? (bufLen - 1) : len; + memcpy(buf, dp, read_len); + buf[read_len] = '\0'; /* null terminate */ + return len; +} + +static uint32_t getAddress(SFSample *sample, SFLAddress *address) { + address->type = getData32(sample); + switch(address->type) { + case SFLADDRESSTYPE_IP_V4: + address->address.ip_v4.addr = getData32_nobswap(sample); + break; + case SFLADDRESSTYPE_IP_V6: + { + /* make sure the data is there before we memcpy */ + uint32_t *dp = sample->datap; + skipBytes(sample, 16); + memcpy(&address->address.ip_v6.addr, dp, 16); + } + break; + default: + /* undefined address type - bail out */ + LogError("SFLOW: getAddress() unknown address type = %d\n", address->type); + SFABORT(sample, SF_ABORT_EOS); + } + return address->type; +} + +static void skipTLVRecord(SFSample *sample, uint32_t tag, uint32_t len, char *description) { +#ifdef DEVEL + char buf[51]; +#endif + dbg_printf("skipping unknown %s: %s len=%d\n", description, printTag(tag, buf, 50), len); + skipBytes(sample, len); +} + +/*_________________---------------------------__________________ + _________________ readExtendedSwitch __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedSwitch(SFSample *sample) +{ + dbg_printf("extendedType SWITCH\n"); + sample->in_vlan = getData32(sample); + sample->in_priority = getData32(sample); + sample->out_vlan = getData32(sample); + sample->out_priority = getData32(sample); + + sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_SWITCH; + + dbg_printf("in_vlan %u\n", sample->in_vlan); + dbg_printf("in_priority %u\n", sample->in_priority); + dbg_printf("out_vlan %u\n", sample->out_vlan); + dbg_printf("out_priority %u\n", sample->out_priority); +} + +/*_________________---------------------------__________________ + _________________ readExtendedRouter __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedRouter(SFSample *sample) +{ +#ifdef DEVEL + char buf[51]; +#endif + dbg_printf("extendedType ROUTER\n"); + getAddress(sample, &sample->nextHop); + sample->srcMask = getData32(sample); + sample->dstMask = getData32(sample); + + sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_ROUTER; + + dbg_printf("nextHop %s\n", printAddress(&sample->nextHop, buf, 50)); + dbg_printf("srcSubnetMask %u\n", sample->srcMask); + dbg_printf("dstSubnetMask %u\n", sample->dstMask); +} + +/*_________________---------------------------__________________ + _________________ readExtendedGateway_v2 __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedGateway_v2(SFSample *sample) +{ + dbg_printf("extendedType GATEWAY\n"); + + sample->my_as = getData32(sample); + sample->src_as = getData32(sample); + sample->src_peer_as = getData32(sample); + + /* clear dst_peer_as and dst_as to make sure we are not + remembering values from a previous sample - (thanks Marc Lavine) */ + sample->dst_peer_as = 0; + sample->dst_as = 0; + + sample->dst_as_path_len = getData32(sample); + /* just point at the dst_as_path array */ + if(sample->dst_as_path_len > 0) { + sample->dst_as_path = sample->datap; + /* and skip over it in the input */ + skipBytes(sample, sample->dst_as_path_len * 4); + /* fill in the dst and dst_peer fields too */ + sample->dst_peer_as = ntohl(sample->dst_as_path[0]); + sample->dst_as = ntohl(sample->dst_as_path[sample->dst_as_path_len - 1]); + } + + sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_GATEWAY; + + dbg_printf("my_as %u\n", sample->my_as); + dbg_printf("src_as %u\n", sample->src_as); + dbg_printf("src_peer_as %u\n", sample->src_peer_as); + dbg_printf("dst_as %u\n", sample->dst_as); + dbg_printf("dst_peer_as %u\n", sample->dst_peer_as); + dbg_printf("dst_as_path_len %u\n", sample->dst_as_path_len); + if(sample->dst_as_path_len > 0) { + uint32_t i = 0; + for(; i < sample->dst_as_path_len; i++) { + if(i == 0) dbg_printf("dst_as_path "); + else dbg_printf("-"); + dbg_printf("%u", ntohl(sample->dst_as_path[i])); + } + dbg_printf("\n"); + } +} + +/*_________________---------------------------__________________ + _________________ readExtendedGateway __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedGateway(SFSample *sample) +{ + uint32_t segments; + uint32_t seg; +#ifdef DEVEL + char buf[51]; +#endif + + dbg_printf("extendedType GATEWAY\n"); + + if(sample->datagramVersion >= 5) { + getAddress(sample, &sample->bgp_nextHop); + dbg_printf("bgp_nexthop %s\n", printAddress(&sample->bgp_nextHop, buf, 50)); + } + + sample->my_as = getData32(sample); + sample->src_as = getData32(sample); + sample->src_peer_as = getData32(sample); + dbg_printf("my_as %u\n", sample->my_as); + dbg_printf("src_as %u\n", sample->src_as); + dbg_printf("src_peer_as %u\n", sample->src_peer_as); + segments = getData32(sample); + + /* clear dst_peer_as and dst_as to make sure we are not + remembering values from a previous sample - (thanks Marc Lavine) */ + sample->dst_peer_as = 0; + sample->dst_as = 0; + + if(segments > 0) { + dbg_printf("dst_as_path "); + for(seg = 0; seg < segments; seg++) { + uint32_t seg_type; + uint32_t seg_len; + uint32_t i; + seg_type = getData32(sample); + seg_len = getData32(sample); + for(i = 0; i < seg_len; i++) { + uint32_t asNumber; + asNumber = getData32(sample); + /* mark the first one as the dst_peer_as */ + if(i == 0 && seg == 0) sample->dst_peer_as = asNumber; + else dbg_printf("-"); + /* make sure the AS sets are in parentheses */ + if(i == 0 && seg_type == SFLEXTENDED_AS_SET) dbg_printf("("); + dbg_printf("%u", asNumber); + /* mark the last one as the dst_as */ + if(seg == (segments - 1) && i == (seg_len - 1)) sample->dst_as = asNumber; + } + if(seg_type == SFLEXTENDED_AS_SET) dbg_printf(")"); + } + dbg_printf("\n"); + } + dbg_printf("dst_as %u\n", sample->dst_as); + dbg_printf("dst_peer_as %u\n", sample->dst_peer_as); + + sample->communities_len = getData32(sample); + /* just point at the communities array */ + if(sample->communities_len > 0) sample->communities = sample->datap; + /* and skip over it in the input */ + skipBytes(sample, sample->communities_len * 4); + + sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_GATEWAY; + if(sample->communities_len > 0) { + uint32_t j = 0; + for(; j < sample->communities_len; j++) { + if(j == 0) dbg_printf("BGP_communities "); + else dbg_printf("-"); + dbg_printf("%u", ntohl(sample->communities[j])); + } + dbg_printf("\n"); + } + + sample->localpref = getData32(sample); + dbg_printf("BGP_localpref %u\n", sample->localpref); + +} + +/*_________________---------------------------__________________ + _________________ readExtendedUser __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedUser(SFSample *sample) +{ + dbg_printf("extendedType USER\n"); + + if(sample->datagramVersion >= 5) { + sample->src_user_charset = getData32(sample); + dbg_printf("src_user_charset %d\n", sample->src_user_charset); + } + + sample->src_user_len = getString(sample, sample->src_user, SA_MAX_EXTENDED_USER_LEN); + + if(sample->datagramVersion >= 5) { + sample->dst_user_charset = getData32(sample); + dbg_printf("dst_user_charset %d\n", sample->dst_user_charset); + } + + sample->dst_user_len = getString(sample, sample->dst_user, SA_MAX_EXTENDED_USER_LEN); + + sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_USER; + + dbg_printf("src_user %s\n", sample->src_user); + dbg_printf("dst_user %s\n", sample->dst_user); +} + +/*_________________---------------------------__________________ + _________________ readExtendedUrl __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedUrl(SFSample *sample) +{ + dbg_printf("extendedType URL\n"); + + sample->url_direction = getData32(sample); + dbg_printf("url_direction %u\n", sample->url_direction); + sample->url_len = getString(sample, sample->url, SA_MAX_EXTENDED_URL_LEN); + dbg_printf("url %s\n", sample->url); + if(sample->datagramVersion >= 5) { + sample->host_len = getString(sample, sample->host, SA_MAX_EXTENDED_HOST_LEN); + dbg_printf("host %s\n", sample->host); + } + sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_URL; +} + + +/*_________________---------------------------__________________ + _________________ mplsLabelStack __________________ + -----------------___________________________------------------ +*/ + +static void mplsLabelStack(SFSample *sample, char *fieldName) +{ + SFLLabelStack lstk; + uint32_t lab; + lstk.depth = getData32(sample); + /* just point at the lablelstack array */ + if(lstk.depth > 0) lstk.stack = (uint32_t *)sample->datap; + /* and skip over it in the input */ + skipBytes(sample, lstk.depth * 4); + + if(lstk.depth > 0) { + uint32_t j = 0; + for(; j < lstk.depth; j++) { + if(j == 0) dbg_printf("%s ", fieldName); + else dbg_printf("-"); + lab = ntohl(lstk.stack[j]); + dbg_printf("%u.%u.%u.%u", + (lab >> 12), /* label */ + (lab >> 9) & 7, /* experimental */ + (lab >> 8) & 1, /* bottom of stack */ + (lab & 255)); /* TTL */ + } + dbg_printf("\n"); + } +} + +/*_________________---------------------------__________________ + _________________ readExtendedMpls __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedMpls(SFSample *sample) +{ +#ifdef DEVEL + char buf[51]; +#endif + dbg_printf("extendedType MPLS\n"); + getAddress(sample, &sample->mpls_nextHop); + dbg_printf("mpls_nexthop %s\n", printAddress(&sample->mpls_nextHop, buf, 50)); + + mplsLabelStack(sample, "mpls_input_stack"); + mplsLabelStack(sample, "mpls_output_stack"); + + sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_MPLS; +} + +/*_________________---------------------------__________________ + _________________ readExtendedNat __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedNat(SFSample *sample) +{ +#ifdef DEVEL + char buf[51]; +#endif + dbg_printf("extendedType NAT\n"); + getAddress(sample, &sample->nat_src); + dbg_printf("nat_src %s\n", printAddress(&sample->nat_src, buf, 50)); + getAddress(sample, &sample->nat_dst); + dbg_printf("nat_dst %s\n", printAddress(&sample->nat_dst, buf, 50)); + sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_NAT; +} + +/*_________________---------------------------__________________ + _________________ readExtendedNatPort __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedNatPort(SFSample *sample) +{ + dbg_printf("extendedType NAT PORT\n"); + sf_log_next32(sample, "nat_src_port"); + sf_log_next32(sample, "nat_dst_port"); +} + + +/*_________________---------------------------__________________ + _________________ readExtendedMplsTunnel __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedMplsTunnel(SFSample *sample) +{ +#define SA_MAX_TUNNELNAME_LEN 100 + char tunnel_name[SA_MAX_TUNNELNAME_LEN+1]; + uint32_t tunnel_id, tunnel_cos; + + if(getString(sample, tunnel_name, SA_MAX_TUNNELNAME_LEN) > 0) + dbg_printf("mpls_tunnel_lsp_name %s\n", tunnel_name); + tunnel_id = getData32(sample); + dbg_printf("mpls_tunnel_id %u\n", tunnel_id); + tunnel_cos = getData32(sample); + dbg_printf("mpls_tunnel_cos %u\n", tunnel_cos); + sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_MPLS_TUNNEL; +} + +/*_________________---------------------------__________________ + _________________ readExtendedMplsVC __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedMplsVC(SFSample *sample) +{ +#define SA_MAX_VCNAME_LEN 100 + char vc_name[SA_MAX_VCNAME_LEN+1]; + uint32_t vll_vc_id, vc_cos; + if(getString(sample, vc_name, SA_MAX_VCNAME_LEN) > 0) + dbg_printf("mpls_vc_name %s\n", vc_name); + vll_vc_id = getData32(sample); + dbg_printf("mpls_vll_vc_id %u\n", vll_vc_id); + vc_cos = getData32(sample); + dbg_printf("mpls_vc_cos %u\n", vc_cos); + sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_MPLS_VC; +} + +/*_________________---------------------------__________________ + _________________ readExtendedMplsFTN __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedMplsFTN(SFSample *sample) +{ +#define SA_MAX_FTN_LEN 100 + char ftn_descr[SA_MAX_FTN_LEN+1]; + uint32_t ftn_mask; + if(getString(sample, ftn_descr, SA_MAX_FTN_LEN) > 0) + dbg_printf("mpls_ftn_descr %s\n", ftn_descr); + ftn_mask = getData32(sample); + dbg_printf("mpls_ftn_mask %u\n", ftn_mask); + sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_MPLS_FTN; +} + +/*_________________---------------------------__________________ + _________________ readExtendedMplsLDP_FEC __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedMplsLDP_FEC(SFSample *sample) +{ +#ifdef DEVEL + uint32_t fec_addr_prefix_len = getData32(sample); + dbg_printf("mpls_fec_addr_prefix_len %u\n", fec_addr_prefix_len); +#endif + sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_MPLS_LDP_FEC; +} + +/*_________________---------------------------__________________ + _________________ readExtendedVlanTunnel __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedVlanTunnel(SFSample *sample) +{ + uint32_t lab; + SFLLabelStack lstk; + lstk.depth = getData32(sample); + /* just point at the lablelstack array */ + if(lstk.depth > 0) lstk.stack = (uint32_t *)sample->datap; + /* and skip over it in the input */ + skipBytes(sample, lstk.depth * 4); + + if(lstk.depth > 0) { + uint32_t j = 0; + for(; j < lstk.depth; j++) { + if(j == 0) dbg_printf("vlan_tunnel "); + else dbg_printf("-"); + lab = ntohl(lstk.stack[j]); + dbg_printf("0x%04x.%u.%u.%u", + (lab >> 16), /* TPI */ + (lab >> 13) & 7, /* priority */ + (lab >> 12) & 1, /* CFI */ + (lab & 4095)); /* VLAN */ + } + dbg_printf("\n"); + } + sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_VLAN_TUNNEL; +} + +/*_________________---------------------------__________________ + _________________ readExtendedWifiPayload __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedWifiPayload(SFSample *sample) +{ + sf_log_next32(sample, "cipher_suite"); + readFlowSample_header(sample); +} + +/*_________________---------------------------__________________ + _________________ readExtendedWifiRx __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedWifiRx(SFSample *sample) +{ + uint32_t i; + uint8_t *bssid; + char ssid[SFL_MAX_SSID_LEN+1]; + if(getString(sample, ssid, SFL_MAX_SSID_LEN) > 0) { + dbg_printf("rx_SSID %s\n", ssid); + } + + bssid = (uint8_t *)sample->datap; + dbg_printf("rx_BSSID "); + for(i = 0; i < 6; i++) dbg_printf("%02x", bssid[i]); + dbg_printf("\n"); + skipBytes(sample, 6); + + sf_log_next32(sample, "rx_version"); + sf_log_next32(sample, "rx_channel"); + sf_log_next64(sample, "rx_speed"); + sf_log_next32(sample, "rx_rsni"); + sf_log_next32(sample, "rx_rcpi"); + sf_log_next32(sample, "rx_packet_uS"); +} + +/*_________________---------------------------__________________ + _________________ readExtendedWifiTx __________________ + -----------------___________________________------------------ +*/ + +static void readExtendedWifiTx(SFSample *sample) +{ + uint32_t i; + uint8_t *bssid; + char ssid[SFL_MAX_SSID_LEN+1]; + if(getString(sample, ssid, SFL_MAX_SSID_LEN) > 0) { + dbg_printf("tx_SSID %s\n", ssid); + } + + bssid = (uint8_t *)sample->datap; + dbg_printf("tx_BSSID "); + for(i = 0; i < 6; i++) dbg_printf("%02x", bssid[i]); + dbg_printf("\n"); + skipBytes(sample, 6); + + sf_log_next32(sample, "tx_version"); + sf_log_next32(sample, "tx_transmissions"); + sf_log_next32(sample, "tx_packet_uS"); + sf_log_next32(sample, "tx_retrans_uS"); + sf_log_next32(sample, "tx_channel"); + sf_log_next64(sample, "tx_speed"); + sf_log_next32(sample, "tx_power_mW"); +} + +/*_________________---------------------------__________________ + _________________ readExtendedAggregation __________________ + -----------------___________________________------------------ +*/ + +#if 0 /* commenting this out until its caller is uncommented too */ +static void readExtendedAggregation(SFSample *sample) +{ + uint32_t i, num_pdus = getData32(sample); + dbg_printf("aggregation_num_pdus %u\n", num_pdus); + for(i = 0; i < num_pdus; i++) { + dbg_printf("aggregation_pdu %u\n", i); + readFlowSample(sample, NO); /* not sure if this the right one here */ + } +} +#endif + +/*_________________---------------------------__________________ + _________________ readFlowSample_header __________________ + -----------------___________________________------------------ +*/ + +static void readFlowSample_header(SFSample *sample) +{ + dbg_printf("flowSampleType HEADER\n"); + sample->headerProtocol = getData32(sample); + dbg_printf("headerProtocol %u\n", sample->headerProtocol); + sample->sampledPacketSize = getData32(sample); + dbg_printf("sampledPacketSize %u\n", sample->sampledPacketSize); + if(sample->datagramVersion > 4) { + /* stripped count introduced in sFlow version 5 */ + sample->stripped = getData32(sample); + dbg_printf("strippedBytes %u\n", sample->stripped); + } + sample->headerLen = getData32(sample); + dbg_printf("headerLen %u\n", sample->headerLen); + + sample->header = (uint8_t *)sample->datap; /* just point at the header */ + skipBytes(sample, sample->headerLen); + { + char scratch[2000]; + printHex(sample->header, sample->headerLen, scratch, 2000, 0, 2000); + dbg_printf("headerBytes %s\n", scratch); + } + + switch(sample->headerProtocol) { + /* the header protocol tells us where to jump into the decode */ + case SFLHEADER_ETHERNET_ISO8023: + decodeLinkLayer(sample); + break; + case SFLHEADER_IPv4: + sample->gotIPV4 = YES; + sample->offsetToIPV4 = 0; + break; + case SFLHEADER_IPv6: + sample->gotIPV6 = YES; + sample->offsetToIPV6 = 0; + break; + case SFLHEADER_IEEE80211MAC: + decode80211MAC(sample); + break; + case SFLHEADER_ISO88024_TOKENBUS: + case SFLHEADER_ISO88025_TOKENRING: + case SFLHEADER_FDDI: + case SFLHEADER_FRAME_RELAY: + case SFLHEADER_X25: + case SFLHEADER_PPP: + case SFLHEADER_SMDS: + case SFLHEADER_AAL5: + case SFLHEADER_AAL5_IP: + case SFLHEADER_MPLS: + case SFLHEADER_POS: + case SFLHEADER_IEEE80211_AMPDU: + case SFLHEADER_IEEE80211_AMSDU_SUBFRAME: + dbg_printf("NO_DECODE headerProtocol=%d\n", sample->headerProtocol); + break; + default: + LogError("SFLOW: readFlowSample_header() undefined headerProtocol = %d\n", sample->headerProtocol); + exit(-12); + } + + if(sample->gotIPV4) { + /* report the size of the original IPPdu (including the IP header) */ + dbg_printf("IPSize %d\n", sample->sampledPacketSize - sample->stripped - sample->offsetToIPV4); + decodeIPV4(sample); + } + else if(sample->gotIPV6) { + /* report the size of the original IPPdu (including the IP header) */ + dbg_printf("IPSize %d\n", sample->sampledPacketSize - sample->stripped - sample->offsetToIPV6); + decodeIPV6(sample); + } + +} + +/*_________________---------------------------__________________ + _________________ readFlowSample_ethernet __________________ + -----------------___________________________------------------ +*/ + +static void readFlowSample_ethernet(SFSample *sample, char *prefix) +{ + uint8_t *p; + dbg_printf("flowSampleType %sETHERNET\n", prefix); + sample->eth_len = getData32(sample); + memcpy(sample->eth_src, sample->datap, 6); + skipBytes(sample, 6); + memcpy(sample->eth_dst, sample->datap, 6); + skipBytes(sample, 6); + sample->eth_type = getData32(sample); + dbg_printf("%sethernet_type %u\n", prefix, sample->eth_type); + dbg_printf("%sethernet_len %u\n", prefix, sample->eth_len); + p = sample->eth_src; + dbg_printf("%sethernet_src %02x%02x%02x%02x%02x%02x\n", prefix, p[0], p[1], p[2], p[3], p[4], p[5]); + p = sample->eth_dst; + dbg_printf("%sethernet_dst %02x%02x%02x%02x%02x%02x\n", prefix, p[0], p[1], p[2], p[3], p[4], p[5]); +} + + +/*_________________---------------------------__________________ + _________________ readFlowSample_IPv4 __________________ + -----------------___________________________------------------ +*/ + +static void readFlowSample_IPv4(SFSample *sample, char *prefix) +{ + dbg_printf("flowSampleType %sIPV4\n", prefix); + sample->headerLen = sizeof(SFLSampled_ipv4); + sample->header = (uint8_t *)sample->datap; /* just point at the header */ + skipBytes(sample, sample->headerLen); + { +#ifdef DEVEL + char buf[51]; +#endif + SFLSampled_ipv4 nfKey; + memcpy(&nfKey, sample->header, sizeof(nfKey)); + sample->sampledPacketSize = ntohl(nfKey.length); + dbg_printf("%ssampledPacketSize %u\n", prefix, sample->sampledPacketSize); + dbg_printf("%sIPSize %u\n", prefix, sample->sampledPacketSize); + sample->ipsrc.type = SFLADDRESSTYPE_IP_V4; + sample->ipsrc.address.ip_v4 = nfKey.src_ip; + sample->ipdst.type = SFLADDRESSTYPE_IP_V4; + sample->ipdst.address.ip_v4 = nfKey.dst_ip; + sample->dcd_ipProtocol = ntohl(nfKey.protocol); + sample->dcd_ipTos = ntohl(nfKey.tos); + dbg_printf("%ssrcIP %s\n", prefix, printAddress(&sample->ipsrc, buf, 50)); + dbg_printf("%sdstIP %s\n", prefix, printAddress(&sample->ipdst, buf, 50)); + dbg_printf("%sIPProtocol %u\n", prefix, sample->dcd_ipProtocol); + dbg_printf("%sIPTOS %u\n", prefix, sample->dcd_ipTos); + sample->dcd_sport = ntohl(nfKey.src_port); + sample->dcd_dport = ntohl(nfKey.dst_port); + switch(sample->dcd_ipProtocol) { + case 1: /* ICMP */ + dbg_printf("%sICMPType %u\n", prefix, sample->dcd_dport); + /* not sure about the dest port being icmp type + - might be that src port is icmp type and dest + port is icmp code. Still, have seen some + implementations where src port is 0 and dst + port is the type, so it may be safer to + assume that the destination port has the type */ + break; + case 6: /* TCP */ + dbg_printf("%sTCPSrcPort %u\n", prefix, sample->dcd_sport); + dbg_printf("%sTCPDstPort %u\n", prefix, sample->dcd_dport); + sample->dcd_tcpFlags = ntohl(nfKey.tcp_flags); + dbg_printf("%sTCPFlags %u\n", prefix, sample->dcd_tcpFlags); + break; + case 17: /* UDP */ + dbg_printf("%sUDPSrcPort %u\n", prefix, sample->dcd_sport); + dbg_printf("%sUDPDstPort %u\n", prefix, sample->dcd_dport); + break; + default: /* some other protcol */ + break; + } + } +} + +/*_________________---------------------------__________________ + _________________ readFlowSample_IPv6 __________________ + -----------------___________________________------------------ +*/ + +static void readFlowSample_IPv6(SFSample *sample, char *prefix) +{ + dbg_printf("flowSampleType %sIPV6\n", prefix); + sample->header = (uint8_t *)sample->datap; /* just point at the header */ + sample->headerLen = sizeof(SFLSampled_ipv6); + skipBytes(sample, sample->headerLen); + { +#ifdef DEVEL + char buf[51]; +#endif + SFLSampled_ipv6 nfKey6; + memcpy(&nfKey6, sample->header, sizeof(nfKey6)); + sample->sampledPacketSize = ntohl(nfKey6.length); + dbg_printf("%ssampledPacketSize %u\n", prefix, sample->sampledPacketSize); + dbg_printf("%sIPSize %u\n", prefix, sample->sampledPacketSize); + sample->ipsrc.type = SFLADDRESSTYPE_IP_V6; + memcpy(&sample->ipsrc.address.ip_v6, &nfKey6.src_ip, 16); + sample->ipdst.type = SFLADDRESSTYPE_IP_V6; + memcpy(&sample->ipdst.address.ip_v6, &nfKey6.dst_ip, 16); + sample->dcd_ipProtocol = ntohl(nfKey6.protocol); + dbg_printf("%ssrcIP6 %s\n", prefix, printAddress(&sample->ipsrc, buf, 50)); + dbg_printf("%sdstIP6 %s\n", prefix, printAddress(&sample->ipdst, buf, 50)); + dbg_printf("%sIPProtocol %u\n", prefix, sample->dcd_ipProtocol); + dbg_printf("%spriority %u\n", prefix, ntohl(nfKey6.priority)); + sample->dcd_sport = ntohl(nfKey6.src_port); + sample->dcd_dport = ntohl(nfKey6.dst_port); + switch(sample->dcd_ipProtocol) { + case 1: /* ICMP */ + dbg_printf("%sICMPType %u\n", prefix, sample->dcd_dport); + /* not sure about the dest port being icmp type + - might be that src port is icmp type and dest + port is icmp code. Still, have seen some + implementations where src port is 0 and dst + port is the type, so it may be safer to + assume that the destination port has the type */ + break; + case 6: /* TCP */ + dbg_printf("%sTCPSrcPort %u\n", prefix, sample->dcd_sport); + dbg_printf("%sTCPDstPort %u\n", prefix, sample->dcd_dport); + sample->dcd_tcpFlags = ntohl(nfKey6.tcp_flags); + dbg_printf("%sTCPFlags %u\n", prefix, sample->dcd_tcpFlags); + break; + case 17: /* UDP */ + dbg_printf("%sUDPSrcPort %u\n", prefix, sample->dcd_sport); + dbg_printf("%sUDPDstPort %u\n", prefix, sample->dcd_dport); + break; + default: /* some other protcol */ + break; + } + } +} + +/*_________________----------------------------__________________ + _________________ readFlowSample_memcache __________________ + -----------------____________________________------------------ +*/ + +static void readFlowSample_memcache(SFSample *sample) +{ + char key[SFL_MAX_MEMCACHE_KEY+1]; +#define ENC_KEY_BYTES (SFL_MAX_MEMCACHE_KEY * 3) + 1 + dbg_printf("flowSampleType memcache\n"); + sf_log_next32(sample, "memcache_op_protocol"); + sf_log_next32(sample, "memcache_op_cmd"); + if(getString(sample, key, SFL_MAX_MEMCACHE_KEY) > 0) { +#ifdef DEVEL + char enc_key[ENC_KEY_BYTES]; + dbg_printf("memcache_op_key %s\n", URLEncode(key, enc_key, ENC_KEY_BYTES)); +#endif + } + sf_log_next32(sample, "memcache_op_nkeys"); + sf_log_next32(sample, "memcache_op_value_bytes"); + sf_log_next32(sample, "memcache_op_duration_uS"); + sf_log_next32(sample, "memcache_op_status"); +} + +/*_________________----------------------------__________________ + _________________ readFlowSample_http __________________ + -----------------____________________________------------------ +*/ + +/* absorb compiler warning about strftime printing */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + +static void readFlowSample_http(SFSample *sample, uint32_t tag) +{ + char uri[SFL_MAX_HTTP_URI+1]; + char host[SFL_MAX_HTTP_HOST+1]; + char referrer[SFL_MAX_HTTP_REFERRER+1]; + char useragent[SFL_MAX_HTTP_USERAGENT+1]; + char xff[SFL_MAX_HTTP_XFF+1]; + char authuser[SFL_MAX_HTTP_AUTHUSER+1]; + char mimetype[SFL_MAX_HTTP_MIMETYPE+1]; + uint32_t method; + uint32_t protocol; + uint32_t status; + uint64_t req_bytes; + uint64_t resp_bytes; + + dbg_printf("flowSampleType http\n"); + method = sf_log_next32(sample, "http_method"); + protocol = sf_log_next32(sample, "http_protocol"); + if(getString(sample, uri, SFL_MAX_HTTP_URI) > 0) { + dbg_printf("http_uri %s\n", uri); + } + if(getString(sample, host, SFL_MAX_HTTP_HOST) > 0) { + dbg_printf("http_host %s\n", host); + } + if(getString(sample, referrer, SFL_MAX_HTTP_REFERRER) > 0) { + dbg_printf("http_referrer %s\n", referrer); + } + if(getString(sample, useragent, SFL_MAX_HTTP_USERAGENT) > 0) { + dbg_printf("http_useragent %s\n", useragent); + } + if(tag == SFLFLOW_HTTP2) { + if(getString(sample, xff, SFL_MAX_HTTP_XFF) > 0) { + dbg_printf("http_xff %s\n", xff); + } + } + if(getString(sample, authuser, SFL_MAX_HTTP_AUTHUSER) > 0) { + dbg_printf("http_authuser %s\n", authuser); + } + if(getString(sample, mimetype, SFL_MAX_HTTP_MIMETYPE) > 0) { + dbg_printf("http_mimetype %s\n", mimetype); + } + if(tag == SFLFLOW_HTTP2) { + req_bytes = sf_log_next64(sample, "http_request_bytes"); + } + resp_bytes = sf_log_next64(sample, "http_bytes"); + sf_log_next32(sample, "http_duration_uS"); + status = sf_log_next32(sample, "http_status"); + +// XXX +#ifdef DEVEL + { + static const char *SFHTTP_method_names[] = { "-", "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT" }; + + time_t now = time(NULL); + char nowstr[200]; + strftime(nowstr, 200, "%d/%b/%Y:%H:%M:%S %z", localtime(&now)); /* there seems to be no simple portable equivalent to %z */ + /* should really be: snprintf(sfCLF.http_log, SFLFMT_CLF_MAX_LINE,...) but snprintf() is not always available */ + printf("- %s [%s] \"%s %s HTTP/%u.%u\" %u %llu \"%s\" \"%s\"", + authuser[0] ? authuser : "-", + nowstr, + SFHTTP_method_names[method], + uri[0] ? uri : "-", + protocol / 1000, + protocol % 1000, + status, + resp_bytes, + referrer[0] ? referrer : "-", + useragent[0] ? useragent : "-"); + } +#endif +} + +#pragma GCC diagnostic pop + +/*_________________----------------------------__________________ + _________________ readFlowSample_APP __________________ + -----------------____________________________------------------ +*/ + +static void readFlowSample_APP(SFSample *sample) +{ + char application[SFLAPP_MAX_APPLICATION_LEN]; + char operation[SFLAPP_MAX_OPERATION_LEN]; + char attributes[SFLAPP_MAX_ATTRIBUTES_LEN]; + char status[SFLAPP_MAX_STATUS_LEN]; + uint32_t status32; + + dbg_printf("flowSampleType applicationOperation\n"); + + if(getString(sample, application, SFLAPP_MAX_APPLICATION_LEN) > 0) { + dbg_printf("application %s\n", application); + } + if(getString(sample, operation, SFLAPP_MAX_OPERATION_LEN) > 0) { + dbg_printf("operation %s\n", operation); + } + if(getString(sample, attributes, SFLAPP_MAX_ATTRIBUTES_LEN) > 0) { + dbg_printf("attributes %s\n", attributes); + } + if(getString(sample, status, SFLAPP_MAX_STATUS_LEN) > 0) { + dbg_printf("status_descr %s\n", status); + } + sf_log_next64(sample, "request_bytes"); + sf_log_next64(sample, "response_bytes"); + sf_log_next32(sample, "duration_uS"); + status32 = getData32(sample); + if(status32 >= SFLAPP_NUM_STATUS_CODES) + dbg_printf("status \n", status32); + else + dbg_printf("status %s\n", SFL_APP_STATUS_names[status32]); +} + + +/*_________________----------------------------__________________ + _________________ readFlowSample_APP_CTXT __________________ + -----------------____________________________------------------ +*/ + +static void readFlowSample_APP_CTXT(SFSample *sample) +{ + char application[SFLAPP_MAX_APPLICATION_LEN]; + char operation[SFLAPP_MAX_OPERATION_LEN]; + char attributes[SFLAPP_MAX_ATTRIBUTES_LEN]; + if(getString(sample, application, SFLAPP_MAX_APPLICATION_LEN) > 0) { + dbg_printf("server_context_application %s\n", application); + } + if(getString(sample, operation, SFLAPP_MAX_OPERATION_LEN) > 0) { + dbg_printf("server_context_operation %s\n", operation); + } + if(getString(sample, attributes, SFLAPP_MAX_ATTRIBUTES_LEN) > 0) { + dbg_printf("server_context_attributes %s\n", attributes); + } +} + +/*_________________---------------------------------__________________ + _________________ readFlowSample_APP_ACTOR_INIT __________________ + -----------------_________________________________------------------ +*/ + +static void readFlowSample_APP_ACTOR_INIT(SFSample *sample) +{ + char actor[SFLAPP_MAX_ACTOR_LEN]; + if(getString(sample, actor, SFLAPP_MAX_ACTOR_LEN) > 0) { + dbg_printf("actor_initiator %s\n", actor); + } +} + +/*_________________---------------------------------__________________ + _________________ readFlowSample_APP_ACTOR_TGT __________________ + -----------------_________________________________------------------ +*/ + +static void readFlowSample_APP_ACTOR_TGT(SFSample *sample) +{ + char actor[SFLAPP_MAX_ACTOR_LEN]; + if(getString(sample, actor, SFLAPP_MAX_ACTOR_LEN) > 0) { + dbg_printf("actor_target %s\n", actor); + } +} + +/*_________________----------------------------__________________ + _________________ readExtendedSocket4 __________________ + -----------------____________________________------------------ +*/ + +static void readExtendedSocket4(SFSample *sample) +{ +#ifdef DEVEL + char buf[51]; +#endif + dbg_printf("extendedType socket4\n"); + sf_log_next32(sample, "socket4_ip_protocol"); + sample->ipsrc.type = SFLADDRESSTYPE_IP_V4; + sample->ipsrc.address.ip_v4.addr = getData32_nobswap(sample); + sample->ipdst.type = SFLADDRESSTYPE_IP_V4; + sample->ipdst.address.ip_v4.addr = getData32_nobswap(sample); + dbg_printf("socket4_local_ip %s\n", printAddress(&sample->ipsrc, buf, 50)); + dbg_printf("socket4_remote_ip %s\n", printAddress(&sample->ipdst, buf, 50)); + sf_log_next32(sample, "socket4_local_port"); + sf_log_next32(sample, "socket4_remote_port"); + +} + +/*_________________----------------------------__________________ + _________________ readExtendedProxySocket4 __________________ + -----------------____________________________------------------ +*/ + +static void readExtendedProxySocket4(SFSample *sample) +{ +#ifdef DEVEL + char buf[51]; +#endif + SFLAddress ipsrc,ipdst; + dbg_printf("extendedType proxy_socket4\n"); + sf_log_next32(sample, "proxy_socket4_ip_protocol"); + ipsrc.type = SFLADDRESSTYPE_IP_V4; + ipsrc.address.ip_v4.addr = getData32_nobswap(sample); + ipdst.type = SFLADDRESSTYPE_IP_V4; + ipdst.address.ip_v4.addr = getData32_nobswap(sample); + dbg_printf("proxy_socket4_local_ip %s\n", printAddress(&ipsrc, buf, 50)); + dbg_printf("proxy_socket4_remote_ip %s\n", printAddress(&ipdst, buf, 50)); + sf_log_next32(sample, "proxy_socket4_local_port"); + sf_log_next32(sample, "proxy_socket4_remote_port"); +} + +/*_________________----------------------------__________________ + _________________ readExtendedSocket6 __________________ + -----------------____________________________------------------ +*/ + +static void readExtendedSocket6(SFSample *sample) +{ +#ifdef DEVEL + char buf[51]; +#endif + dbg_printf("extendedType socket6\n"); + sf_log_next32(sample, "socket6_ip_protocol"); + sample->ipsrc.type = SFLADDRESSTYPE_IP_V6; + memcpy(&sample->ipsrc.address.ip_v6, sample->datap, 16); + skipBytes(sample, 16); + sample->ipdst.type = SFLADDRESSTYPE_IP_V6; + memcpy(&sample->ipdst.address.ip_v6, sample->datap, 16); + skipBytes(sample, 16); + dbg_printf("socket6_local_ip %s\n", printAddress(&sample->ipsrc, buf, 50)); + dbg_printf("socket6_remote_ip %s\n", printAddress(&sample->ipdst, buf, 50)); + sf_log_next32(sample, "socket6_local_port"); + sf_log_next32(sample, "socket6_remote_port"); + +} + +/*_________________----------------------------__________________ + _________________ readExtendedProxySocket6 __________________ + -----------------____________________________------------------ +*/ + +static void readExtendedProxySocket6(SFSample *sample) +{ +#ifdef DEVEL + char buf[51]; +#endif + SFLAddress ipsrc, ipdst; + dbg_printf("extendedType proxy_socket6\n"); + sf_log_next32(sample, "proxy_socket6_ip_protocol"); + ipsrc.type = SFLADDRESSTYPE_IP_V6; + memcpy(&ipsrc.address.ip_v6, sample->datap, 16); + skipBytes(sample, 16); + ipdst.type = SFLADDRESSTYPE_IP_V6; + memcpy(&ipdst.address.ip_v6, sample->datap, 16); + skipBytes(sample, 16); + dbg_printf("proxy_socket6_local_ip %s\n", printAddress(&ipsrc, buf, 50)); + dbg_printf("proxy_socket6_remote_ip %s\n", printAddress(&ipdst, buf, 50)); + sf_log_next32(sample, "proxy_socket6_local_port"); + sf_log_next32(sample, "proxy_socket6_remote_port"); +} + +/*_________________----------------------------__________________ + _________________ readExtendedDecap __________________ + -----------------____________________________------------------ +*/ + +static void readExtendedDecap(SFSample *sample, char *prefix) +{ +#ifdef DEVEL + uint32_t offset = getData32(sample); + dbg_printf("extendedType %sdecap\n", prefix); + dbg_printf("%sdecap_inner_header_offset %u\n", prefix, offset); +#endif +} + +/*_________________----------------------------__________________ + _________________ readExtendedVNI __________________ + -----------------____________________________------------------ +*/ + +static void readExtendedVNI(SFSample *sample, char *prefix) +{ +#ifdef DEVEL + uint32_t vni = getData32(sample); + dbg_printf("extendedType %sVNI\n", prefix); + dbg_printf("%sVNI %u\n", prefix, vni); +#endif +} + +/*_________________----------------------------__________________ + _________________ readExtendedTCPInfo __________________ + -----------------____________________________------------------ +*/ + +static void readExtendedTCPInfo(SFSample *sample) +{ + char *direction; + EnumPktDirection dirn = getData32(sample); + switch(dirn) { + case PKTDIR_unknown: direction = "unknown"; break; + case PKTDIR_received: direction = "received"; break; + case PKTDIR_sent: direction = "sent"; break; + default: direction = ""; break; + } + dbg_printf( "tcpinfo_direction %s\n", direction); + sf_log_next32(sample, "tcpinfo_send_mss"); + sf_log_next32(sample, "tcpinfo_receive_mss"); + sf_log_next32(sample, "tcpinfo_unacked_pkts"); + sf_log_next32(sample, "tcpinfo_lost_pkts"); + sf_log_next32(sample, "tcpinfo_retrans_pkts"); + sf_log_next32(sample, "tcpinfo_path_mtu"); + sf_log_next32(sample, "tcpinfo_rtt_uS"); + sf_log_next32(sample, "tcpinfo_rtt_uS_var"); + sf_log_next32(sample, "tcpinfo_send_congestion_win"); + sf_log_next32(sample, "tcpinfo_reordering"); + sf_log_next32(sample, "tcpinfo_rtt_uS_min"); +} + +/*_________________---------------------------__________________ + _________________ readFlowSample_v2v4 __________________ + -----------------___________________________------------------ +*/ + +static void readFlowSample_v2v4(SFSample *sample, FlowSource_t *fs) +{ + dbg_printf("sampleType FLOWSAMPLE\n"); + + sample->samplesGenerated = getData32(sample); + dbg_printf("sampleSequenceNo %u\n", sample->samplesGenerated); + { + uint32_t samplerId = getData32(sample); + sample->ds_class = samplerId >> 24; + sample->ds_index = samplerId & 0x00ffffff; + dbg_printf("sourceId %u:%u\n", sample->ds_class, sample->ds_index); + } + + sample->meanSkipCount = getData32(sample); + sample->samplePool = getData32(sample); + sample->dropEvents = getData32(sample); + sample->inputPort = getData32(sample); + sample->outputPort = getData32(sample); + dbg_printf("meanSkipCount %u\n", sample->meanSkipCount); + dbg_printf("samplePool %u\n", sample->samplePool); + dbg_printf("dropEvents %u\n", sample->dropEvents); + dbg_printf("inputPort %u\n", sample->inputPort); + if(sample->outputPort & 0x80000000) { + uint32_t numOutputs = sample->outputPort & 0x7fffffff; + if(numOutputs > 0) dbg_printf("outputPort multiple %d\n", numOutputs); + else dbg_printf("outputPort multiple >1\n"); + } + else dbg_printf("outputPort %u\n", sample->outputPort); + + sample->packet_data_tag = getData32(sample); + + switch(sample->packet_data_tag) { + + case INMPACKETTYPE_HEADER: readFlowSample_header(sample); break; + case INMPACKETTYPE_IPV4: + sample->gotIPV4Struct = YES; + readFlowSample_IPv4(sample, ""); + break; + case INMPACKETTYPE_IPV6: + sample->gotIPV6Struct = YES; + readFlowSample_IPv6(sample, ""); + break; + default: receiveError(sample, "unexpected packet_data_tag", YES); break; + } + + sample->extended_data_tag = 0; + { + uint32_t x; + sample->num_extended = getData32(sample); + for(x = 0; x < sample->num_extended; x++) { + uint32_t extended_tag; + extended_tag = getData32(sample); + switch(extended_tag) { + case INMEXTENDED_SWITCH: readExtendedSwitch(sample); break; + case INMEXTENDED_ROUTER: readExtendedRouter(sample); break; + case INMEXTENDED_GATEWAY: + if(sample->datagramVersion == 2) readExtendedGateway_v2(sample); + else readExtendedGateway(sample); + break; + case INMEXTENDED_USER: readExtendedUser(sample); break; + case INMEXTENDED_URL: readExtendedUrl(sample); break; + default: receiveError(sample, "unrecognized extended data tag", YES); break; + } + } + } + + if(sample->gotIPV4 || sample->gotIPV6) + StoreSflowRecord(sample, fs); + + if ( verbose ) + writeFlowLine(sample); + +} + +/*_________________---------------------------__________________ + _________________ readFlowSample __________________ + -----------------___________________________------------------ +*/ + +static void readFlowSample(SFSample *sample, int expanded, FlowSource_t *fs) +{ + uint32_t num_elements, sampleLength; + uint8_t *sampleStart; + + dbg_printf("sampleType FLOWSAMPLE\n"); + sampleLength = getData32(sample); + sampleStart = (uint8_t *)sample->datap; + sample->samplesGenerated = getData32(sample); + dbg_printf("sampleSequenceNo %u\n", sample->samplesGenerated); + if(expanded) { + sample->ds_class = getData32(sample); + sample->ds_index = getData32(sample); + } + else { + uint32_t samplerId = getData32(sample); + sample->ds_class = samplerId >> 24; + sample->ds_index = samplerId & 0x00ffffff; + } + dbg_printf("sourceId %u:%u\n", sample->ds_class, sample->ds_index); + + sample->meanSkipCount = getData32(sample); + sample->samplePool = getData32(sample); + sample->dropEvents = getData32(sample); + dbg_printf("meanSkipCount %u\n", sample->meanSkipCount); + dbg_printf("samplePool %u\n", sample->samplePool); + dbg_printf("dropEvents %u\n", sample->dropEvents); + if(expanded) { + sample->inputPortFormat = getData32(sample); + sample->inputPort = getData32(sample); + sample->outputPortFormat = getData32(sample); + sample->outputPort = getData32(sample); + } + else { + uint32_t inp, outp; + inp = getData32(sample); + outp = getData32(sample); + sample->inputPortFormat = inp >> 30; + sample->outputPortFormat = outp >> 30; + sample->inputPort = inp & 0x3fffffff; + sample->outputPort = outp & 0x3fffffff; + } + + switch(sample->inputPortFormat) { + case 3: dbg_printf("inputPort format==3 %u\n", sample->inputPort); break; + case 2: dbg_printf("inputPort multiple %u\n", sample->inputPort); break; + case 1: dbg_printf("inputPort dropCode %u\n", sample->inputPort); break; + case 0: dbg_printf("inputPort %u\n", sample->inputPort); break; + } + + switch(sample->outputPortFormat) { + case 3: dbg_printf("outputPort format==3 %u\n", sample->outputPort); break; + case 2: dbg_printf("outputPort multiple %u\n", sample->outputPort); break; + case 1: dbg_printf("outputPort dropCode %u\n", sample->outputPort); break; + case 0: dbg_printf("outputPort %u\n", sample->outputPort); break; + } + + num_elements = getData32(sample); + { + uint32_t el; + for(el = 0; el < num_elements; el++) { + uint32_t tag, length; + uint8_t *start; +#ifdef DEVEL + char buf[51]; +#endif + tag = sample->elementType = getData32(sample); + dbg_printf("flowBlock_tag %s\n", printTag(tag, buf, 50)); + length = getData32(sample); + start = (uint8_t *)sample->datap; + + switch(tag) { + case SFLFLOW_HEADER: readFlowSample_header(sample); break; + case SFLFLOW_ETHERNET: readFlowSample_ethernet(sample, ""); break; + case SFLFLOW_IPV4: readFlowSample_IPv4(sample, ""); break; + case SFLFLOW_IPV6: readFlowSample_IPv6(sample, ""); break; + case SFLFLOW_MEMCACHE: readFlowSample_memcache(sample); break; + case SFLFLOW_HTTP: readFlowSample_http(sample, tag); break; + case SFLFLOW_HTTP2: readFlowSample_http(sample, tag); break; + case SFLFLOW_APP: readFlowSample_APP(sample); break; + case SFLFLOW_APP_CTXT: readFlowSample_APP_CTXT(sample); break; + case SFLFLOW_APP_ACTOR_INIT: readFlowSample_APP_ACTOR_INIT(sample); break; + case SFLFLOW_APP_ACTOR_TGT: readFlowSample_APP_ACTOR_TGT(sample); break; + case SFLFLOW_EX_SWITCH: readExtendedSwitch(sample); break; + case SFLFLOW_EX_ROUTER: readExtendedRouter(sample); break; + case SFLFLOW_EX_GATEWAY: readExtendedGateway(sample); break; + case SFLFLOW_EX_USER: readExtendedUser(sample); break; + case SFLFLOW_EX_URL: readExtendedUrl(sample); break; + case SFLFLOW_EX_MPLS: readExtendedMpls(sample); break; + case SFLFLOW_EX_NAT: readExtendedNat(sample); break; + case SFLFLOW_EX_NAT_PORT: readExtendedNatPort(sample); break; + case SFLFLOW_EX_MPLS_TUNNEL: readExtendedMplsTunnel(sample); break; + case SFLFLOW_EX_MPLS_VC: readExtendedMplsVC(sample); break; + case SFLFLOW_EX_MPLS_FTN: readExtendedMplsFTN(sample); break; + case SFLFLOW_EX_MPLS_LDP_FEC: readExtendedMplsLDP_FEC(sample); break; + case SFLFLOW_EX_VLAN_TUNNEL: readExtendedVlanTunnel(sample); break; + case SFLFLOW_EX_80211_PAYLOAD: readExtendedWifiPayload(sample); break; + case SFLFLOW_EX_80211_RX: readExtendedWifiRx(sample); break; + case SFLFLOW_EX_80211_TX: readExtendedWifiTx(sample); break; + /* case SFLFLOW_EX_AGGREGATION: readExtendedAggregation(sample); break; */ + case SFLFLOW_EX_SOCKET4: readExtendedSocket4(sample); break; + case SFLFLOW_EX_SOCKET6: readExtendedSocket6(sample); break; + case SFLFLOW_EX_PROXYSOCKET4: readExtendedProxySocket4(sample); break; + case SFLFLOW_EX_PROXYSOCKET6: readExtendedProxySocket6(sample); break; + case SFLFLOW_EX_L2_TUNNEL_OUT: readFlowSample_ethernet(sample, "tunnel_l2_out_"); break; + case SFLFLOW_EX_L2_TUNNEL_IN: readFlowSample_ethernet(sample, "tunnel_l2_in_"); break; + case SFLFLOW_EX_IPV4_TUNNEL_OUT: readFlowSample_IPv4(sample, "tunnel_ipv4_out_"); break; + case SFLFLOW_EX_IPV4_TUNNEL_IN: readFlowSample_IPv4(sample, "tunnel_ipv4_in_"); break; + case SFLFLOW_EX_IPV6_TUNNEL_OUT: readFlowSample_IPv6(sample, "tunnel_ipv6_out_"); break; + case SFLFLOW_EX_IPV6_TUNNEL_IN: readFlowSample_IPv6(sample, "tunnel_ipv6_in_"); break; + case SFLFLOW_EX_DECAP_OUT: readExtendedDecap(sample, "out_"); break; + case SFLFLOW_EX_DECAP_IN: readExtendedDecap(sample, "in_"); break; + case SFLFLOW_EX_VNI_OUT: readExtendedVNI(sample, "out_"); break; + case SFLFLOW_EX_VNI_IN: readExtendedVNI(sample, "in_"); break; + case SFLFLOW_EX_TCP_INFO: readExtendedTCPInfo(sample); break; + default: skipTLVRecord(sample, tag, length, "flow_sample_element"); break; + } + lengthCheck(sample, "flow_sample_element", start, length); + } + } + lengthCheck(sample, "flow_sample", sampleStart, sampleLength); + + if ( sample->gotIPV4 || sample->gotIPV6 ) + StoreSflowRecord(sample, fs); + + /* or line-by-line output... */ + if ( verbose ) + writeFlowLine(sample); + +} + +/*_________________---------------------------__________________ + _________________ readCounters_generic __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_generic(SFSample *sample) +{ + /* the first part of the generic counters block is really just more info about the interface. */ + sample->ifCounters.ifIndex = sf_log_next32(sample, "ifIndex"); + sample->ifCounters.ifType = sf_log_next32(sample, "networkType"); + sample->ifCounters.ifSpeed = sf_log_next64(sample, "ifSpeed"); + sample->ifCounters.ifDirection = sf_log_next32(sample, "ifDirection"); + sample->ifCounters.ifStatus = sf_log_next32(sample, "ifStatus"); + /* the generic counters always come first */ + sample->ifCounters.ifInOctets = sf_log_next64(sample, "ifInOctets"); + sample->ifCounters.ifInUcastPkts = sf_log_next32(sample, "ifInUcastPkts"); + sample->ifCounters.ifInMulticastPkts = sf_log_next32(sample, "ifInMulticastPkts"); + sample->ifCounters.ifInBroadcastPkts = sf_log_next32(sample, "ifInBroadcastPkts"); + sample->ifCounters.ifInDiscards = sf_log_next32(sample, "ifInDiscards"); + sample->ifCounters.ifInErrors = sf_log_next32(sample, "ifInErrors"); + sample->ifCounters.ifInUnknownProtos = sf_log_next32(sample, "ifInUnknownProtos"); + sample->ifCounters.ifOutOctets = sf_log_next64(sample, "ifOutOctets"); + sample->ifCounters.ifOutUcastPkts = sf_log_next32(sample, "ifOutUcastPkts"); + sample->ifCounters.ifOutMulticastPkts = sf_log_next32(sample, "ifOutMulticastPkts"); + sample->ifCounters.ifOutBroadcastPkts = sf_log_next32(sample, "ifOutBroadcastPkts"); + sample->ifCounters.ifOutDiscards = sf_log_next32(sample, "ifOutDiscards"); + sample->ifCounters.ifOutErrors = sf_log_next32(sample, "ifOutErrors"); + sample->ifCounters.ifPromiscuousMode = sf_log_next32(sample, "ifPromiscuousMode"); +} + +/*_________________---------------------------__________________ + _________________ readCounters_ethernet __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_ethernet(SFSample *sample) +{ + sf_log_next32(sample, "dot3StatsAlignmentErrors"); + sf_log_next32(sample, "dot3StatsFCSErrors"); + sf_log_next32(sample, "dot3StatsSingleCollisionFrames"); + sf_log_next32(sample, "dot3StatsMultipleCollisionFrames"); + sf_log_next32(sample, "dot3StatsSQETestErrors"); + sf_log_next32(sample, "dot3StatsDeferredTransmissions"); + sf_log_next32(sample, "dot3StatsLateCollisions"); + sf_log_next32(sample, "dot3StatsExcessiveCollisions"); + sf_log_next32(sample, "dot3StatsInternalMacTransmitErrors"); + sf_log_next32(sample, "dot3StatsCarrierSenseErrors"); + sf_log_next32(sample, "dot3StatsFrameTooLongs"); + sf_log_next32(sample, "dot3StatsInternalMacReceiveErrors"); + sf_log_next32(sample, "dot3StatsSymbolErrors"); +} + + +/*_________________---------------------------__________________ + _________________ readCounters_tokenring __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_tokenring(SFSample *sample) +{ + sf_log_next32(sample, "dot5StatsLineErrors"); + sf_log_next32(sample, "dot5StatsBurstErrors"); + sf_log_next32(sample, "dot5StatsACErrors"); + sf_log_next32(sample, "dot5StatsAbortTransErrors"); + sf_log_next32(sample, "dot5StatsInternalErrors"); + sf_log_next32(sample, "dot5StatsLostFrameErrors"); + sf_log_next32(sample, "dot5StatsReceiveCongestions"); + sf_log_next32(sample, "dot5StatsFrameCopiedErrors"); + sf_log_next32(sample, "dot5StatsTokenErrors"); + sf_log_next32(sample, "dot5StatsSoftErrors"); + sf_log_next32(sample, "dot5StatsHardErrors"); + sf_log_next32(sample, "dot5StatsSignalLoss"); + sf_log_next32(sample, "dot5StatsTransmitBeacons"); + sf_log_next32(sample, "dot5StatsRecoverys"); + sf_log_next32(sample, "dot5StatsLobeWires"); + sf_log_next32(sample, "dot5StatsRemoves"); + sf_log_next32(sample, "dot5StatsSingles"); + sf_log_next32(sample, "dot5StatsFreqErrors"); +} + + +/*_________________---------------------------__________________ + _________________ readCounters_vg __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_vg(SFSample *sample) +{ + sf_log_next32(sample, "dot12InHighPriorityFrames"); + sf_log_next64(sample, "dot12InHighPriorityOctets"); + sf_log_next32(sample, "dot12InNormPriorityFrames"); + sf_log_next64(sample, "dot12InNormPriorityOctets"); + sf_log_next32(sample, "dot12InIPMErrors"); + sf_log_next32(sample, "dot12InOversizeFrameErrors"); + sf_log_next32(sample, "dot12InDataErrors"); + sf_log_next32(sample, "dot12InNullAddressedFrames"); + sf_log_next32(sample, "dot12OutHighPriorityFrames"); + sf_log_next64(sample, "dot12OutHighPriorityOctets"); + sf_log_next32(sample, "dot12TransitionIntoTrainings"); + sf_log_next64(sample, "dot12HCInHighPriorityOctets"); + sf_log_next64(sample, "dot12HCInNormPriorityOctets"); + sf_log_next64(sample, "dot12HCOutHighPriorityOctets"); +} + + + +/*_________________---------------------------__________________ + _________________ readCounters_vlan __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_vlan(SFSample *sample) +{ + sample->in_vlan = getData32(sample); + dbg_printf("in_vlan %u\n", sample->in_vlan); + sf_log_next64(sample, "octets"); + sf_log_next32(sample, "ucastPkts"); + sf_log_next32(sample, "multicastPkts"); + sf_log_next32(sample, "broadcastPkts"); + sf_log_next32(sample, "discards"); +} + +/*_________________---------------------------__________________ + _________________ readCounters_80211 __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_80211(SFSample *sample) +{ + sf_log_next32(sample, "dot11TransmittedFragmentCount"); + sf_log_next32(sample, "dot11MulticastTransmittedFrameCount"); + sf_log_next32(sample, "dot11FailedCount"); + sf_log_next32(sample, "dot11RetryCount"); + sf_log_next32(sample, "dot11MultipleRetryCount"); + sf_log_next32(sample, "dot11FrameDuplicateCount"); + sf_log_next32(sample, "dot11RTSSuccessCount"); + sf_log_next32(sample, "dot11RTSFailureCount"); + sf_log_next32(sample, "dot11ACKFailureCount"); + sf_log_next32(sample, "dot11ReceivedFragmentCount"); + sf_log_next32(sample, "dot11MulticastReceivedFrameCount"); + sf_log_next32(sample, "dot11FCSErrorCount"); + sf_log_next32(sample, "dot11TransmittedFrameCount"); + sf_log_next32(sample, "dot11WEPUndecryptableCount"); + sf_log_next32(sample, "dot11QoSDiscardedFragmentCount"); + sf_log_next32(sample, "dot11AssociatedStationCount"); + sf_log_next32(sample, "dot11QoSCFPollsReceivedCount"); + sf_log_next32(sample, "dot11QoSCFPollsUnusedCount"); + sf_log_next32(sample, "dot11QoSCFPollsUnusableCount"); + sf_log_next32(sample, "dot11QoSCFPollsLostCount"); +} + +/*_________________---------------------------__________________ + _________________ readCounters_processor __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_processor(SFSample *sample) +{ + sf_log_percentage(sample, "5s_cpu"); + sf_log_percentage(sample, "1m_cpu"); + sf_log_percentage(sample, "5m_cpu"); + sf_log_next64(sample, "total_memory_bytes"); + sf_log_next64(sample, "free_memory_bytes"); +} + +/*_________________---------------------------__________________ + _________________ readCounters_radio __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_radio(SFSample *sample) +{ + sf_log_next32(sample, "radio_elapsed_time"); + sf_log_next32(sample, "radio_on_channel_time"); + sf_log_next32(sample, "radio_on_channel_busy_time"); +} + +/*_________________---------------------------__________________ + _________________ readCounters_OFPort __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_OFPort(SFSample *sample) +{ +#ifdef DEVEL + uint64_t dpid = getData64(sample); + dbg_printf( "openflow_datapath_id %llx\n", dpid); +#endif + sf_log_next32(sample, "openflow_port"); +} + +/*_________________---------------------------__________________ + _________________ readCounters_portName __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_portName(SFSample *sample) +{ + char ifname[SFL_MAX_PORTNAME_LEN+1]; + if(getString(sample, ifname, SFL_MAX_PORTNAME_LEN) > 0) { + dbg_printf("ifName %s\n", ifname); + } +} + +/*_________________---------------------------__________________ + _________________ readCounters_OVSDP __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_OVSDP(SFSample *sample) +{ + sf_log_next32(sample, "OVS_dp_hits"); + sf_log_next32(sample, "OVS_dp_misses"); + sf_log_next32(sample, "OVS_dp_lost"); + sf_log_next32(sample, "OVS_dp_mask_hits"); + sf_log_next32(sample, "OVS_dp_flows"); + sf_log_next32(sample, "OVS_dp_masks"); +} + +/*_________________---------------------------__________________ + _________________ readCounters_host_hid __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_host_hid(SFSample *sample) +{ + uint8_t *uuid; + char hostname[SFL_MAX_HOSTNAME_LEN+1]; + char os_release[SFL_MAX_OSRELEASE_LEN+1]; + char uuidStr[100]; + if(getString(sample, hostname, SFL_MAX_HOSTNAME_LEN) > 0) { + dbg_printf("hostname %s\n", hostname); + } + uuid = (uint8_t *)sample->datap; + printUUID(uuid, uuidStr, 100); + dbg_printf("UUID %s\n", uuidStr); + skipBytes(sample, 16); + sf_log_next32(sample, "machine_type"); + sf_log_next32(sample, "os_name"); + if(getString(sample, os_release, SFL_MAX_OSRELEASE_LEN) > 0) { + dbg_printf("os_release %s\n", os_release); + } +} + +/*_________________---------------------------__________________ + _________________ readCounters_adaptors __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_adaptors(SFSample *sample) +{ + uint8_t *mac; + uint32_t i, j, ifindex, num_macs, num_adaptors = getData32(sample); + for(i = 0; i < num_adaptors; i++) { + ifindex = getData32(sample); + dbg_printf("adaptor_%u_ifIndex %u\n", i, ifindex); + num_macs = getData32(sample); + dbg_printf("adaptor_%u_MACs %u\n", i, num_macs); + for(j = 0; j < num_macs; j++) { + mac = (uint8_t *)sample->datap; + dbg_printf("adaptor_%u_MAC_%u %02x%02x%02x%02x%02x%02x\n", + i, j, + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + skipBytes(sample, 8); + } + } +} + + +/*_________________----------------------------__________________ + _________________ readCounters_host_parent __________________ + -----------------____________________________------------------ +*/ + +static void readCounters_host_parent(SFSample *sample) +{ + sf_log_next32(sample, "parent_dsClass"); + sf_log_next32(sample, "parent_dsIndex"); +} + +/*_________________---------------------------__________________ + _________________ readCounters_host_cpu __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_host_cpu(SFSample *sample, uint32_t length) +{ + sf_log_nextFloat(sample, "cpu_load_one"); + sf_log_nextFloat(sample, "cpu_load_five"); + sf_log_nextFloat(sample, "cpu_load_fifteen"); + sf_log_next32(sample, "cpu_proc_run"); + sf_log_next32(sample, "cpu_proc_total"); + sf_log_next32(sample, "cpu_num"); + sf_log_next32(sample, "cpu_speed"); + sf_log_next32(sample, "cpu_uptime"); + sf_log_next32(sample, "cpu_user"); + sf_log_next32(sample, "cpu_nice"); + sf_log_next32(sample, "cpu_system"); + sf_log_next32(sample, "cpu_idle"); + sf_log_next32(sample, "cpu_wio"); + sf_log_next32(sample, "cpuintr"); + sf_log_next32(sample, "cpu_sintr"); + sf_log_next32(sample, "cpuinterrupts"); + sf_log_next32(sample, "cpu_contexts"); + if(length > 68) { + /* these three fields were added in December 2014 */ + sf_log_next32(sample, "cpu_steal"); + sf_log_next32(sample, "cpu_guest"); + sf_log_next32(sample, "cpu_guest_nice"); + } +} + +/*_________________---------------------------__________________ + _________________ readCounters_host_mem __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_host_mem(SFSample *sample) +{ + sf_log_next64(sample, "mem_total"); + sf_log_next64(sample, "mem_free"); + sf_log_next64(sample, "mem_shared"); + sf_log_next64(sample, "mem_buffers"); + sf_log_next64(sample, "mem_cached"); + sf_log_next64(sample, "swap_total"); + sf_log_next64(sample, "swap_free"); + sf_log_next32(sample, "page_in"); + sf_log_next32(sample, "page_out"); + sf_log_next32(sample, "swap_in"); + sf_log_next32(sample, "swap_out"); +} + + +/*_________________---------------------------__________________ + _________________ readCounters_host_dsk __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_host_dsk(SFSample *sample) +{ + sf_log_next64(sample, "disk_total"); + sf_log_next64(sample, "disk_free"); + sf_log_percentage(sample, "disk_partition_max_used"); + sf_log_next32(sample, "disk_reads"); + sf_log_next64(sample, "disk_bytes_read"); + sf_log_next32(sample, "disk_read_time"); + sf_log_next32(sample, "disk_writes"); + sf_log_next64(sample, "disk_bytes_written"); + sf_log_next32(sample, "disk_write_time"); +} + +/*_________________---------------------------__________________ + _________________ readCounters_host_nio __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_host_nio(SFSample *sample) +{ + sf_log_next64(sample, "nio_bytes_in"); + sf_log_next32(sample, "nio_pkts_in"); + sf_log_next32(sample, "nio_errs_in"); + sf_log_next32(sample, "nio_drops_in"); + sf_log_next64(sample, "nio_bytes_out"); + sf_log_next32(sample, "nio_pkts_out"); + sf_log_next32(sample, "nio_errs_out"); + sf_log_next32(sample, "nio_drops_out"); +} + +/*_________________---------------------------__________________ + _________________ readCounters_host_ip __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_host_ip(SFSample *sample) +{ + sf_log_next32(sample, "ipForwarding"); + sf_log_next32(sample, "ipDefaultTTL"); + sf_log_next32(sample, "ipInReceives"); + sf_log_next32(sample, "ipInHdrErrors"); + sf_log_next32(sample, "ipInAddrErrors"); + sf_log_next32(sample, "ipForwDatagrams"); + sf_log_next32(sample, "ipInUnknownProtos"); + sf_log_next32(sample, "ipInDiscards"); + sf_log_next32(sample, "ipInDelivers"); + sf_log_next32(sample, "ipOutRequests"); + sf_log_next32(sample, "ipOutDiscards"); + sf_log_next32(sample, "ipOutNoRoutes"); + sf_log_next32(sample, "ipReasmTimeout"); + sf_log_next32(sample, "ipReasmReqds"); + sf_log_next32(sample, "ipReasmOKs"); + sf_log_next32(sample, "ipReasmFails"); + sf_log_next32(sample, "ipFragOKs"); + sf_log_next32(sample, "ipFragFails"); + sf_log_next32(sample, "ipFragCreates"); +} + +/*_________________---------------------------__________________ + _________________ readCounters_host_icmp __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_host_icmp(SFSample *sample) +{ + sf_log_next32(sample, "icmpInMsgs"); + sf_log_next32(sample, "icmpInErrors"); + sf_log_next32(sample, "icmpInDestUnreachs"); + sf_log_next32(sample, "icmpInTimeExcds"); + sf_log_next32(sample, "icmpInParamProbs"); + sf_log_next32(sample, "icmpInSrcQuenchs"); + sf_log_next32(sample, "icmpInRedirects"); + sf_log_next32(sample, "icmpInEchos"); + sf_log_next32(sample, "icmpInEchoReps"); + sf_log_next32(sample, "icmpInTimestamps"); + sf_log_next32(sample, "icmpInAddrMasks"); + sf_log_next32(sample, "icmpInAddrMaskReps"); + sf_log_next32(sample, "icmpOutMsgs"); + sf_log_next32(sample, "icmpOutErrors"); + sf_log_next32(sample, "icmpOutDestUnreachs"); + sf_log_next32(sample, "icmpOutTimeExcds"); + sf_log_next32(sample, "icmpOutParamProbs"); + sf_log_next32(sample, "icmpOutSrcQuenchs"); + sf_log_next32(sample, "icmpOutRedirects"); + sf_log_next32(sample, "icmpOutEchos"); + sf_log_next32(sample, "icmpOutEchoReps"); + sf_log_next32(sample, "icmpOutTimestamps"); + sf_log_next32(sample, "icmpOutTimestampReps"); + sf_log_next32(sample, "icmpOutAddrMasks"); + sf_log_next32(sample, "icmpOutAddrMaskReps"); +} + +/*_________________---------------------------__________________ + _________________ readCounters_host_tcp __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_host_tcp(SFSample *sample) +{ + sf_log_next32(sample, "tcpRtoAlgorithm"); + sf_log_next32(sample, "tcpRtoMin"); + sf_log_next32(sample, "tcpRtoMax"); + sf_log_next32(sample, "tcpMaxConn"); + sf_log_next32(sample, "tcpActiveOpens"); + sf_log_next32(sample, "tcpPassiveOpens"); + sf_log_next32(sample, "tcpAttemptFails"); + sf_log_next32(sample, "tcpEstabResets"); + sf_log_next32(sample, "tcpCurrEstab"); + sf_log_next32(sample, "tcpInSegs"); + sf_log_next32(sample, "tcpOutSegs"); + sf_log_next32(sample, "tcpRetransSegs"); + sf_log_next32(sample, "tcpInErrs"); + sf_log_next32(sample, "tcpOutRsts"); + sf_log_next32(sample, "tcpInCsumErrors"); +} + +/*_________________---------------------------__________________ + _________________ readCounters_host_udp __________________ + -----------------___________________________------------------ +*/ + +static void readCounters_host_udp(SFSample *sample) +{ + sf_log_next32(sample, "udpInDatagrams"); + sf_log_next32(sample, "udpNoPorts"); + sf_log_next32(sample, "udpInErrors"); + sf_log_next32(sample, "udpOutDatagrams"); + sf_log_next32(sample, "udpRcvbufErrors"); + sf_log_next32(sample, "udpSndbufErrors"); + sf_log_next32(sample, "udpInCsumErrors"); +} + +/*_________________-----------------------------__________________ + _________________ readCounters_host_vnode __________________ + -----------------_____________________________------------------ +*/ + +static void readCounters_host_vnode(SFSample *sample) +{ + sf_log_next32(sample, "vnode_mhz"); + sf_log_next32(sample, "vnode_cpus"); + sf_log_next64(sample, "vnode_memory"); + sf_log_next64(sample, "vnode_memory_free"); + sf_log_next32(sample, "vnode_num_domains"); +} + +/*_________________----------------------------__________________ + _________________ readCounters_host_vcpu __________________ + -----------------____________________________------------------ +*/ + +static void readCounters_host_vcpu(SFSample *sample) +{ + sf_log_next32(sample, "vcpu_state"); + sf_log_next32(sample, "vcpu_cpu_mS"); + sf_log_next32(sample, "vcpu_cpuCount"); +} + +/*_________________----------------------------__________________ + _________________ readCounters_host_vmem __________________ + -----------------____________________________------------------ +*/ + +static void readCounters_host_vmem(SFSample *sample) +{ + sf_log_next64(sample, "vmem_memory"); + sf_log_next64(sample, "vmem_maxMemory"); +} + +/*_________________----------------------------__________________ + _________________ readCounters_host_vdsk __________________ + -----------------____________________________------------------ +*/ + +static void readCounters_host_vdsk(SFSample *sample) +{ + sf_log_next64(sample, "vdsk_capacity"); + sf_log_next64(sample, "vdsk_allocation"); + sf_log_next64(sample, "vdsk_available"); + sf_log_next32(sample, "vdsk_rd_req"); + sf_log_next64(sample, "vdsk_rd_bytes"); + sf_log_next32(sample, "vdsk_wr_req"); + sf_log_next64(sample, "vdsk_wr_bytes"); + sf_log_next32(sample, "vdsk_errs"); +} + +/*_________________----------------------------__________________ + _________________ readCounters_host_vnio __________________ + -----------------____________________________------------------ +*/ + +static void readCounters_host_vnio(SFSample *sample) +{ + sf_log_next64(sample, "vnio_bytes_in"); + sf_log_next32(sample, "vnio_pkts_in"); + sf_log_next32(sample, "vnio_errs_in"); + sf_log_next32(sample, "vnio_drops_in"); + sf_log_next64(sample, "vnio_bytes_out"); + sf_log_next32(sample, "vnio_pkts_out"); + sf_log_next32(sample, "vnio_errs_out"); + sf_log_next32(sample, "vnio_drops_out"); +} + +/*_________________------------------------------__________________ + _________________ readCounters_host_gpu_nvml __________________ + -----------------______________________________------------------ +*/ + +static void readCounters_host_gpu_nvml(SFSample *sample) +{ + sf_log_next32(sample, "nvml_device_count"); + sf_log_next32(sample, "nvml_processes"); + sf_log_next32(sample, "nvml_gpu_mS"); + sf_log_next32(sample, "nvml_mem_mS"); + sf_log_next64(sample, "nvml_mem_bytes_total"); + sf_log_next64(sample, "nvml_mem_bytes_free"); + sf_log_next32(sample, "nvml_ecc_errors"); + sf_log_next32(sample, "nvml_energy_mJ"); + sf_log_next32(sample, "nvml_temperature_C"); + sf_log_next32(sample, "nvml_fan_speed_pc"); +} + +/*_________________------------------------------__________________ + _________________ readCounters_bcm_tables __________________ + -----------------______________________________------------------ +*/ + +static void readCounters_bcm_tables(SFSample *sample) +{ + sf_log_next32(sample, "bcm_asic_host_entries"); + sf_log_next32(sample, "bcm_host_entries_max"); + sf_log_next32(sample, "bcm_ipv4_entries"); + sf_log_next32(sample, "bcm_ipv4_entries_max"); + sf_log_next32(sample, "bcm_ipv6_entries"); + sf_log_next32(sample, "bcm_ipv6_entries_max"); + sf_log_next32(sample, "bcm_ipv4_ipv6_entries"); + sf_log_next32(sample, "bcm_ipv4_ipv6_entries_max"); + sf_log_next32(sample, "bcm_long_ipv6_entries"); + sf_log_next32(sample, "bcm_long_ipv6_entries_max"); + sf_log_next32(sample, "bcm_total_routes"); + sf_log_next32(sample, "bcm_total_routes_max"); + sf_log_next32(sample, "bcm_ecmp_nexthops"); + sf_log_next32(sample, "bcm_ecmp_nexthops_max"); + sf_log_next32(sample, "bcm_mac_entries"); + sf_log_next32(sample, "bcm_mac_entries_max"); + sf_log_next32(sample, "bcm_ipv4_neighbors"); + sf_log_next32(sample, "bcm_ipv6_neighbors"); + sf_log_next32(sample, "bcm_ipv4_routes"); + sf_log_next32(sample, "bcm_ipv6_routes"); + sf_log_next32(sample, "bcm_acl_ingress_entries"); + sf_log_next32(sample, "bcm_acl_ingress_entries_max"); + sf_log_next32(sample, "bcm_acl_ingress_counters"); + sf_log_next32(sample, "bcm_acl_ingress_counters_max"); + sf_log_next32(sample, "bcm_acl_ingress_meters"); + sf_log_next32(sample, "bcm_acl_ingress_meters_max"); + sf_log_next32(sample, "bcm_acl_ingress_slices"); + sf_log_next32(sample, "bcm_acl_ingress_slices_max"); + sf_log_next32(sample, "bcm_acl_egress_entries"); + sf_log_next32(sample, "bcm_acl_egress_entries_max"); + sf_log_next32(sample, "bcm_acl_egress_counters"); + sf_log_next32(sample, "bcm_acl_egress_counters_max"); + sf_log_next32(sample, "bcm_acl_egress_meters"); + sf_log_next32(sample, "bcm_acl_egress_meters_max"); + sf_log_next32(sample, "bcm_acl_egress_slices"); + sf_log_next32(sample, "bcm_acl_egress_slices_max"); +} + +/*_________________----------------------------__________________ + _________________ readCounters_memcache __________________ + -----------------____________________________------------------ + for structure 2200 (deprecated) +*/ + +static void readCounters_memcache(SFSample *sample) +{ + sf_log_next32(sample, "memcache_uptime"); + sf_log_next32(sample, "memcache_rusage_user"); + sf_log_next32(sample, "memcache_rusage_system"); + sf_log_next32(sample, "memcache_curr_connections"); + sf_log_next32(sample, "memcache_total_connections"); + sf_log_next32(sample, "memcache_connection_structures"); + sf_log_next32(sample, "memcache_cmd_get"); + sf_log_next32(sample, "memcache_cmd_set"); + sf_log_next32(sample, "memcache_cmd_flush"); + sf_log_next32(sample, "memcache_get_hits"); + sf_log_next32(sample, "memcache_get_misses"); + sf_log_next32(sample, "memcache_delete_misses"); + sf_log_next32(sample, "memcache_delete_hits"); + sf_log_next32(sample, "memcache_incr_misses"); + sf_log_next32(sample, "memcache_incr_hits"); + sf_log_next32(sample, "memcache_decr_misses"); + sf_log_next32(sample, "memcache_decr_hits"); + sf_log_next32(sample, "memcache_cas_misses"); + sf_log_next32(sample, "memcache_cas_hits"); + sf_log_next32(sample, "memcache_cas_badval"); + sf_log_next32(sample, "memcache_auth_cmds"); + sf_log_next32(sample, "memcache_auth_errors"); + sf_log_next64(sample, "memcache_bytes_read"); + sf_log_next64(sample, "memcache_bytes_written"); + sf_log_next32(sample, "memcache_limit_maxbytes"); + sf_log_next32(sample, "memcache_accepting_conns"); + sf_log_next32(sample, "memcache_listen_disabled_num"); + sf_log_next32(sample, "memcache_threads"); + sf_log_next32(sample, "memcache_conn_yields"); + sf_log_next64(sample, "memcache_bytes"); + sf_log_next32(sample, "memcache_curr_items"); + sf_log_next32(sample, "memcache_total_items"); + sf_log_next32(sample, "memcache_evictions"); +} + +/*_________________----------------------------__________________ + _________________ readCounters_memcache2 __________________ + -----------------____________________________------------------ + for structure 2204 +*/ + +static void readCounters_memcache2(SFSample *sample) +{ + sf_log_next32(sample, "memcache_cmd_set"); + sf_log_next32(sample, "memcache_cmd_touch"); + sf_log_next32(sample, "memcache_cmd_flush"); + sf_log_next32(sample, "memcache_get_hits"); + sf_log_next32(sample, "memcache_get_misses"); + sf_log_next32(sample, "memcache_delete_hits"); + sf_log_next32(sample, "memcache_delete_misses"); + sf_log_next32(sample, "memcache_incr_hits"); + sf_log_next32(sample, "memcache_incr_misses"); + sf_log_next32(sample, "memcache_decr_hits"); + sf_log_next32(sample, "memcache_decr_misses"); + sf_log_next32(sample, "memcache_cas_hits"); + sf_log_next32(sample, "memcache_cas_misses"); + sf_log_next32(sample, "memcache_cas_badval"); + sf_log_next32(sample, "memcache_auth_cmds"); + sf_log_next32(sample, "memcache_auth_errors"); + sf_log_next32(sample, "memcache_threads"); + sf_log_next32(sample, "memcache_conn_yields"); + sf_log_next32(sample, "memcache_listen_disabled_num"); + sf_log_next32(sample, "memcache_curr_connections"); + sf_log_next32(sample, "memcache_rejected_connections"); + sf_log_next32(sample, "memcache_total_connections"); + sf_log_next32(sample, "memcache_connection_structures"); + sf_log_next32(sample, "memcache_evictions"); + sf_log_next32(sample, "memcache_reclaimed"); + sf_log_next32(sample, "memcache_curr_items"); + sf_log_next32(sample, "memcache_total_items"); + sf_log_next64(sample, "memcache_bytes_read"); + sf_log_next64(sample, "memcache_bytes_written"); + sf_log_next64(sample, "memcache_bytes"); + sf_log_next64(sample, "memcache_limit_maxbytes"); +} + +/*_________________----------------------------__________________ + _________________ readCounters_http __________________ + -----------------____________________________------------------ +*/ + +static void readCounters_http(SFSample *sample) +{ + sf_log_next32(sample, "http_method_option_count"); + sf_log_next32(sample, "http_method_get_count"); + sf_log_next32(sample, "http_method_head_count"); + sf_log_next32(sample, "http_method_post_count"); + sf_log_next32(sample, "http_method_put_count"); + sf_log_next32(sample, "http_method_delete_count"); + sf_log_next32(sample, "http_method_trace_count"); + sf_log_next32(sample, "http_methd_connect_count"); + sf_log_next32(sample, "http_method_other_count"); + sf_log_next32(sample, "http_status_1XX_count"); + sf_log_next32(sample, "http_status_2XX_count"); + sf_log_next32(sample, "http_status_3XX_count"); + sf_log_next32(sample, "http_status_4XX_count"); + sf_log_next32(sample, "http_status_5XX_count"); + sf_log_next32(sample, "http_status_other_count"); +} + +/*_________________----------------------------__________________ + _________________ readCounters_JVM __________________ + -----------------____________________________------------------ +*/ + +static void readCounters_JVM(SFSample *sample) +{ + char vm_name[SFLJVM_MAX_VMNAME_LEN]; + char vendor[SFLJVM_MAX_VENDOR_LEN]; + char version[SFLJVM_MAX_VERSION_LEN]; + if(getString(sample, vm_name, SFLJVM_MAX_VMNAME_LEN) > 0) { + dbg_printf("jvm_name %s\n", vm_name); + } + if(getString(sample, vendor, SFLJVM_MAX_VENDOR_LEN) > 0) { + dbg_printf("jvm_vendor %s\n", vendor); + } + if(getString(sample, version, SFLJVM_MAX_VERSION_LEN) > 0) { + dbg_printf("jvm_version %s\n", version); + } +} + +/*_________________----------------------------__________________ + _________________ readCounters_JMX __________________ + -----------------____________________________------------------ +*/ + +static void readCounters_JMX(SFSample *sample, uint32_t length) +{ + sf_log_next64(sample, "heap_mem_initial"); + sf_log_next64(sample, "heap_mem_used"); + sf_log_next64(sample, "heap_mem_committed"); + sf_log_next64(sample, "heap_mem_max"); + sf_log_next64(sample, "non_heap_mem_initial"); + sf_log_next64(sample, "non_heap_mem_used"); + sf_log_next64(sample, "non_heap_mem_committed"); + sf_log_next64(sample, "non_heap_mem_max"); + sf_log_next32(sample, "gc_count"); + sf_log_next32(sample, "gc_mS"); + sf_log_next32(sample, "classes_loaded"); + sf_log_next32(sample, "classes_total"); + sf_log_next32(sample, "classes_unloaded"); + sf_log_next32(sample, "compilation_mS"); + sf_log_next32(sample, "threads_live"); + sf_log_next32(sample, "threads_daemon"); + sf_log_next32(sample, "threads_started"); + if(length > 100) { + sf_log_next32(sample, "fds_open"); + sf_log_next32(sample, "fds_max"); + } +} + +/*_________________----------------------------__________________ + _________________ readCounters_APP __________________ + -----------------____________________________------------------ +*/ + +static void readCounters_APP(SFSample *sample) +{ + char application[SFLAPP_MAX_APPLICATION_LEN]; + if(getString(sample, application, SFLAPP_MAX_APPLICATION_LEN) > 0) { + dbg_printf("application %s\n", application); + } + sf_log_next32(sample, "status_OK"); + sf_log_next32(sample, "errors_OTHER"); + sf_log_next32(sample, "errors_TIMEOUT"); + sf_log_next32(sample, "errors_INTERNAL_ERROR"); + sf_log_next32(sample, "errors_BAD_REQUEST"); + sf_log_next32(sample, "errors_FORBIDDEN"); + sf_log_next32(sample, "errors_TOO_LARGE"); + sf_log_next32(sample, "errors_NOT_IMPLEMENTED"); + sf_log_next32(sample, "errors_NOT_FOUND"); + sf_log_next32(sample, "errors_UNAVAILABLE"); + sf_log_next32(sample, "errors_UNAUTHORIZED"); +} + +/*_________________----------------------------__________________ + _________________ readCounters_APP_RESOURCE __________________ + -----------------____________________________------------------ +*/ + +static void readCounters_APP_RESOURCE(SFSample *sample) +{ + sf_log_next32(sample, "user_time"); + sf_log_next32(sample, "system_time"); + sf_log_next64(sample, "memory_used"); + sf_log_next64(sample, "memory_max"); + sf_log_next32(sample, "files_open"); + sf_log_next32(sample, "files_max"); + sf_log_next32(sample, "connections_open"); + sf_log_next32(sample, "connections_max"); +} + +/*_________________----------------------------__________________ + _________________ readCounters_APP_WORKERS __________________ + -----------------____________________________------------------ +*/ + +static void readCounters_APP_WORKERS(SFSample *sample) +{ + sf_log_next32(sample, "workers_active"); + sf_log_next32(sample, "workers_idle"); + sf_log_next32(sample, "workers_max"); + sf_log_next32(sample, "requests_delayed"); + sf_log_next32(sample, "requests_dropped"); +} + +/*_________________----------------------------__________________ + _________________ readCounters_VDI __________________ + -----------------____________________________------------------ +*/ + +static void readCounters_VDI(SFSample *sample) +{ + sf_log_next32(sample, "vdi_sessions_current"); + sf_log_next32(sample, "vdi_sessions_total"); + sf_log_next32(sample, "vdi_sessions_duration"); + sf_log_next32(sample, "vdi_rx_bytes"); + sf_log_next32(sample, "vdi_tx_bytes"); + sf_log_next32(sample, "vdi_rx_packets"); + sf_log_next32(sample, "vdi_tx_packets"); + sf_log_next32(sample, "vdi_rx_packets_lost"); + sf_log_next32(sample, "vdi_tx_packets_lost"); + sf_log_next32(sample, "vdi_rtt_min_ms"); + sf_log_next32(sample, "vdi_rtt_max_ms"); + sf_log_next32(sample, "vdi_rtt_avg_ms"); + sf_log_next32(sample, "vdi_audio_rx_bytes"); + sf_log_next32(sample, "vdi_audio_tx_bytes"); + sf_log_next32(sample, "vdi_audio_tx_limit"); + sf_log_next32(sample, "vdi_img_rx_bytes"); + sf_log_next32(sample, "vdi_img_tx_bytes"); + sf_log_next32(sample, "vdi_img_frames"); + sf_log_next32(sample, "vdi_img_qual_min"); + sf_log_next32(sample, "vdi_img_qual_max"); + sf_log_next32(sample, "vdi_img_qual_avg"); + sf_log_next32(sample, "vdi_usb_rx_bytes"); + sf_log_next32(sample, "vdi_usb_tx_bytes"); +} + +/*_________________------------------------------__________________ + _________________ readCounters_LACP __________________ + -----------------______________________________------------------ +*/ + +static void readCounters_LACP(SFSample *sample) +{ + SFLLACP_portState portState; + sf_log_nextMAC(sample, "actorSystemID"); + sf_log_nextMAC(sample, "partnerSystemID"); + sf_log_next32(sample, "attachedAggID"); + portState.all = getData32_nobswap(sample); + dbg_printf("actorAdminPortState %u\n", portState.v.actorAdmin); + dbg_printf("actorOperPortState %u\n", portState.v.actorOper); + dbg_printf("partnerAdminPortState %u\n", portState.v.partnerAdmin); + dbg_printf("partnerOperPortState %u\n", portState.v.partnerOper); + sf_log_next32(sample, "LACPDUsRx"); + sf_log_next32(sample, "markerPDUsRx"); + sf_log_next32(sample, "markerResponsePDUsRx"); + sf_log_next32(sample, "unknownRx"); + sf_log_next32(sample, "illegalRx"); + sf_log_next32(sample, "LACPDUsTx"); + sf_log_next32(sample, "markerPDUsTx"); + sf_log_next32(sample, "markerResponsePDUsTx"); +} + +/*_________________----------------------------__________________ + _________________ readCounters_SFP __________________ + -----------------____________________________------------------ +*/ + +static void readCounters_SFP(SFSample *sample) +{ + uint32_t num_lanes,ll; + sf_log_next32(sample, "sfp_module_id"); + sf_log_next32(sample, "sfp_module_total_lanes"); + sf_log_next32(sample, "sfp_module_supply_voltage"); + sf_log_next32(sample, "sfp_module_temperature"); + num_lanes = getData32(sample); + dbg_printf( "sfp_module_active_lanes %u\n", num_lanes); + for(ll=0; ll < num_lanes; ll++) { + dbg_printf( "sfp_lane_index.%u %u\n", ll, getData32(sample)); + dbg_printf( "sfp_lane_tx_bias_current_uA.%u %u\n", ll, getData32(sample)); + dbg_printf( "sfp_lane_tx_power_uW.%u %u\n", ll, getData32(sample)); + dbg_printf( "sfp_lane_tx_power_min_uW.%u %u\n", ll, getData32(sample)); + dbg_printf( "sfp_lane_tx_power_max_uW.%u %u\n", ll, getData32(sample)); + dbg_printf( "sfp_lane_tx_wavelength_nM.%u %u\n", ll, getData32(sample)); + dbg_printf( "sfp_lane_rx_power_uW.%u %u\n", ll, getData32(sample)); + dbg_printf( "sfp_lane_rx_power_min_uW.%u %u\n", ll, getData32(sample)); + dbg_printf( "sfp_lane_rx_power_max_uW.%u %u\n", ll, getData32(sample)); + dbg_printf( "sfp_lane_rx_wavelength_nM.%u %u\n", ll, getData32(sample)); + } +} + +/*_________________---------------------------__________________ + _________________ readCountersSample_v2v4 __________________ + -----------------___________________________------------------ +*/ + +static void readCountersSample_v2v4(SFSample *sample, FlowSource_t *fs) +{ + dbg_printf("sampleType COUNTERSSAMPLE\n"); + sample->samplesGenerated = getData32(sample); + dbg_printf("sampleSequenceNo %u\n", sample->samplesGenerated); + { + uint32_t samplerId = getData32(sample); + sample->ds_class = samplerId >> 24; + sample->ds_index = samplerId & 0x00ffffff; + } + dbg_printf("sourceId %u:%u\n", sample->ds_class, sample->ds_index); + + + sample->statsSamplingInterval = getData32(sample); + dbg_printf("statsSamplingInterval %u\n", sample->statsSamplingInterval); + /* now find out what sort of counter blocks we have here... */ + sample->counterBlockVersion = getData32(sample); + dbg_printf("counterBlockVersion %u\n", sample->counterBlockVersion); + + /* first see if we should read the generic stats */ + switch(sample->counterBlockVersion) { + case INMCOUNTERSVERSION_GENERIC: + case INMCOUNTERSVERSION_ETHERNET: + case INMCOUNTERSVERSION_TOKENRING: + case INMCOUNTERSVERSION_FDDI: + case INMCOUNTERSVERSION_VG: + case INMCOUNTERSVERSION_WAN: readCounters_generic(sample); break; + case INMCOUNTERSVERSION_VLAN: break; + default: receiveError(sample, "unknown stats version", YES); break; + } + + /* now see if there are any specific counter blocks to add */ + switch(sample->counterBlockVersion) { + case INMCOUNTERSVERSION_GENERIC: /* nothing more */ break; + case INMCOUNTERSVERSION_ETHERNET: readCounters_ethernet(sample); break; + case INMCOUNTERSVERSION_TOKENRING:readCounters_tokenring(sample); break; + case INMCOUNTERSVERSION_FDDI: break; + case INMCOUNTERSVERSION_VG: readCounters_vg(sample); break; + case INMCOUNTERSVERSION_WAN: break; + case INMCOUNTERSVERSION_VLAN: readCounters_vlan(sample); break; + default: receiveError(sample, "unknown INMCOUNTERSVERSION", YES); break; + } + /* line-by-line output... */ + if ( verbose ) + writeCountersLine(sample); +} + +/*_________________---------------------------__________________ + _________________ readCountersSample __________________ + -----------------___________________________------------------ +*/ + +static void readCountersSample(SFSample *sample, int expanded, FlowSource_t *fs) +{ + uint32_t sampleLength; + uint32_t num_elements; + uint8_t *sampleStart; + dbg_printf("sampleType COUNTERSSAMPLE\n"); + sampleLength = getData32(sample); + sampleStart = (uint8_t *)sample->datap; + sample->samplesGenerated = getData32(sample); + + dbg_printf("sampleSequenceNo %u\n", sample->samplesGenerated); + if(expanded) { + sample->ds_class = getData32(sample); + sample->ds_index = getData32(sample); + } + else { + uint32_t samplerId = getData32(sample); + sample->ds_class = samplerId >> 24; + sample->ds_index = samplerId & 0x00ffffff; + } + dbg_printf("sourceId %u:%u\n", sample->ds_class, sample->ds_index); + + num_elements = getData32(sample); + { + uint32_t el; + for(el = 0; el < num_elements; el++) { + uint32_t tag, length; + uint8_t *start; +#ifdef DEVEL + char buf[51]; +#endif + tag = sample->elementType = getData32(sample); + dbg_printf("counterBlock_tag %s\n", printTag(tag, buf, 50)); + length = getData32(sample); + start = (uint8_t *)sample->datap; + + switch(tag) { + case SFLCOUNTERS_GENERIC: readCounters_generic(sample); break; + case SFLCOUNTERS_ETHERNET: readCounters_ethernet(sample); break; + case SFLCOUNTERS_TOKENRING:readCounters_tokenring(sample); break; + case SFLCOUNTERS_VG: readCounters_vg(sample); break; + case SFLCOUNTERS_VLAN: readCounters_vlan(sample); break; + case SFLCOUNTERS_80211: readCounters_80211(sample); break; + case SFLCOUNTERS_LACP: readCounters_LACP(sample); break; + case SFLCOUNTERS_SFP: readCounters_SFP(sample); break; + case SFLCOUNTERS_PROCESSOR: readCounters_processor(sample); break; + case SFLCOUNTERS_RADIO: readCounters_radio(sample); break; + case SFLCOUNTERS_OFPORT: readCounters_OFPort(sample); break; + case SFLCOUNTERS_PORTNAME: readCounters_portName(sample); break; + case SFLCOUNTERS_HOST_HID: readCounters_host_hid(sample); break; + case SFLCOUNTERS_ADAPTORS: readCounters_adaptors(sample); break; + case SFLCOUNTERS_HOST_PAR: readCounters_host_parent(sample); break; + case SFLCOUNTERS_HOST_CPU: readCounters_host_cpu(sample, length); break; + case SFLCOUNTERS_HOST_MEM: readCounters_host_mem(sample); break; + case SFLCOUNTERS_HOST_DSK: readCounters_host_dsk(sample); break; + case SFLCOUNTERS_HOST_NIO: readCounters_host_nio(sample); break; + case SFLCOUNTERS_HOST_IP: readCounters_host_ip(sample); break; + case SFLCOUNTERS_HOST_ICMP: readCounters_host_icmp(sample); break; + case SFLCOUNTERS_HOST_TCP: readCounters_host_tcp(sample); break; + case SFLCOUNTERS_HOST_UDP: readCounters_host_udp(sample); break; + case SFLCOUNTERS_HOST_VRT_NODE: readCounters_host_vnode(sample); break; + case SFLCOUNTERS_HOST_VRT_CPU: readCounters_host_vcpu(sample); break; + case SFLCOUNTERS_HOST_VRT_MEM: readCounters_host_vmem(sample); break; + case SFLCOUNTERS_HOST_VRT_DSK: readCounters_host_vdsk(sample); break; + case SFLCOUNTERS_HOST_VRT_NIO: readCounters_host_vnio(sample); break; + case SFLCOUNTERS_HOST_GPU_NVML: readCounters_host_gpu_nvml(sample); break; + case SFLCOUNTERS_BCM_TABLES: readCounters_bcm_tables(sample); break; + case SFLCOUNTERS_MEMCACHE: readCounters_memcache(sample); break; + case SFLCOUNTERS_MEMCACHE2: readCounters_memcache2(sample); break; + case SFLCOUNTERS_HTTP: readCounters_http(sample); break; + case SFLCOUNTERS_JVM: readCounters_JVM(sample); break; + case SFLCOUNTERS_JMX: readCounters_JMX(sample, length); break; + case SFLCOUNTERS_APP: readCounters_APP(sample); break; + case SFLCOUNTERS_APP_RESOURCE: readCounters_APP_RESOURCE(sample); break; + case SFLCOUNTERS_APP_WORKERS: readCounters_APP_WORKERS(sample); break; + case SFLCOUNTERS_VDI: readCounters_VDI(sample); break; + case SFLCOUNTERS_OVSDP: readCounters_OVSDP(sample); break; + default: skipTLVRecord(sample, tag, length, "counters_sample_element"); break; + } + lengthCheck(sample, "counters_sample_element", start, length); + } + } + lengthCheck(sample, "counters_sample", sampleStart, sampleLength); + /* line-by-line output... */ + if ( verbose ) + writeCountersLine(sample); +} + +/*_________________---------------------------__________________ + _________________ readRTMetric __________________ + -----------------___________________________------------------ +*/ + +static void readRTMetric(SFSample *sample, FlowSource_t *fs) +{ +#define SFL_MAX_RTMETRIC_KEY_LEN 64 +#define SFL_MAX_RTMETRIC_VAL_LEN 255 + char dsName[SFL_MAX_RTMETRIC_KEY_LEN]; + uint32_t sampleLength; + uint32_t num_elements; + uint8_t *sampleStart; + dbg_printf("sampleType RTMETRIC\n"); + sampleLength = getData32(sample); + sampleStart = (uint8_t *)sample->datap; + if(getString(sample, dsName, SFL_MAX_RTMETRIC_KEY_LEN) > 0) { + dbg_printf( "rtmetric_datasource_name %s\n", dsName); + } + num_elements = getData32(sample); + { + uint32_t el; + for(el = 0; el < num_elements; el++) { + char mname[SFL_MAX_RTMETRIC_KEY_LEN]; + uint32_t mtype; + char mvalstr[SFL_MAX_RTMETRIC_VAL_LEN]; + uint32_t mvali32; + uint64_t mvali64; + float mvalfloat; + double mvaldouble; + getString(sample, mname, SFL_MAX_RTMETRIC_KEY_LEN); + mtype = getData32(sample); + switch(mtype) { + case 0: + getString(sample, mvalstr, SFL_MAX_RTMETRIC_VAL_LEN); + dbg_printf( "rtmetric %s = (string) \"%s\"\n", mname, mvalstr); + break; + case 1: + mvali32 = getData32(sample); + dbg_printf( "rtmetric %s = (counter32) %u\n", mname, mvali32); + break; + case 2: + mvali64 = getData64(sample); + dbg_printf( "rtmetric %s = (counter64) %llu\n", mname, mvali64); + break; + case 3: + mvali32 = getData32(sample); + dbg_printf( "rtmetric %s = (gauge32) %u\n", mname, mvali32); + break; + case 4: + mvali64 = getData64(sample); + dbg_printf( "rtmetric %s = (gauge64) %llu\n", mname, mvali64); + break; + case 5: + mvalfloat = getFloat(sample); + dbg_printf( "rtmetric %s = (gaugefloat) %.3f\n", mname, mvalfloat); + break; + case 6: + mvaldouble = getDouble(sample); + dbg_printf( "rtmetric %s = (gaugefloat) %.3f\n", mname, mvaldouble); + break; + default: + dbg_printf( "rtmetric unknown_type %u\n", mtype); + SFABORT(sample, SF_ABORT_DECODE_ERROR); + break; + } + } + } + lengthCheck(sample, "rtmetric_sample", sampleStart, sampleLength); + + if ( verbose ) + writeCountersLine(sample); + +} + +/*_________________---------------------------__________________ + _________________ readRTFlow __________________ + -----------------___________________________------------------ +*/ + +static void readRTFlow(SFSample *sample, FlowSource_t *fs) +{ + char dsName[SFL_MAX_RTMETRIC_KEY_LEN]; + uint32_t sampleLength; + uint32_t num_elements; + uint8_t *sampleStart; + dbg_printf("sampleType RTFLOW\n"); + sampleLength = getData32(sample); + sampleStart = (uint8_t *)sample->datap; + if(getString(sample, dsName, SFL_MAX_RTMETRIC_KEY_LEN) > 0) { + dbg_printf( "rtflow_datasource_name %s\n", dsName); + } + sf_log_next32(sample, "rtflow_sampling_rate"); + sf_log_next32(sample, "rtflow_sample_pool"); + num_elements = getData32(sample); + { + uint32_t el; + for(el = 0; el < num_elements; el++) { + char fname[SFL_MAX_RTMETRIC_KEY_LEN]; + uint32_t ftype; + char fvalstr[SFL_MAX_RTMETRIC_VAL_LEN]; + uint32_t fvali32; + uint64_t fvali64; + float fvalfloat; + double fvaldouble; + SFLAddress fvaladdr; +#ifdef DEVEL + char fvaladdrstr[64]; +#endif + u_char fvalmac[6]; + char fvalmacstr[32]; + getString(sample, fname, SFL_MAX_RTMETRIC_KEY_LEN); + ftype = getData32(sample); + switch(ftype) { + case 0: + getString(sample, fvalstr, SFL_MAX_RTMETRIC_VAL_LEN); + dbg_printf( "rtflow %s = (string) \"%s\"\n", fname, fvalstr); + break; + case 1: + memcpy(fvalmac, sample->datap, 6); + skipBytes(sample, 6); + printHex(fvalmac, 6, fvalmacstr, 32, 0, 100); + dbg_printf( "rtflow %s = (mac) %s\n", fname, fvalmacstr); + break; + case 2: + fvaladdr.type = SFLADDRESSTYPE_IP_V4; + fvaladdr.address.ip_v4.addr = getData32_nobswap(sample); + dbg_printf( "rtflow %s = (ip) %s\n", + fname, + printAddress(&fvaladdr,fvaladdrstr, 63)); + break; + case 3: + fvaladdr.type = SFLADDRESSTYPE_IP_V6; + memcpy(fvaladdr.address.ip_v6.addr, sample->datap, 16); + skipBytes(sample, 16); + dbg_printf( "rtflow %s = (ip6) %s\n", + fname, + printAddress(&fvaladdr,fvaladdrstr, 63)); + break; + case 4: + fvali32 = getData32(sample); + dbg_printf( "rtflow %s = (int32) %u\n", fname, fvali32); + break; + case 5: + fvali64 = getData64(sample); + dbg_printf( "rtflow %s = (int64) %llu\n", fname, fvali64); + break; + case 6: + fvalfloat = getFloat(sample); + dbg_printf( "rtflow %s = (gaugefloat) %.3f\n", fname, fvalfloat); + break; + case 7: + fvaldouble = getDouble(sample); + dbg_printf( "rtflow %s = (gaugefloat) %.3f\n", fname, fvaldouble); + break; + default: + dbg_printf( "rtflow unknown_type %u\n", ftype); + SFABORT(sample, SF_ABORT_DECODE_ERROR); + break; + } + } + } + lengthCheck(sample, "rtflow_sample", sampleStart, sampleLength); + + if ( verbose ) + writeCountersLine(sample); + +} + +/*_________________---------------------------__________________ + _________________ readSFlowDatagram __________________ + -----------------___________________________------------------ +*/ + +static void readSFlowDatagram(SFSample *sample, FlowSource_t *fs) +{ + uint32_t samplesInPacket; +#ifdef DEVEL + char buf[51]; +#endif + + /* log some datagram info */ + dbg_printf("datagramSourceIP %s\n", IP_to_a(sample->sourceIP.s_addr, buf, 51)); + dbg_printf("datagramSize %u\n", sample->rawSampleLen); + dbg_printf("unixSecondsUTC %llu\n", (unsigned long long)sample->readTimestamp); + + /* check the version */ + sample->datagramVersion = getData32(sample); + dbg_printf("datagramVersion %d\n", sample->datagramVersion); + if(sample->datagramVersion != 2 && + sample->datagramVersion != 4 && + sample->datagramVersion != 5) { + receiveError(sample, "unexpected datagram version number\n", YES); + } + + /* get the agent address */ + getAddress(sample, &sample->agent_addr); + + /* version 5 has an agent sub-id as well */ + if(sample->datagramVersion >= 5) { + sample->agentSubId = getData32(sample); + dbg_printf("agentSubId %u\n", sample->agentSubId); + } + + sample->sequenceNo = getData32(sample); /* this is the packet sequence number */ + sample->sysUpTime = getData32(sample); + samplesInPacket = getData32(sample); + dbg_printf("agent %s\n", printAddress(&sample->agent_addr, buf, 50)); + dbg_printf("packetSequenceNo %u\n", sample->sequenceNo); + dbg_printf("sysUpTime %u\n", sample->sysUpTime); + dbg_printf("samplesInPacket %u\n", samplesInPacket); + + /* now iterate and pull out the flows and counters samples */ + { + uint32_t samp = 0; + for(; samp < samplesInPacket; samp++) { + if((uint8_t *)sample->datap >= sample->endp) { + LogError("SFLOW: readSFlowDatagram() unexpected end of datagram after sample %d of %d\n", samp, samplesInPacket); + SFABORT(sample, SF_ABORT_EOS); + } + /* just read the tag, then call the approriate decode fn */ + sample->elementType = 0; + sample->sampleType = getData32(sample); + dbg_printf("startSample ----------------------\n"); + dbg_printf("sampleType_tag %s\n", printTag(sample->sampleType, buf, 50)); + if(sample->datagramVersion >= 5) { + switch(sample->sampleType) { + case SFLFLOW_SAMPLE: readFlowSample(sample, NO, fs); break; + case SFLCOUNTERS_SAMPLE: readCountersSample(sample, NO, fs); break; + case SFLFLOW_SAMPLE_EXPANDED: readFlowSample(sample, YES, fs); break; + case SFLCOUNTERS_SAMPLE_EXPANDED: readCountersSample(sample, YES, fs); break; + case SFLRTMETRIC: readRTMetric(sample, fs); break; + case SFLRTFLOW: readRTFlow(sample, fs); break; + default: skipTLVRecord(sample, sample->sampleType, getData32(sample), "sample"); break; + } + } + else { + switch(sample->sampleType) { + case FLOWSAMPLE: readFlowSample_v2v4(sample, fs); break; + case COUNTERSSAMPLE: readCountersSample_v2v4(sample, fs); break; + default: receiveError(sample, "unexpected sample type", YES); break; + } + } + dbg_printf("endSample ----------------------\n"); + } + } +} + +/*_________________---------------------------__________________ + _________________ printUUID __________________ + -----------------___________________________------------------ +*/ + + static int printUUID(const uint8_t *a, char *buf, int bufLen) + { + int i, b = 0; + b += printHex(a, 4, buf, bufLen, 0, 100); + buf[b++] = '-'; + b += printHex(a + 4, 2, buf + b, bufLen - b, 0, 100); + buf[b++] = '-'; + b += printHex(a + 6, 2, buf + b, bufLen - b, 0, 100); + buf[b++] = '-'; + b += printHex(a + 8, 2, buf + b, bufLen - b, 0, 100); + buf[b++] = '-'; + b += printHex(a + 10, 6, buf + b, bufLen - b, 0, 100); + + /* should really be lowercase hex - fix that here */ + for(i = 0; i < b; i++) buf[i] = tolower(buf[i]); + + /* add NUL termination */ + buf[b] = '\0'; + + return b; + } + +#ifdef DEVEL +static char *URLEncode(char *in, char *out, int outlen) +{ + register char c, *r = in, *w = out; + int maxlen = (strlen(in) * 3) + 1; + if(outlen < maxlen) return "URLEncode: not enough space"; + while ((c = *r++)) { + if(isalnum(c)) *w++ = c; + else if(isspace(c)) *w++ = '+'; + else { + *w++ = '%'; + *w++ = bin2hex(c >> 4); + *w++ = bin2hex(c & 0x0f); + } + } + *w++ = '\0'; + return out; +} +#endif diff --git a/bin/sflow_nfdump.h b/bin/sflow_nfdump.h new file mode 100644 index 0000000..b494338 --- /dev/null +++ b/bin/sflow_nfdump.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017, Peter Haag + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the author nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _SFLOW_NFDUMP_H +#define _SFLOW_NFDUMP_H 1 + +void Init_sflow(void); + +void Process_sflow(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs); + +/* + * Extension map for sflow ( compatibility for now ) + * + * Required extensions: + * + * 4 byte byte counter + * | 4byte packet counter + * | | IPv4 + * | | | + * xxxx x0 0 0 + * + * Optional extensions: + * + * 4 : 2 byte input/output interface id + * 6 : 2 byte src/dst as + */ + +#endif // _SFLOW_NFDUMP_H diff --git a/bin/sflow_proto.h b/bin/sflow_proto.h deleted file mode 100644 index 34302e8..0000000 --- a/bin/sflow_proto.h +++ /dev/null @@ -1,702 +0,0 @@ -/* - * Copyright (c) 2014, Peter Haag - * Copyright (c) 2009, Peter Haag - * Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the author nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Author: haag $ - * - * $Id: sflow_proto.h 39 2009-11-25 08:11:15Z haag $ - * - * $LastChangedRevision: 39 $ - * - * - */ - -/* - * sfcapd makes use of code originated from sflowtool by InMon Corp. - * Those parts of the code are distributed under the InMon Public License below. - * All other/additional code is pubblished under BSD license. - */ - - -/* - * ----------------------------------------------------------------------- - * Copyright (c) 2001-2002 InMon Corp. All rights reserved. - * ----------------------------------------------------------------------- - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes sFlow(TM), freely available from - * http://www.inmon.com/". - * - * 4. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes sFlow(TM), freely available from - * http://www.inmon.com/". - * - * 5. InMon Corp. may publish revised and/or new versions - * of the license from time to time. Each version will be given a - * distinguishing version number. Once covered code has been - * published under a particular version of the license, you may - * always continue to use it under the terms of that version. You - * may also choose to use such covered code under the terms of any - * subsequent version of the license published by InMon Corp. - * No one other than the InMon Corp. has the right to modify the terms - * applicable to covered code created under this License. - * - * 6. The name "sFlow" must not be used to endorse or promote products - * derived from this software without prior written permission - * from InMon Corp. This does not apply to add-on libraries or tools - * that work in conjunction with sFlow. In such a case the sFlow name - * may be used to indicate that the product supports sFlow. - * - * 7. Products derived from this software may not be called "sFlow", - * nor may "sFlow" appear in their name, without prior written - * permission of InMon Corp. - * - * - * THIS SOFTWARE IS PROVIDED BY INMON CORP. ``AS IS'' AND - * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * INMON CORP. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * -------------------------------------------------------------------- - * - * This software consists of voluntary contributions made by many - * individuals on behalf of InMon Corp. - * - * InMon Corp. can be contacted via Email at info@inmon.com. - * - * For more information on InMon Corp. and sFlow, - * please see http://www.inmon.com/. - * - * InMon Public License Version 1.0 written May 31, 2001 - * - */ - -///////////////////////////////////////////////////////////////////////////////// -/////////////////////// sFlow Sampling Packet Data Types //////////////////////// -///////////////////////////////////////////////////////////////////////////////// - -#ifndef _SFLOW_PROTO_H -#define _SFLOW_PROTO_H 1 - -#if defined(__cplusplus) -extern "C" { -#endif - -enum SFLAddress_type { - SFLADDRESSTYPE_IP_V4 = 1, - SFLADDRESSTYPE_IP_V6 = 2 -}; - -typedef union _SFLAddress_value { - struct in_addr ip_v4; - struct in6_addr ip_v6; -} SFLAddress_value; - -typedef struct _SFLAddress { - uint32_t type; /* enum SFLAddress_type */ - SFLAddress_value address; -} SFLAddress; - -/* Packet header data */ - -#define SFL_DEFAULT_HEADER_SIZE 128 -#define SFL_DEFAULT_COLLECTOR_PORT 6343 -#define SFL_DEFAULT_SAMPLING_RATE 400 - -/* The header protocol describes the format of the sampled header */ -enum SFLHeader_protocol { - SFLHEADER_ETHERNET_ISO8023 = 1, - SFLHEADER_ISO88024_TOKENBUS = 2, - SFLHEADER_ISO88025_TOKENRING = 3, - SFLHEADER_FDDI = 4, - SFLHEADER_FRAME_RELAY = 5, - SFLHEADER_X25 = 6, - SFLHEADER_PPP = 7, - SFLHEADER_SMDS = 8, - SFLHEADER_AAL5 = 9, - SFLHEADER_AAL5_IP = 10, /* e.g. Cisco AAL5 mux */ - SFLHEADER_IPv4 = 11, - SFLHEADER_IPv6 = 12, - SFLHEADER_MPLS = 13 -}; - -/* raw sampled header */ - -typedef struct _SFLSampled_header { - uint32_t header_protocol; /* (enum SFLHeader_protocol) */ - uint32_t frame_length; /* Original length of packet before sampling */ - uint32_t stripped; /* header/trailer bytes stripped by sender */ - uint32_t header_length; /* length of sampled header bytes to follow */ - uint8_t *header_bytes; /* Header bytes */ -} SFLSampled_header; - -/* decoded ethernet header */ - -typedef struct _SFLSampled_ethernet { - uint32_t eth_len; /* The length of the MAC packet excluding - lower layer encapsulations */ - uint8_t src_mac[8]; /* 6 bytes + 2 pad */ - uint8_t dst_mac[8]; - uint32_t eth_type; -} SFLSampled_ethernet; - -/* decoded IP version 4 header */ - -typedef struct _SFLSampled_ipv4 { - uint32_t length; /* The length of the IP packet - excluding lower layer encapsulations */ - uint32_t protocol; /* IP Protocol type (for example, TCP = 6, UDP = 17) */ - struct in_addr src_ip; /* Source IP Address */ - struct in_addr dst_ip; /* Destination IP Address */ - uint32_t src_port; /* TCP/UDP source port number or equivalent */ - uint32_t dst_port; /* TCP/UDP destination port number or equivalent */ - uint32_t tcp_flags; /* TCP flags */ - uint32_t tos; /* IP type of service */ -} SFLSampled_ipv4; - -/* decoded IP version 6 data */ - -typedef struct _SFLSampled_ipv6 { - uint32_t length; /* The length of the IP packet - excluding lower layer encapsulations */ - uint32_t protocol; /* IP Protocol type (for example, TCP = 6, UDP = 17) */ - struct in6_addr src_ip; /* Source IP Address */ - struct in6_addr dst_ip; /* Destination IP Address */ - uint32_t src_port; /* TCP/UDP source port number or equivalent */ - uint32_t dst_port; /* TCP/UDP destination port number or equivalent */ - uint32_t tcp_flags; /* TCP flags */ - uint32_t priority; /* IP priority */ -} SFLSampled_ipv6; - -/* Extended data types */ - -/* Extended switch data */ - -typedef struct _SFLExtended_switch { - uint32_t src_vlan; /* The 802.1Q VLAN id of incomming frame */ - uint32_t src_priority; /* The 802.1p priority */ - uint32_t dst_vlan; /* The 802.1Q VLAN id of outgoing frame */ - uint32_t dst_priority; /* The 802.1p priority */ -} SFLExtended_switch; - -/* Extended router data */ - -typedef struct _SFLExtended_router { - SFLAddress nexthop; /* IP address of next hop router */ - uint32_t src_mask; /* Source address prefix mask bits */ - uint32_t dst_mask; /* Destination address prefix mask bits */ -} SFLExtended_router; - -/* Extended gateway data */ -enum SFLExtended_as_path_segment_type { - SFLEXTENDED_AS_SET = 1, /* Unordered set of ASs */ - SFLEXTENDED_AS_SEQUENCE = 2 /* Ordered sequence of ASs */ -}; - -typedef struct _SFLExtended_as_path_segment { - uint32_t type; /* enum SFLExtended_as_path_segment_type */ - uint32_t length; /* number of AS numbers in set/sequence */ - union { - uint32_t *set; - uint32_t *seq; - } as; -} SFLExtended_as_path_segment; - -typedef struct _SFLExtended_gateway { - SFLAddress nexthop; /* Address of the border router that should - be used for the destination network */ - uint32_t as; /* AS number for this gateway */ - uint32_t src_as; /* AS number of source (origin) */ - uint32_t src_peer_as; /* AS number of source peer */ - uint32_t dst_as_path_segments; /* number of segments in path */ - SFLExtended_as_path_segment *dst_as_path; /* list of seqs or sets */ - uint32_t communities_length; /* number of communities */ - uint32_t *communities; /* set of communities */ - uint32_t localpref; /* LocalPref associated with this route */ -} SFLExtended_gateway; - -typedef struct _SFLString { - uint32_t len; - char *str; -} SFLString; - -/* Extended user data */ - -typedef struct _SFLExtended_user { - uint32_t src_charset; /* MIBEnum value of character set used to encode a string - See RFC 2978 - Where possible UTF-8 encoding (MIBEnum=106) should be used. A value - of zero indicates an unknown encoding. */ - SFLString src_user; - uint32_t dst_charset; - SFLString dst_user; -} SFLExtended_user; - -/* Extended URL data */ - -enum SFLExtended_url_direction { - SFLEXTENDED_URL_SRC = 1, /* URL is associated with source address */ - SFLEXTENDED_URL_DST = 2 /* URL is associated with destination address */ -}; - -typedef struct _SFLExtended_url { - uint32_t direction; /* enum SFLExtended_url_direction */ - SFLString url; /* URL associated with the packet flow. - Must be URL encoded */ - SFLString host; /* The host field from the HTTP header */ -} SFLExtended_url; - -/* Extended MPLS data */ - -typedef struct _SFLLabelStack { - uint32_t depth; - uint32_t *stack; /* first entry is top of stack - see RFC 3032 for encoding */ -} SFLLabelStack; - -typedef struct _SFLExtended_mpls { - SFLAddress nextHop; /* Address of the next hop */ - SFLLabelStack in_stack; - SFLLabelStack out_stack; -} SFLExtended_mpls; - - /* Extended NAT data - Packet header records report addresses as seen at the sFlowDataSource. - The extended_nat structure reports on translated source and/or destination - addesses for this packet. If an address was not translated it should - be equal to that reported for the header. */ - -typedef struct _SFLExtended_nat { - SFLAddress src; /* Source address */ - SFLAddress dst; /* Destination address */ -} SFLExtended_nat; - - /* additional Extended MPLS stucts */ - -typedef struct _SFLExtended_mpls_tunnel { - SFLString tunnel_lsp_name; /* Tunnel name */ - uint32_t tunnel_id; /* Tunnel ID */ - uint32_t tunnel_cos; /* Tunnel COS value */ -} SFLExtended_mpls_tunnel; - -typedef struct _SFLExtended_mpls_vc { - SFLString vc_instance_name; /* VC instance name */ - uint32_t vll_vc_id; /* VLL/VC instance ID */ - uint32_t vc_label_cos; /* VC Label COS value */ -} SFLExtended_mpls_vc; - -/* Extended MPLS FEC - - Definitions from MPLS-FTN-STD-MIB mplsFTNTable */ - -typedef struct _SFLExtended_mpls_FTN { - SFLString mplsFTNDescr; - uint32_t mplsFTNMask; -} SFLExtended_mpls_FTN; - -/* Extended MPLS LVP FEC - - Definition from MPLS-LDP-STD-MIB mplsFecTable - Note: mplsFecAddrType, mplsFecAddr information available - from packet header */ - -typedef struct _SFLExtended_mpls_LDP_FEC { - uint32_t mplsFecAddrPrefixLength; -} SFLExtended_mpls_LDP_FEC; - -/* Extended VLAN tunnel information - Record outer VLAN encapsulations that have - been stripped. extended_vlantunnel information - should only be reported if all the following conditions are satisfied: - 1. The packet has nested vlan tags, AND - 2. The reporting device is VLAN aware, AND - 3. One or more VLAN tags have been stripped, either - because they represent proprietary encapsulations, or - because switch hardware automatically strips the outer VLAN - encapsulation. - Reporting extended_vlantunnel information is not a substitute for - reporting extended_switch information. extended_switch data must - always be reported to describe the ingress/egress VLAN information - for the packet. The extended_vlantunnel information only applies to - nested VLAN tags, and then only when one or more tags has been - stripped. */ - -typedef SFLLabelStack SFLVlanStack; -typedef struct _SFLExtended_vlan_tunnel { - SFLVlanStack stack; /* List of stripped 802.1Q TPID/TCI layers. Each - TPID,TCI pair is represented as a single 32 bit - integer. Layers listed from outermost to - innermost. */ -} SFLExtended_vlan_tunnel; - - - ////////////////// InMon Extension structs ////////////////////////// - -typedef struct _SFLProcess { - uint32_t pid; - SFLString command; -} SFLProcess; - -#define SFL_MAX_PROCESSES 10 -typedef struct _SFLExtended_process { - uint32_t num_processes; - SFLProcess processes[SFL_MAX_PROCESSES]; -} SFLExtended_process; - - ////////////////////////////////////////////////////////////////////// - -enum SFLFlow_type_tag { - /* enterprise = 0, format = ... */ - SFLFLOW_HEADER = 1, /* Packet headers are sampled */ - SFLFLOW_ETHERNET = 2, /* MAC layer information */ - SFLFLOW_IPV4 = 3, /* IP version 4 data */ - SFLFLOW_IPV6 = 4, /* IP version 6 data */ - SFLFLOW_EX_SWITCH = 1001, /* Extended switch information */ - SFLFLOW_EX_ROUTER = 1002, /* Extended router information */ - SFLFLOW_EX_GATEWAY = 1003, /* Extended gateway router information */ - SFLFLOW_EX_USER = 1004, /* Extended TACAS/RADIUS user information */ - SFLFLOW_EX_URL = 1005, /* Extended URL information */ - SFLFLOW_EX_MPLS = 1006, /* Extended MPLS information */ - SFLFLOW_EX_NAT = 1007, /* Extended NAT information */ - SFLFLOW_EX_MPLS_TUNNEL = 1008, /* additional MPLS information */ - SFLFLOW_EX_MPLS_VC = 1009, - SFLFLOW_EX_MPLS_FTN = 1010, - SFLFLOW_EX_MPLS_LDP_FEC = 1011, - SFLFLOW_EX_VLAN_TUNNEL = 1012, /* VLAN stack */ - /* enterprise = 4300 (inmon)...*/ - SFLFLOW_EX_PROCESS = (4300 << 12) + 3, /* =17612803 Extended Process information */ -}; - -typedef union _SFLFlow_type { - SFLSampled_header header; - SFLSampled_ethernet ethernet; - SFLSampled_ipv4 ipv4; - SFLSampled_ipv6 ipv6; - SFLExtended_switch sw; - SFLExtended_router router; - SFLExtended_gateway gateway; - SFLExtended_user user; - SFLExtended_url url; - SFLExtended_mpls mpls; - SFLExtended_nat nat; - SFLExtended_mpls_tunnel mpls_tunnel; - SFLExtended_mpls_vc mpls_vc; - SFLExtended_mpls_FTN mpls_ftn; - SFLExtended_mpls_LDP_FEC mpls_ldp_fec; - SFLExtended_vlan_tunnel vlan_tunnel; - // extensions - SFLExtended_process process; -} SFLFlow_type; - -typedef struct _SFLFlow_sample_element { - struct _SFLFlow_sample_element *nxt; - uint32_t tag; /* SFLFlow_type_tag */ - uint32_t length; - SFLFlow_type flowType; -} SFLFlow_sample_element; - -enum SFL_sample_tag { - SFLFLOW_SAMPLE = 1, /* enterprise = 0 : format = 1 */ - SFLCOUNTERS_SAMPLE = 2, /* enterprise = 0 : format = 2 */ - SFLFLOW_SAMPLE_EXPANDED = 3, /* enterprise = 0 : format = 3 */ - SFLCOUNTERS_SAMPLE_EXPANDED = 4 /* enterprise = 0 : format = 4 */ -}; - -/* Format of a single flow sample */ - -typedef struct _SFLFlow_sample { - /* uint32_t tag; */ /* SFL_sample_tag -- enterprise = 0 : format = 1 */ - /* uint32_t length; */ - uint32_t sequence_number; /* Incremented with each flow sample - generated */ - uint32_t source_id; /* fsSourceId */ - uint32_t sampling_rate; /* fsPacketSamplingRate */ - uint32_t sample_pool; /* Total number of packets that could have been - sampled (i.e. packets skipped by sampling - process + total number of samples) */ - uint32_t drops; /* Number of times a packet was dropped due to - lack of resources */ - uint32_t input; /* SNMP ifIndex of input interface. - 0 if interface is not known. */ - uint32_t output; /* SNMP ifIndex of output interface, - 0 if interface is not known. - Set most significant bit to indicate - multiple destination interfaces - (i.e. in case of broadcast or multicast) - and set lower order bits to indicate - number of destination interfaces. - Examples: - 0x00000002 indicates ifIndex = 2 - 0x00000000 ifIndex unknown. - 0x80000007 indicates a packet sent - to 7 interfaces. - 0x80000000 indicates a packet sent to - an unknown number of - interfaces greater than 1.*/ - uint32_t num_elements; - SFLFlow_sample_element *elements; -} SFLFlow_sample; - - /* same thing, but the expanded version (for full 32-bit ifIndex numbers) */ - -typedef struct _SFLFlow_sample_expanded { - /* uint32_t tag; */ /* SFL_sample_tag -- enterprise = 0 : format = 1 */ - /* uint32_t length; */ - uint32_t sequence_number; /* Incremented with each flow sample - generated */ - uint32_t ds_class; /* EXPANDED */ - uint32_t ds_index; /* EXPANDED */ - uint32_t sampling_rate; /* fsPacketSamplingRate */ - uint32_t sample_pool; /* Total number of packets that could have been - sampled (i.e. packets skipped by sampling - process + total number of samples) */ - uint32_t drops; /* Number of times a packet was dropped due to - lack of resources */ - uint32_t inputFormat; /* EXPANDED */ - uint32_t input; /* SNMP ifIndex of input interface. - 0 if interface is not known. */ - uint32_t outputFormat; /* EXPANDED */ - uint32_t output; /* SNMP ifIndex of output interface, - 0 if interface is not known. */ - uint32_t num_elements; - SFLFlow_sample_element *elements; -} SFLFlow_sample_expanded; - -/* Counter types */ - -/* Generic interface counters - see RFC 1573, 2233 */ - -typedef struct _SFLIf_counters { - uint32_t ifIndex; - uint32_t ifType; - uint64_t ifSpeed; - uint32_t ifDirection; /* Derived from MAU MIB (RFC 2668) - 0 = unknown, 1 = full-duplex, - 2 = half-duplex, 3 = in, 4 = out */ - uint32_t ifStatus; /* bit field with the following bits assigned: - bit 0 = ifAdminStatus (0 = down, 1 = up) - bit 1 = ifOperStatus (0 = down, 1 = up) */ - uint64_t ifInOctets; - uint32_t ifInUcastPkts; - uint32_t ifInMulticastPkts; - uint32_t ifInBroadcastPkts; - uint32_t ifInDiscards; - uint32_t ifInErrors; - uint32_t ifInUnknownProtos; - uint64_t ifOutOctets; - uint32_t ifOutUcastPkts; - uint32_t ifOutMulticastPkts; - uint32_t ifOutBroadcastPkts; - uint32_t ifOutDiscards; - uint32_t ifOutErrors; - uint32_t ifPromiscuousMode; -} SFLIf_counters; - -/* Ethernet interface counters - see RFC 2358 */ -typedef struct _SFLEthernet_counters { - uint32_t dot3StatsAlignmentErrors; - uint32_t dot3StatsFCSErrors; - uint32_t dot3StatsSingleCollisionFrames; - uint32_t dot3StatsMultipleCollisionFrames; - uint32_t dot3StatsSQETestErrors; - uint32_t dot3StatsDeferredTransmissions; - uint32_t dot3StatsLateCollisions; - uint32_t dot3StatsExcessiveCollisions; - uint32_t dot3StatsInternalMacTransmitErrors; - uint32_t dot3StatsCarrierSenseErrors; - uint32_t dot3StatsFrameTooLongs; - uint32_t dot3StatsInternalMacReceiveErrors; - uint32_t dot3StatsSymbolErrors; -} SFLEthernet_counters; - -/* Token ring counters - see RFC 1748 */ - -typedef struct _SFLTokenring_counters { - uint32_t dot5StatsLineErrors; - uint32_t dot5StatsBurstErrors; - uint32_t dot5StatsACErrors; - uint32_t dot5StatsAbortTransErrors; - uint32_t dot5StatsInternalErrors; - uint32_t dot5StatsLostFrameErrors; - uint32_t dot5StatsReceiveCongestions; - uint32_t dot5StatsFrameCopiedErrors; - uint32_t dot5StatsTokenErrors; - uint32_t dot5StatsSoftErrors; - uint32_t dot5StatsHardErrors; - uint32_t dot5StatsSignalLoss; - uint32_t dot5StatsTransmitBeacons; - uint32_t dot5StatsRecoverys; - uint32_t dot5StatsLobeWires; - uint32_t dot5StatsRemoves; - uint32_t dot5StatsSingles; - uint32_t dot5StatsFreqErrors; -} SFLTokenring_counters; - -/* 100 BaseVG interface counters - see RFC 2020 */ - -typedef struct _SFLVg_counters { - uint32_t dot12InHighPriorityFrames; - uint64_t dot12InHighPriorityOctets; - uint32_t dot12InNormPriorityFrames; - uint64_t dot12InNormPriorityOctets; - uint32_t dot12InIPMErrors; - uint32_t dot12InOversizeFrameErrors; - uint32_t dot12InDataErrors; - uint32_t dot12InNullAddressedFrames; - uint32_t dot12OutHighPriorityFrames; - uint64_t dot12OutHighPriorityOctets; - uint32_t dot12TransitionIntoTrainings; - uint64_t dot12HCInHighPriorityOctets; - uint64_t dot12HCInNormPriorityOctets; - uint64_t dot12HCOutHighPriorityOctets; -} SFLVg_counters; - -typedef struct _SFLVlan_counters { - uint32_t vlan_id; - uint64_t octets; - uint32_t ucastPkts; - uint32_t multicastPkts; - uint32_t broadcastPkts; - uint32_t discards; -} SFLVlan_counters; - -/* Processor Information */ -/* opaque = counter_data; enterprise = 0; format = 1001 */ - -typedef struct _SFLProcessor_counters { - uint32_t five_sec_cpu; /* 5 second average CPU utilization */ - uint32_t one_min_cpu; /* 1 minute average CPU utilization */ - uint32_t five_min_cpu; /* 5 minute average CPU utilization */ - uint64_t total_memory; /* total memory (in bytes) */ - uint64_t free_memory; /* free memory (in bytes) */ -} SFLProcessor_counters; - -/* Counters data */ - -enum SFLCounters_type_tag { - /* enterprise = 0, format = ... */ - SFLCOUNTERS_GENERIC = 1, - SFLCOUNTERS_ETHERNET = 2, - SFLCOUNTERS_TOKENRING = 3, - SFLCOUNTERS_VG = 4, - SFLCOUNTERS_VLAN = 5, - SFLCOUNTERS_PROCESSOR = 1001 -}; - -typedef union _SFLCounters_type { - SFLIf_counters generic; - SFLEthernet_counters ethernet; - SFLTokenring_counters tokenring; - SFLVg_counters vg; - SFLVlan_counters vlan; - SFLProcessor_counters processor; -} SFLCounters_type; - -typedef struct _SFLCounters_sample_element { - struct _SFLCounters_sample_element *nxt; /* linked list */ - uint32_t tag; /* SFLCounters_type_tag */ - uint32_t length; - SFLCounters_type counterBlock; -} SFLCounters_sample_element; - -typedef struct _SFLCounters_sample { - /* uint32_t tag; */ /* SFL_sample_tag -- enterprise = 0 : format = 2 */ - /* uint32_t length; */ - uint32_t sequence_number; /* Incremented with each counters sample - generated by this source_id */ - uint32_t source_id; /* fsSourceId */ - uint32_t num_elements; - SFLCounters_sample_element *elements; -} SFLCounters_sample; - -/* same thing, but the expanded version, so ds_index can be a full 32 bits */ -typedef struct _SFLCounters_sample_expanded { - /* uint32_t tag; */ /* SFL_sample_tag -- enterprise = 0 : format = 2 */ - /* uint32_t length; */ - uint32_t sequence_number; /* Incremented with each counters sample - generated by this source_id */ - uint32_t ds_class; /* EXPANDED */ - uint32_t ds_index; /* EXPANDED */ - uint32_t num_elements; - SFLCounters_sample_element *elements; -} SFLCounters_sample_expanded; - -#define SFLADD_ELEMENT(_sm, _el) do { (_el)->nxt = (_sm)->elements; (_sm)->elements = (_el); } while(0) - -/* Format of a sample datagram */ - -enum SFLDatagram_version { - SFLDATAGRAM_VERSION2 = 2, - SFLDATAGRAM_VERSION4 = 4, - SFLDATAGRAM_VERSION5 = 5 -}; - -typedef struct _SFLSample_datagram_hdr { - uint32_t datagram_version; /* (enum SFLDatagram_version) = VERSION5 = 5 */ - SFLAddress agent_address; /* IP address of sampling agent */ - uint32_t sub_agent_id; /* Used to distinguishing between datagram - streams from separate agent sub entities - within an device. */ - uint32_t sequence_number; /* Incremented with each sample datagram - generated */ - uint32_t uptime; /* Current time (in milliseconds since device - last booted). Should be set as close to - datagram transmission time as possible.*/ - uint32_t num_records; /* Number of tag-len-val flow/counter records to follow */ -} SFLSample_datagram_hdr; - -#define SFL_MAX_DATAGRAM_SIZE 1500 -#define SFL_MIN_DATAGRAM_SIZE 200 -#define SFL_DEFAULT_DATAGRAM_SIZE 1400 - -#define SFL_DATA_PAD 400 - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -#endif /* _SFLOW_PROTO_H */ diff --git a/bin/sflow_v2v4.h b/bin/sflow_v2v4.h new file mode 100755 index 0000000..1231c10 --- /dev/null +++ b/bin/sflow_v2v4.h @@ -0,0 +1,436 @@ +/* Copyright (c) 2002-2011 InMon Corp. Licensed under the terms of the InMon sFlow licence: */ +/* http://www.inmon.com/technology/sflowlicense.txt */ + +#ifndef SFLOW_V2V4_H +#define SFLOW_V2V4_H 1 + +#if defined(__cplusplus) +extern "C" { +#endif + +enum INMAddress_type { + INMADDRESSTYPE_IP_V4 = 1, + INMADDRESSTYPE_IP_V6 = 2 +}; + +typedef union _INMAddress_value { + SFLIPv4 ip_v4; + SFLIPv6 ip_v6; +} INMAddress_value; + +typedef struct _INMAddress { + uint32_t type; /* enum INMAddress_type */ + INMAddress_value address; +} INMAddress; + +/* Packet header data */ + +#define INM_MAX_HEADER_SIZE 256 /* The maximum sampled header size. */ +#define INM_DEFAULT_HEADER_SIZE 128 +#define INM_DEFAULT_COLLECTOR_PORT 6343 +#define INM_DEFAULT_SAMPLING_RATE 400 + +/* The header protocol describes the format of the sampled header */ +enum INMHeader_protocol { + INMHEADER_ETHERNET_ISO8023 = 1, + INMHEADER_ISO88024_TOKENBUS = 2, + INMHEADER_ISO88025_TOKENRING = 3, + INMHEADER_FDDI = 4, + INMHEADER_FRAME_RELAY = 5, + INMHEADER_X25 = 6, + INMHEADER_PPP = 7, + INMHEADER_SMDS = 8, + INMHEADER_AAL5 = 9, + INMHEADER_AAL5_IP = 10, /* e.g. Cisco AAL5 mux */ + INMHEADER_IPv4 = 11, + INMHEADER_IPv6 = 12 +}; + +typedef struct _INMSampled_header { + uint32_t header_protocol; /* (enum INMHeader_protocol) */ + uint32_t frame_length; /* Original length of packet before sampling */ + uint32_t header_length; /* length of sampled header bytes to follow */ + uint8_t header[INM_MAX_HEADER_SIZE]; /* Header bytes */ +} INMSampled_header; + +/* Packet IP version 4 data */ + +typedef struct _INMSampled_ipv4 { + uint32_t length; /* The length of the IP packet + excluding lower layer encapsulations */ + uint32_t protocol; /* IP Protocol type (for example, TCP = 6, UDP = 17) */ + SFLIPv4 src_ip; /* Source IP Address */ + SFLIPv4 dst_ip; /* Destination IP Address */ + uint32_t src_port; /* TCP/UDP source port number or equivalent */ + uint32_t dst_port; /* TCP/UDP destination port number or equivalent */ + uint32_t tcp_flags; /* TCP flags */ + uint32_t tos; /* IP type of service */ +} INMSampled_ipv4; + +/* Packet IP version 6 data */ + +typedef struct _INMSampled_ipv6 { + uint32_t length; /* The length of the IP packet + excluding lower layer encapsulations */ + uint32_t protocol; /* IP Protocol type (for example, TCP = 6, UDP = 17) */ + SFLIPv6 src_ip; /* Source IP Address */ + SFLIPv6 dst_ip; /* Destination IP Address */ + uint32_t src_port; /* TCP/UDP source port number or equivalent */ + uint32_t dst_port; /* TCP/UDP destination port number or equivalent */ + uint32_t tcp_flags; /* TCP flags */ + uint32_t tos; /* IP type of service */ +} INMSampled_ipv6; + + +/* Packet data */ + +enum INMPacket_information_type { + INMPACKETTYPE_HEADER = 1, /* Packet headers are sampled */ + INMPACKETTYPE_IPV4 = 2, /* IP version 4 data */ + INMPACKETTYPE_IPV6 = 3 /* IP version 4 data */ +}; + +typedef union _INMPacket_data_type { + INMSampled_header header; + INMSampled_ipv4 ipv4; + INMSampled_ipv6 ipv6; +} INMPacket_data_type; + +/* Extended data types */ + +/* Extended switch data */ + +typedef struct _INMExtended_switch { + uint32_t src_vlan; /* The 802.1Q VLAN id of incomming frame */ + uint32_t src_priority; /* The 802.1p priority */ + uint32_t dst_vlan; /* The 802.1Q VLAN id of outgoing frame */ + uint32_t dst_priority; /* The 802.1p priority */ +} INMExtended_switch; + +/* Extended router data */ + +typedef struct _INMExtended_router { + INMAddress nexthop; /* IP address of next hop router */ + uint32_t src_mask; /* Source address prefix mask bits */ + uint32_t dst_mask; /* Destination address prefix mask bits */ +} INMExtended_router; + +/* Extended gateway data */ + +enum INMExtended_as_path_segment_type { + INMEXTENDED_AS_SET = 1, /* Unordered set of ASs */ + INMEXTENDED_AS_SEQUENCE = 2 /* Ordered sequence of ASs */ +}; + +typedef struct _INMExtended_as_path_segment { + uint32_t type; /* enum INMExtended_as_path_segment_type */ + uint32_t length; /* number of AS numbers in set/sequence */ + union { + uint32_t *set; + uint32_t *seq; + } as; +} INMExtended_as_path_segment; + +/* note: the INMExtended_gateway structure has changed between v2 and v4. + Here is the old version first... */ + +typedef struct _INMExtended_gateway_v2 { + uint32_t as; /* AS number for this gateway */ + uint32_t src_as; /* AS number of source (origin) */ + uint32_t src_peer_as; /* AS number of source peer */ + uint32_t dst_as_path_length; /* number of AS numbers in path */ + uint32_t *dst_as_path; +} INMExtended_gateway_v2; + +/* now here is the new version... */ + +typedef struct _INMExtended_gateway_v4 { + uint32_t as; /* AS number for this gateway */ + uint32_t src_as; /* AS number of source (origin) */ + uint32_t src_peer_as; /* AS number of source peer */ + uint32_t dst_as_path_segments; /* number of segments in path */ + INMExtended_as_path_segment *dst_as_path; /* list of seqs or sets */ + uint32_t communities_length; /* number of communities */ + uint32_t *communities; /* set of communities */ + uint32_t localpref; /* LocalPref associated with this route */ +} INMExtended_gateway_v4; + +/* Extended user data */ +typedef struct _INMExtended_user { + uint32_t src_user_len; + char *src_user; + uint32_t dst_user_len; + char *dst_user; +} INMExtended_user; +enum INMExtended_url_direction { + INMEXTENDED_URL_SRC = 1, /* URL is associated with source address */ + INMEXTENDED_URL_DST = 2 /* URL is associated with destination address */ +}; + +typedef struct _INMExtended_url { + uint32_t direction; /* enum INMExtended_url_direction */ + uint32_t url_len; + char *url; +} INMExtended_url; + +/* Extended data */ + +enum INMExtended_information_type { + INMEXTENDED_SWITCH = 1, /* Extended switch information */ + INMEXTENDED_ROUTER = 2, /* Extended router information */ + INMEXTENDED_GATEWAY = 3, /* Extended gateway router information */ + INMEXTENDED_USER = 4, /* Extended TACAS/RADIUS user information */ + INMEXTENDED_URL = 5 /* Extended URL information */ +}; + +/* Format of a single sample */ + +typedef struct _INMFlow_sample { + uint32_t sequence_number; /* Incremented with each flow sample + generated */ + uint32_t source_id; /* fsSourceId */ + uint32_t sampling_rate; /* fsPacketSamplingRate */ + uint32_t sample_pool; /* Total number of packets that could have been + sampled (i.e. packets skipped by sampling + process + total number of samples) */ + uint32_t drops; /* Number of times a packet was dropped due to + lack of resources */ + uint32_t input; /* SNMP ifIndex of input interface. + 0 if interface is not known. */ + uint32_t output; /* SNMP ifIndex of output interface, + 0 if interface is not known. + Set most significant bit to indicate + multiple destination interfaces + (i.e. in case of broadcast or multicast) + and set lower order bits to indicate + number of destination interfaces. + Examples: + 0x00000002 indicates ifIndex = 2 + 0x00000000 ifIndex unknown. + 0x80000007 indicates a packet sent + to 7 interfaces. + 0x80000000 indicates a packet sent to + an unknown number of + interfaces greater than 1.*/ + uint32_t packet_data_tag; /* enum INMPacket_information_type */ + INMPacket_data_type packet_data; /* Information about sampled packet */ + + /* in the sFlow packet spec the next field is the number of extended objects + followed by the data for each one (tagged with the type). Here we just + provide space for each one, and flags to enable them. The correct format + is then put together by the serialization code */ + int gotSwitch; + INMExtended_switch switchDevice; + int gotRouter; + INMExtended_router router; + int gotGateway; + union { + INMExtended_gateway_v2 v2; /* make the version explicit so that there is */ + INMExtended_gateway_v4 v4; /* less danger of mistakes when upgrading code */ + } gateway; + int gotUser; + INMExtended_user user; + int gotUrl; + INMExtended_url url; +} INMFlow_sample; + +/* Counter types */ + +/* Generic interface counters - see RFC 1573, 2233 */ + +typedef struct _INMIf_counters { + uint32_t ifIndex; + uint32_t ifType; + uint64_t ifSpeed; + uint32_t ifDirection; /* Derived from MAU MIB (RFC 2239) + 0 = unknown, 1 = full-duplex, + 2 = half-duplex, 3 = in, 4 = out */ + uint32_t ifStatus; /* bit field with the following bits assigned: + bit 0 = ifAdminStatus (0 = down, 1 = up) + bit 1 = ifOperStatus (0 = down, 1 = up) */ + uint64_t ifInOctets; + uint32_t ifInUcastPkts; + uint32_t ifInMulticastPkts; + uint32_t ifInBroadcastPkts; + uint32_t ifInDiscards; + uint32_t ifInErrors; + uint32_t ifInUnknownProtos; + uint64_t ifOutOctets; + uint32_t ifOutUcastPkts; + uint32_t ifOutMulticastPkts; + uint32_t ifOutBroadcastPkts; + uint32_t ifOutDiscards; + uint32_t ifOutErrors; + uint32_t ifPromiscuousMode; +} INMIf_counters; + +/* Ethernet interface counters - see RFC 2358 */ +typedef struct _INMEthernet_specific_counters { + uint32_t dot3StatsAlignmentErrors; + uint32_t dot3StatsFCSErrors; + uint32_t dot3StatsSingleCollisionFrames; + uint32_t dot3StatsMultipleCollisionFrames; + uint32_t dot3StatsSQETestErrors; + uint32_t dot3StatsDeferredTransmissions; + uint32_t dot3StatsLateCollisions; + uint32_t dot3StatsExcessiveCollisions; + uint32_t dot3StatsInternalMacTransmitErrors; + uint32_t dot3StatsCarrierSenseErrors; + uint32_t dot3StatsFrameTooLongs; + uint32_t dot3StatsInternalMacReceiveErrors; + uint32_t dot3StatsSymbolErrors; +} INMEthernet_specific_counters; + +typedef struct _INMEthernet_counters { + INMIf_counters generic; + INMEthernet_specific_counters ethernet; +} INMEthernet_counters; + +/* FDDI interface counters - see RFC 1512 */ +typedef struct _INMFddi_counters { + INMIf_counters generic; +} INMFddi_counters; + +/* Token ring counters - see RFC 1748 */ + +typedef struct _INMTokenring_specific_counters { + uint32_t dot5StatsLineErrors; + uint32_t dot5StatsBurstErrors; + uint32_t dot5StatsACErrors; + uint32_t dot5StatsAbortTransErrors; + uint32_t dot5StatsInternalErrors; + uint32_t dot5StatsLostFrameErrors; + uint32_t dot5StatsReceiveCongestions; + uint32_t dot5StatsFrameCopiedErrors; + uint32_t dot5StatsTokenErrors; + uint32_t dot5StatsSoftErrors; + uint32_t dot5StatsHardErrors; + uint32_t dot5StatsSignalLoss; + uint32_t dot5StatsTransmitBeacons; + uint32_t dot5StatsRecoverys; + uint32_t dot5StatsLobeWires; + uint32_t dot5StatsRemoves; + uint32_t dot5StatsSingles; + uint32_t dot5StatsFreqErrors; +} INMTokenring_specific_counters; + +typedef struct _INMTokenring_counters { + INMIf_counters generic; + INMTokenring_specific_counters tokenring; +} INMTokenring_counters; + +/* 100 BaseVG interface counters - see RFC 2020 */ + +typedef struct _INMVg_specific_counters { + uint32_t dot12InHighPriorityFrames; + uint64_t dot12InHighPriorityOctets; + uint32_t dot12InNormPriorityFrames; + uint64_t dot12InNormPriorityOctets; + uint32_t dot12InIPMErrors; + uint32_t dot12InOversizeFrameErrors; + uint32_t dot12InDataErrors; + uint32_t dot12InNullAddressedFrames; + uint32_t dot12OutHighPriorityFrames; + uint64_t dot12OutHighPriorityOctets; + uint32_t dot12TransitionIntoTrainings; + uint64_t dot12HCInHighPriorityOctets; + uint64_t dot12HCInNormPriorityOctets; + uint64_t dot12HCOutHighPriorityOctets; +} INMVg_specific_counters; + +typedef struct _INMVg_counters { + INMIf_counters generic; + INMVg_specific_counters vg; +} INMVg_counters; + +/* WAN counters */ + +typedef struct _INMWan_counters { + INMIf_counters generic; +} INMWan_counters; + +typedef struct _INMVlan_counters { + uint32_t vlan_id; + uint64_t octets; + uint32_t ucastPkts; + uint32_t multicastPkts; + uint32_t broadcastPkts; + uint32_t discards; +} INMVlan_counters; + +/* Counters data */ + +enum INMCounters_version { + INMCOUNTERSVERSION_GENERIC = 1, + INMCOUNTERSVERSION_ETHERNET = 2, + INMCOUNTERSVERSION_TOKENRING = 3, + INMCOUNTERSVERSION_FDDI = 4, + INMCOUNTERSVERSION_VG = 5, + INMCOUNTERSVERSION_WAN = 6, + INMCOUNTERSVERSION_VLAN = 7 +}; + +typedef union _INMCounters_type { + INMIf_counters generic; + INMEthernet_counters ethernet; + INMTokenring_counters tokenring; + INMFddi_counters fddi; + INMVg_counters vg; + INMWan_counters wan; + INMVlan_counters vlan; +} INMCounters_type; + +typedef struct _INMCounters_sample_hdr { + uint32_t sequence_number; /* Incremented with each counters sample + generated by this source_id */ + uint32_t source_id; /* fsSourceId */ + uint32_t sampling_interval; /* fsCounterSamplingInterval */ +} INMCounters_sample_hdr; + +typedef struct _INMCounters_sample { + INMCounters_sample_hdr hdr; + uint32_t counters_type_tag; /* Enum INMCounters_version */ + INMCounters_type counters; /* Counter set for this interface type */ +} INMCounters_sample; + +/* when I turn on optimisation with the Microsoft compiler it seems to change + the values of these enumerated types and break the program - not sure why */ +enum INMSample_types { + FLOWSAMPLE = 1, + COUNTERSSAMPLE = 2 +}; + +typedef union _INMSample_type { + INMFlow_sample flowsample; + INMCounters_sample counterssample; +} INMSample_type; + +/* Format of a sample datagram */ + +enum INMDatagram_version { + INMDATAGRAM_VERSION2 = 2, + INMDATAGRAM_VERSION4 = 4 +}; + +typedef struct _INMSample_datagram_hdr { + uint32_t datagram_version; /* (enum INMDatagram_version) = VERSION4 */ + INMAddress agent_address; /* IP address of sampling agent */ + uint32_t sequence_number; /* Incremented with each sample datagram + generated */ + uint32_t uptime; /* Current time (in milliseconds since device + last booted). Should be set as close to + datagram transmission time as possible.*/ + uint32_t num_samples; /* Number of flow and counters samples to follow */ +} INMSample_datagram_hdr; + +#define INM_MAX_DATAGRAM_SIZE 1500 +#define INM_MIN_DATAGRAM_SIZE 200 +#define INM_DEFAULT_DATAGRAM_SIZE 1400 + +#define INM_DATA_PAD 400 + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +#endif /* SFLOW_V2V4_H */