ipfix.c
/*
 * Given an array of expired flows, send netflow v9 report packets
 * Returns number of packets sent or -1 on error
 */
Given an array of expired flows, send netflow v9 report packets
Returns number of packets sent or -1 on error
Given an array of expired flows send netflow v9 report packets Returns number of packets sent or - 1 on error
int
send_ipfix(struct FLOW **flows, int num_flows, int nfsock,
		u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param,
		int verbose_flag)
{
	struct IPFIX_HEADER *ipfix;
	struct IPFIX_SET_HEADER *dh;
	struct timeval now;
	u_int offset, last_af, i, j, num_packets, inc, last_valid;
	socklen_t errsz;
	int err, r;
	u_int records;
	u_char packet[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE];
	struct timeval *system_boot_time = &param->system_boot_time;
	u_int64_t *flows_exported = &param->flows_exported;
	u_int64_t *records_sent = &param->records_sent;
	struct OPTION *option = &param->option;
	gettimeofday(&now, NULL);
	if (ipfix_pkts_until_template == -1) {
		ipfix_init_template(param);
		ipfix_pkts_until_template = 0;
		if (option != NULL){
			ipfix_init_option(system_boot_time, option);
		}
	}		
	last_valid = num_packets = 0;
	for (j = 0; j < num_flows;) {
		bzero(packet, sizeof(packet));
		ipfix = (struct IPFIX_HEADER *)packet;
		ipfix->version = htons(10);
		ipfix->length = 0; 
		ipfix->export_time = htonl(time(NULL));
		ipfix->od_id = 0;
		offset = sizeof(*ipfix);
		if (ipfix_pkts_until_template <= 0) {
			memcpy(packet + offset, &v4_template,
			    sizeof(v4_template));
			offset += sizeof(v4_template);
			memcpy(packet + offset, &v6_template,
			    sizeof(v6_template));
			offset += sizeof(v6_template);
			if (option != NULL){
				memcpy(packet + offset, &option_template,
				       sizeof(option_template));
				offset += sizeof(option_template);
				memcpy(packet + offset, &option_data,
				       sizeof(option_data));
				offset += sizeof(option_data);
			}
			ipfix_pkts_until_template = IPFIX_DEFAULT_TEMPLATE_INTERVAL;
		}
		dh = NULL;
		last_af = 0;
		records = 0;
		for (i = 0; i + j < num_flows; i++) {
			if (dh == NULL || flows[i + j]->af != last_af) {
				if (dh != NULL) {
					if (offset % 4 != 0) {
						dh->length += 4 - (offset % 4);
						offset += 4 - (offset % 4);
					}
					dh->length = htons(dh->length);
				}
				if (offset + sizeof(*dh) > sizeof(packet)) {
					dh = NULL;
					break;
				}
				dh = (struct IPFIX_SET_HEADER *)
				    (packet + offset);
				dh->set_id =
				    (flows[i + j]->af == AF_INET) ?
				    v4_template.h.r.template_id : 
				    v6_template.h.r.template_id;
				last_af = flows[i + j]->af;
				last_valid = offset;
				dh->length = sizeof(*dh); 
				offset += sizeof(*dh);
			}
			r = ipfix_flow_to_flowset(flows[i + j], packet + offset,
			    sizeof(packet) - offset, ifidx, system_boot_time, &inc, param);
			if (r <= 0) {
				if (last_valid)
					offset = last_valid;
				break;
			}
			records += (u_int)r;
			offset += inc;
			dh->length += inc;
			last_valid = 0; 
			if (verbose_flag) {
				logit(LOG_DEBUG, "Flow %d/%d: "
				    "r %d offset %d ie %04x len %d(0x%04x)",
				    r, i, j, offset, 
				    dh->set_id, dh->length, 
				    dh->length);
			}
		}
		if (dh != NULL) {
			if (offset % 4 != 0) {
				dh->length += 4 - (offset % 4);
				offset += 4 - (offset % 4);
			}
			dh->length = htons(dh->length);
		}
		ipfix->length = htons(offset);
		*records_sent += records;
		ipfix->sequence = htonl((u_int32_t)(*records_sent & 0x00000000ffffffff));
		if (verbose_flag)
			logit(LOG_DEBUG, "Sending flow packet len = %d", offset);
		errsz = sizeof(err);
		getsockopt(nfsock, SOL_SOCKET, SO_ERROR, &err, &errsz); 
		if (send(nfsock, packet, (size_t)offset, 0) == -1)
			return (-1);
		num_packets++;
		ipfix_pkts_until_template--;
		j += i;
	}
	*flows_exported += j;
	return (num_packets);
}
int send_ipfix ( struct FLOW * * flows , int num_flows , int nfsock , u_int16_t ifidx , struct FLOWTRACKPARAMETERS * param , int verbose_flag ) { struct IPFIX_HEADER * ipfix ; struct IPFIX_SET_HEADER * dh ; struct timeval now ; u_int offset , last_af , i , j , num_packets , inc , last_valid ; socklen_t errsz ; int err , r ; u_int records ; u_char packet [ IPFIX_SOFTFLOWD_MAX_PACKET_SIZE ] ; struct timeval * system_boot_time = & param -> system_boot_time ; u_int64_t * flows_exported = & param -> flows_exported ; u_int64_t * records_sent = & param -> records_sent ; struct OPTION * option = & param -> option ; gettimeofday ( & now , NULL ) ; if ( ipfix_pkts_until_template == -1 ) { ipfix_init_template ( param ) ; ipfix_pkts_until_template = 0 ; if ( option != NULL ) { ipfix_init_option ( system_boot_time , option ) ; } } last_valid = num_packets = 0 ; for ( j = 0 ; j < num_flows ; ) { bzero ( packet , sizeof ( packet ) ) ; ipfix = ( struct IPFIX_HEADER * ) packet ; ipfix -> version = htons ( 10 ) ; ipfix -> length = 0 ; ipfix -> export_time = htonl ( time ( NULL ) ) ; ipfix -> od_id = 0 ; offset = sizeof ( * ipfix ) ; if ( ipfix_pkts_until_template <= 0 ) { memcpy ( packet + offset , & v4_template , sizeof ( v4_template ) ) ; offset += sizeof ( v4_template ) ; memcpy ( packet + offset , & v6_template , sizeof ( v6_template ) ) ; offset += sizeof ( v6_template ) ; if ( option != NULL ) { memcpy ( packet + offset , & option_template , sizeof ( option_template ) ) ; offset += sizeof ( option_template ) ; memcpy ( packet + offset , & option_data , sizeof ( option_data ) ) ; offset += sizeof ( option_data ) ; } ipfix_pkts_until_template = IPFIX_DEFAULT_TEMPLATE_INTERVAL ; } dh = NULL ; last_af = 0 ; records = 0 ; for ( i = 0 ; i + j < num_flows ; i ++ ) { if ( dh == NULL || flows [ i + j ] -> af != last_af ) { if ( dh != NULL ) { if ( offset % 4 != 0 ) { dh -> length += 4 - ( offset % 4 ) ; offset += 4 - ( offset % 4 ) ; } dh -> length = htons ( dh -> length ) ; } if ( offset + sizeof ( * dh ) > sizeof ( packet ) ) { dh = NULL ; break ; } dh = ( struct IPFIX_SET_HEADER * ) ( packet + offset ) ; dh -> set_id = ( flows [ i + j ] -> af == AF_INET ) ? v4_template . h . r . template_id : v6_template . h . r . template_id ; last_af = flows [ i + j ] -> af ; last_valid = offset ; dh -> length = sizeof ( * dh ) ; offset += sizeof ( * dh ) ; } r = ipfix_flow_to_flowset ( flows [ i + j ] , packet + offset , sizeof ( packet ) - offset , ifidx , system_boot_time , & inc , param ) ; if ( r <= 0 ) { if ( last_valid ) offset = last_valid ; break ; } records += ( u_int ) r ; offset += inc ; dh -> length += inc ; last_valid = 0 ; if ( verbose_flag ) { logit ( LOG_DEBUG , " " " " , r , i , j , offset , dh -> set_id , dh -> length , dh -> length ) ; } } if ( dh != NULL ) { if ( offset % 4 != 0 ) { dh -> length += 4 - ( offset % 4 ) ; offset += 4 - ( offset % 4 ) ; } dh -> length = htons ( dh -> length ) ; } ipfix -> length = htons ( offset ) ; * records_sent += records ; ipfix -> sequence = htonl ( ( u_int32_t ) ( * records_sent & 0x00000000ffffffff ) ) ; if ( verbose_flag ) logit ( LOG_DEBUG , " " , offset ) ; errsz = sizeof ( err ) ; getsockopt ( nfsock , SOL_SOCKET , SO_ERROR , & err , & errsz ) ; if ( send ( nfsock , packet , ( size_t ) offset , 0 ) == -1 ) return ( -1 ) ; num_packets ++ ; ipfix_pkts_until_template -- ; j += i ; } * flows_exported += j ; return ( num_packets ) ; }
Given an array of expired flows, send netflow v9 report packets
 Returns number of packets sent or -1 on error
Given an array of expired flows send netflow v9 report packets Returns number of packets sent or - 1 on error
/* Filled as we go, htons at end */ /* Refresh template headers if we need to */ /* Pad to multiple of 4 */ /* Finalise last header */ /* Mark header is finished */ /* Filled as we go */ /* yank off data header, if we had to go back */ /* Don't clobber this header now */ /* Don't finish header if it has already been done */ /* Pad to multiple of 4 */ /* Finalise last header */ /* Clear ICMP errors */