Subject: Fix bug. The sequence number field in NetFlow version 9 is number of exported packets. Older version used number of exported flows for this field Origin: softflowd-0.9.9-3-gbd8e31e Upstream-Author: Hitoshi Irino Date: Sat Sep 29 22:35:18 2012 +0900 --- a/netflow1.c +++ b/netflow1.c @@ -60,9 +60,9 @@ * Returns number of packets sent or -1 on error */ int -send_netflow_v1(struct FLOW **flows, int num_flows, int nfsock, u_int16_t ifidx, - u_int64_t *flows_exported, struct timeval *system_boot_time, - int verbose_flag, struct OPTION *option) +send_netflow_v1(struct FLOW **flows, int num_flows, int nfsock, + u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, + int verbose_flag) { struct timeval now; u_int32_t uptime_ms; @@ -71,6 +71,8 @@ struct NF1_FLOW *flw = NULL; int i, j, offset, num_packets, err; socklen_t errsz; + struct timeval *system_boot_time = ¶m->system_boot_time; + u_int64_t *flows_exported = ¶m->flows_exported; gettimeofday(&now, NULL); uptime_ms = timeval_sub_ms(&now, system_boot_time); --- a/netflow5.c +++ b/netflow5.c @@ -59,9 +59,9 @@ * Returns number of packets sent or -1 on error */ int -send_netflow_v5(struct FLOW **flows, int num_flows, int nfsock, u_int16_t ifidx, - u_int64_t *flows_exported, struct timeval *system_boot_time, - int verbose_flag, struct OPTION *option) +send_netflow_v5(struct FLOW **flows, int num_flows, int nfsock, + u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, + int verbose_flag) { struct timeval now; u_int32_t uptime_ms; @@ -70,6 +70,9 @@ struct NF5_FLOW *flw = NULL; int i, j, offset, num_packets, err; socklen_t errsz; + struct timeval *system_boot_time = ¶m->system_boot_time; + u_int64_t *flows_exported = ¶m->flows_exported; + struct OPTION *option = ¶m->option; gettimeofday(&now, NULL); uptime_ms = timeval_sub_ms(&now, system_boot_time); --- a/netflow9.c +++ b/netflow9.c @@ -316,9 +316,9 @@ * Returns number of packets sent or -1 on error */ int -send_netflow_v9(struct FLOW **flows, int num_flows, int nfsock, u_int16_t ifidx, - u_int64_t *flows_exported, struct timeval *system_boot_time, - int verbose_flag, struct OPTION *option) +send_netflow_v9(struct FLOW **flows, int num_flows, int nfsock, + u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, + int verbose_flag) { struct NF9_HEADER *nf9; struct NF9_DATA_FLOWSET_HEADER *dh; @@ -327,6 +327,10 @@ socklen_t errsz; int err, r; u_char packet[NF9_SOFTFLOWD_MAX_PACKET_SIZE]; + struct timeval *system_boot_time = ¶m->system_boot_time; + u_int64_t *flows_exported = ¶m->flows_exported; + u_int64_t *packets_sent = ¶m->packets_sent; + struct OPTION *option = ¶m->option; gettimeofday(&now, NULL); @@ -347,7 +351,6 @@ nf9->flows = 0; /* Filled as we go, htons at end */ nf9->uptime_ms = htonl(timeval_sub_ms(&now, system_boot_time)); nf9->time_sec = htonl(time(NULL)); - nf9->package_sequence = htonl(*flows_exported + j); nf9->source_id = 0; offset = sizeof(*nf9); @@ -432,6 +435,7 @@ dh->c.length = htons(dh->c.length); } nf9->flows = htons(nf9->flows); + nf9->package_sequence = htonl(*packets_sent + num_packets + 1); if (verbose_flag) logit(LOG_DEBUG, "Sending flow packet len = %d", offset); --- a/softflowd.c +++ b/softflowd.c @@ -95,7 +95,7 @@ /* Netflow send functions */ typedef int (netflow_send_func_t)(struct FLOW **, int, int, u_int16_t, - u_int64_t *, struct timeval *, int, struct OPTION *); + struct FLOWTRACKPARAMETERS *, int); struct NETFLOW_SENDER { int version; netflow_send_func_t *func; @@ -459,9 +459,9 @@ } /* Flows over maximum life seconds */ - if (ft->maximum_lifetime != 0 && + if (ft->param.maximum_lifetime != 0 && flow->flow_last.tv_sec - flow->flow_start.tv_sec > - ft->maximum_lifetime) { + ft->param.maximum_lifetime) { flow->expiry->expires_at = 0; flow->expiry->reason = R_MAXLIFE; goto out; @@ -469,60 +469,60 @@ if (flow->protocol == IPPROTO_TCP) { /* Reset TCP flows */ - if (ft->tcp_rst_timeout != 0 && + if (ft->param.tcp_rst_timeout != 0 && ((flow->tcp_flags[0] & TH_RST) || (flow->tcp_flags[1] & TH_RST))) { flow->expiry->expires_at = flow->flow_last.tv_sec + - ft->tcp_rst_timeout; + ft->param.tcp_rst_timeout; flow->expiry->reason = R_TCP_RST; goto out; } /* Finished TCP flows */ - if (ft->tcp_fin_timeout != 0 && + if (ft->param.tcp_fin_timeout != 0 && ((flow->tcp_flags[0] & TH_FIN) && (flow->tcp_flags[1] & TH_FIN))) { flow->expiry->expires_at = flow->flow_last.tv_sec + - ft->tcp_fin_timeout; + ft->param.tcp_fin_timeout; flow->expiry->reason = R_TCP_FIN; goto out; } /* TCP flows */ - if (ft->tcp_timeout != 0) { + if (ft->param.tcp_timeout != 0) { flow->expiry->expires_at = flow->flow_last.tv_sec + - ft->tcp_timeout; + ft->param.tcp_timeout; flow->expiry->reason = R_TCP; goto out; } } - if (ft->udp_timeout != 0 && flow->protocol == IPPROTO_UDP) { + if (ft->param.udp_timeout != 0 && flow->protocol == IPPROTO_UDP) { /* UDP flows */ flow->expiry->expires_at = flow->flow_last.tv_sec + - ft->udp_timeout; + ft->param.udp_timeout; flow->expiry->reason = R_UDP; goto out; } - if (ft->icmp_timeout != 0 && + if (ft->param.icmp_timeout != 0 && ((flow->af == AF_INET && flow->protocol == IPPROTO_ICMP) || ((flow->af == AF_INET6 && flow->protocol == IPPROTO_ICMPV6)))) { /* ICMP flows */ flow->expiry->expires_at = flow->flow_last.tv_sec + - ft->icmp_timeout; + ft->param.icmp_timeout; flow->expiry->reason = R_ICMP; goto out; } /* Everything else */ flow->expiry->expires_at = flow->flow_last.tv_sec + - ft->general_timeout; + ft->param.general_timeout; flow->expiry->reason = R_GENERAL; out: - if (ft->maximum_lifetime != 0 && flow->expiry->expires_at != 0) { + if (ft->param.maximum_lifetime != 0 && flow->expiry->expires_at != 0) { flow->expiry->expires_at = MIN(flow->expiry->expires_at, - flow->flow_start.tv_sec + ft->maximum_lifetime); + flow->flow_start.tv_sec + ft->param.maximum_lifetime); } EXPIRY_INSERT(EXPIRIES, &ft->expiries, flow->expiry); @@ -550,7 +550,7 @@ struct FLOW tmp, *flow; int frag; - ft->total_packets++; + ft->param.total_packets++; /* Convert the IP packet to a flow identity */ memset(&tmp, 0, sizeof(tmp)); @@ -565,15 +565,15 @@ break; default: bad: - ft->bad_packets++; + ft->param.bad_packets++; return (PP_BAD_PACKET); } if (frag) - ft->frag_packets++; + ft->param.frag_packets++; /* Zero out bits of the flow that aren't relevant to tracking level */ - switch (ft->track_level) { + switch (ft->param.track_level) { case TRACK_IP_ONLY: tmp.protocol = 0; /* FALLTHROUGH */ @@ -596,7 +596,7 @@ memcpy(flow, &tmp, sizeof(*flow)); memcpy(&flow->flow_start, received_time, sizeof(flow->flow_start)); - flow->flow_seq = ft->next_flow_seq++; + flow->flow_seq = ft->param.next_flow_seq++; FLOW_INSERT(FLOWS, &ft->flows, flow); /* Allocate and fill in the associated expiry event */ @@ -611,7 +611,7 @@ flow->expiry->reason = R_GENERAL; EXPIRY_INSERT(EXPIRIES, &ft->expiries, flow->expiry); - ft->num_flows++; + ft->param.num_flows++; if (verbose_flag) logit(LOG_DEBUG, "ADD FLOW %s", format_flow_brief(flow)); @@ -671,8 +671,8 @@ double tmp; static double n = 1.0; - ft->flows_expired++; - ft->flows_pp[flow->protocol % 256]++; + ft->param.flows_expired++; + ft->param.flows_pp[flow->protocol % 256]++; tmp = (double)flow->flow_last.tv_sec + ((double)flow->flow_last.tv_usec / 1000000.0); @@ -681,17 +681,17 @@ if (tmp < 0.0) tmp = 0.0; - update_statistic(&ft->duration, tmp, n); - update_statistic(&ft->duration_pp[flow->protocol], tmp, - (double)ft->flows_pp[flow->protocol % 256]); + update_statistic(&ft->param.duration, tmp, n); + update_statistic(&ft->param.duration_pp[flow->protocol], tmp, + (double)ft->param.flows_pp[flow->protocol % 256]); tmp = flow->octets[0] + flow->octets[1]; - update_statistic(&ft->octets, tmp, n); - ft->octets_pp[flow->protocol % 256] += tmp; + update_statistic(&ft->param.octets, tmp, n); + ft->param.octets_pp[flow->protocol % 256] += tmp; tmp = flow->packets[0] + flow->packets[1]; - update_statistic(&ft->packets, tmp, n); - ft->packets_pp[flow->protocol % 256] += tmp; + update_statistic(&ft->param.packets, tmp, n); + ft->param.packets_pp[flow->protocol % 256] += tmp; n++; } @@ -701,34 +701,34 @@ { switch (e->reason) { case R_GENERAL: - ft->expired_general++; + ft->param.expired_general++; break; case R_TCP: - ft->expired_tcp++; + ft->param.expired_tcp++; break; case R_TCP_RST: - ft->expired_tcp_rst++; + ft->param.expired_tcp_rst++; break; case R_TCP_FIN: - ft->expired_tcp_fin++; + ft->param.expired_tcp_fin++; break; case R_UDP: - ft->expired_udp++; + ft->param.expired_udp++; break; case R_ICMP: - ft->expired_icmp++; + ft->param.expired_icmp++; break; case R_MAXLIFE: - ft->expired_maxlife++; + ft->param.expired_maxlife++; break; case R_OVERBYTES: - ft->expired_overbytes++; + ft->param.expired_overbytes++; break; case R_OVERFLOWS: - ft->expired_maxflows++; + ft->param.expired_maxflows++; break; case R_FLUSH: - ft->expired_flush++; + ft->param.expired_flush++; break; } } @@ -754,9 +754,9 @@ return (0); /* Now */ /* Cluster expiries by expiry_interval */ - if (ft->expiry_interval > 1) { - if ((fudge = expires_at % ft->expiry_interval) > 0) - expires_at += ft->expiry_interval - fudge; + if (ft->param.expiry_interval > 1) { + if ((fudge = expires_at % ft->param.expiry_interval) > 0) + expires_at += ft->param.expiry_interval - fudge; } if (expires_at < now.tv_sec) @@ -799,10 +799,10 @@ (expiry->expires_at < now.tv_sec))) { /* Flow has expired */ - if (ft->maximum_lifetime != 0 && + if (ft->param.maximum_lifetime != 0 && expiry->flow->flow_last.tv_sec - expiry->flow->flow_start.tv_sec >= - ft->maximum_lifetime) + ft->param.maximum_lifetime) expiry->reason = R_MAXLIFE; if (verbose_flag) @@ -834,7 +834,7 @@ expiry->flow->expiry = NULL; expiry_put(ft, expiry); - ft->num_flows--; + ft->param.num_flows--; } } @@ -846,15 +846,14 @@ if (num_expired > 0) { if (target != NULL && target->fd != -1) { r = target->dialect->func(expired_flows, num_expired, - target->fd, if_index, &ft->flows_exported, - &ft->system_boot_time, verbose_flag, &ft->option); + target->fd, if_index, &ft->param, verbose_flag); if (verbose_flag) logit(LOG_DEBUG, "sent %d netflow packets", r); if (r > 0) { - ft->packets_sent += r; + ft->param.packets_sent += r; /* XXX what if r < num_expired * 2 ? */ } else { - ft->flows_dropped += num_expired * 2; + ft->param.flows_dropped += num_expired * 2; } } for (i = 0; i < num_expired; i++) { @@ -906,7 +905,7 @@ EXPIRY_FOREACH(expiry, EXPIRIES, &ft->expiries) { expiry->expires_at = 0; expiry->reason = R_OVERFLOWS; - ft->flows_force_expired++; + ft->param.flows_force_expired++; } return; } @@ -930,7 +929,7 @@ expiryv[i]->reason = R_OVERFLOWS; EXPIRY_INSERT(EXPIRIES, &ft->expiries, expiryv[i]); } - ft->flows_force_expired += num_to_expire; + ft->param.flows_force_expired += num_to_expire; free(expiryv); /* XXX - this is overcomplicated, perhaps use a separate queue */ } @@ -950,7 +949,7 @@ EXPIRY_REMOVE(EXPIRIES, &ft->expiries, flow->expiry); expiry_put(ft, flow->expiry); - ft->num_flows--; + ft->param.num_flows--; flow_put(ft, flow); i++; } @@ -971,18 +970,18 @@ char proto[32]; struct pcap_stat ps; - fprintf(out, "Number of active flows: %d\n", ft->num_flows); - fprintf(out, "Packets processed: %"PRIu64"\n", ft->total_packets); - if (ft->non_sampled_packets) + fprintf(out, "Number of active flows: %d\n", ft->param.num_flows); + fprintf(out, "Packets processed: %"PRIu64"\n", ft->param.total_packets); + if (ft->param.non_sampled_packets) fprintf(out, "Packets non-sampled: %"PRIu64"\n", - ft->non_sampled_packets); - fprintf(out, "Fragments: %"PRIu64"\n", ft->frag_packets); + ft->param.non_sampled_packets); + fprintf(out, "Fragments: %"PRIu64"\n", ft->param.frag_packets); fprintf(out, "Ignored packets: %"PRIu64" (%"PRIu64" non-IP, %"PRIu64" too short)\n", - ft->non_ip_packets + ft->bad_packets, ft->non_ip_packets, ft->bad_packets); + ft->param.non_ip_packets + ft->param.bad_packets, ft->param.non_ip_packets, ft->param.bad_packets); fprintf(out, "Flows expired: %"PRIu64" (%"PRIu64" forced)\n", - ft->flows_expired, ft->flows_force_expired); + ft->param.flows_expired, ft->param.flows_force_expired); fprintf(out, "Flows exported: %"PRIu64" in %"PRIu64" packets (%"PRIu64" failures)\n", - ft->flows_exported, ft->packets_sent, ft->flows_dropped); + ft->param.flows_exported, ft->param.packets_sent, ft->param.flows_dropped); if (pcap_stats(pcap, &ps) == 0) { fprintf(out, "Packets received by libpcap: %lu\n", @@ -995,43 +994,43 @@ fprintf(out, "\n"); - if (ft->flows_expired != 0) { + if (ft->param.flows_expired != 0) { fprintf(out, "Expired flow statistics: minimum average maximum\n"); fprintf(out, " Flow bytes: %12.0f %12.0f %12.0f\n", - ft->octets.min, ft->octets.mean, ft->octets.max); + ft->param.octets.min, ft->param.octets.mean, ft->param.octets.max); fprintf(out, " Flow packets: %12.0f %12.0f %12.0f\n", - ft->packets.min, ft->packets.mean, ft->packets.max); + ft->param.packets.min, ft->param.packets.mean, ft->param.packets.max); fprintf(out, " Duration: %12.2fs %12.2fs %12.2fs\n", - ft->duration.min, ft->duration.mean, ft->duration.max); + ft->param.duration.min, ft->param.duration.mean, ft->param.duration.max); fprintf(out, "\n"); fprintf(out, "Expired flow reasons:\n"); fprintf(out, " tcp = %9"PRIu64" tcp.rst = %9"PRIu64" " - "tcp.fin = %9"PRIu64"\n", ft->expired_tcp, ft->expired_tcp_rst, - ft->expired_tcp_fin); + "tcp.fin = %9"PRIu64"\n", ft->param.expired_tcp, ft->param.expired_tcp_rst, + ft->param.expired_tcp_fin); fprintf(out, " udp = %9"PRIu64" icmp = %9"PRIu64" " - "general = %9"PRIu64"\n", ft->expired_udp, ft->expired_icmp, - ft->expired_general); - fprintf(out, " maxlife = %9"PRIu64"\n", ft->expired_maxlife); - fprintf(out, "over 2 GiB = %9"PRIu64"\n", ft->expired_overbytes); - fprintf(out, " maxflows = %9"PRIu64"\n", ft->expired_maxflows); - fprintf(out, " flushed = %9"PRIu64"\n", ft->expired_flush); + "general = %9"PRIu64"\n", ft->param.expired_udp, ft->param.expired_icmp, + ft->param.expired_general); + fprintf(out, " maxlife = %9"PRIu64"\n", ft->param.expired_maxlife); + fprintf(out, "over 2 GiB = %9"PRIu64"\n", ft->param.expired_overbytes); + fprintf(out, " maxflows = %9"PRIu64"\n", ft->param.expired_maxflows); + fprintf(out, " flushed = %9"PRIu64"\n", ft->param.expired_flush); fprintf(out, "\n"); fprintf(out, "Per-protocol statistics: Octets " "Packets Avg Life Max Life\n"); for(i = 0; i < 256; i++) { - if (ft->packets_pp[i]) { + if (ft->param.packets_pp[i]) { pe = getprotobynumber(i); snprintf(proto, sizeof(proto), "%s (%d)", pe != NULL ? pe->p_name : "Unknown", i); fprintf(out, " %17s: %14"PRIu64" %12"PRIu64" %8.2fs " "%10.2fs\n", proto, - ft->octets_pp[i], - ft->packets_pp[i], - ft->duration_pp[i].mean, - ft->duration_pp[i].max); + ft->param.octets_pp[i], + ft->param.packets_pp[i], + ft->param.duration_pp[i].mean, + ft->param.duration_pp[i].max); } } } @@ -1127,16 +1126,16 @@ struct CB_CTXT *cb_ctxt = (struct CB_CTXT *)user_data; struct timeval tv; - if (cb_ctxt->ft->option.sample && - (cb_ctxt->ft->total_packets + - cb_ctxt->ft->non_sampled_packets) % - cb_ctxt->ft->option.sample > 0) { - cb_ctxt->ft->non_sampled_packets++; + if (cb_ctxt->ft->param.option.sample && + (cb_ctxt->ft->param.total_packets + + cb_ctxt->ft->param.non_sampled_packets) % + cb_ctxt->ft->param.option.sample > 0) { + cb_ctxt->ft->param.non_sampled_packets++; return; } s = datalink_check(cb_ctxt->linktype, pkt, phdr->caplen, &af); if (s < 0 || (!cb_ctxt->want_v6 && af == AF_INET6)) { - cb_ctxt->ft->non_ip_packets++; + cb_ctxt->ft->param.non_ip_packets++; } else { tv.tv_sec = phdr->ts.tv_sec; tv.tv_usec = phdr->ts.tv_usec; @@ -1149,14 +1148,14 @@ static void print_timeouts(struct FLOWTRACK *ft, FILE *out) { - fprintf(out, " TCP timeout: %ds\n", ft->tcp_timeout); - fprintf(out, " TCP post-RST timeout: %ds\n", ft->tcp_rst_timeout); - fprintf(out, " TCP post-FIN timeout: %ds\n", ft->tcp_fin_timeout); - fprintf(out, " UDP timeout: %ds\n", ft->udp_timeout); - fprintf(out, " ICMP timeout: %ds\n", ft->icmp_timeout); - fprintf(out, " General timeout: %ds\n", ft->general_timeout); - fprintf(out, " Maximum lifetime: %ds\n", ft->maximum_lifetime); - fprintf(out, " Expiry interval: %ds\n", ft->expiry_interval); + fprintf(out, " TCP timeout: %ds\n", ft->param.tcp_timeout); + fprintf(out, " TCP post-RST timeout: %ds\n", ft->param.tcp_rst_timeout); + fprintf(out, " TCP post-FIN timeout: %ds\n", ft->param.tcp_fin_timeout); + fprintf(out, " UDP timeout: %ds\n", ft->param.udp_timeout); + fprintf(out, " ICMP timeout: %ds\n", ft->param.icmp_timeout); + fprintf(out, " General timeout: %ds\n", ft->param.general_timeout); + fprintf(out, " Maximum lifetime: %ds\n", ft->param.maximum_lifetime); + fprintf(out, " Expiry interval: %ds\n", ft->param.expiry_interval); } static int @@ -1226,7 +1225,7 @@ } else if (strcmp(buf, "statistics") == 0) { fprintf(ctlf, "softflowd[%u]: Accumulated statistics " "since %s UTC:\n", (unsigned int)getpid(), - format_time(ft->system_boot_time.tv_sec)); + format_time(ft->param.system_boot_time.tv_sec)); statistics(ft, ctlf, pcap); ret = 0; } else if (strcmp(buf, "debug+") == 0) { @@ -1430,25 +1429,25 @@ { /* Set up flow-tracking structure */ memset(ft, '\0', sizeof(*ft)); - ft->next_flow_seq = 1; + ft->param.next_flow_seq = 1; FLOW_INIT(&ft->flows); EXPIRY_INIT(&ft->expiries); freelist_init(&ft->flow_freelist, sizeof(struct FLOW)); freelist_init(&ft->expiry_freelist, sizeof(struct EXPIRY)); - ft->max_flows = DEFAULT_MAX_FLOWS; + ft->param.max_flows = DEFAULT_MAX_FLOWS; - ft->track_level = TRACK_FULL; + ft->param.track_level = TRACK_FULL; - ft->tcp_timeout = DEFAULT_TCP_TIMEOUT; - ft->tcp_rst_timeout = DEFAULT_TCP_RST_TIMEOUT; - ft->tcp_fin_timeout = DEFAULT_TCP_FIN_TIMEOUT; - ft->udp_timeout = DEFAULT_UDP_TIMEOUT; - ft->icmp_timeout = DEFAULT_ICMP_TIMEOUT; - ft->general_timeout = DEFAULT_GENERAL_TIMEOUT; - ft->maximum_lifetime = DEFAULT_MAXIMUM_LIFETIME; - ft->expiry_interval = DEFAULT_EXPIRY_INTERVAL; + ft->param.tcp_timeout = DEFAULT_TCP_TIMEOUT; + ft->param.tcp_rst_timeout = DEFAULT_TCP_RST_TIMEOUT; + ft->param.tcp_fin_timeout = DEFAULT_TCP_FIN_TIMEOUT; + ft->param.udp_timeout = DEFAULT_UDP_TIMEOUT; + ft->param.icmp_timeout = DEFAULT_ICMP_TIMEOUT; + ft->param.general_timeout = DEFAULT_GENERAL_TIMEOUT; + ft->param.maximum_lifetime = DEFAULT_MAXIMUM_LIFETIME; + ft->param.expiry_interval = DEFAULT_EXPIRY_INTERVAL; } static char * @@ -1546,28 +1545,28 @@ exit(1); } if (strcmp(name, "tcp") == 0) - ft->tcp_timeout = timeout; + ft->param.tcp_timeout = timeout; else if (strcmp(name, "tcp.rst") == 0) - ft->tcp_rst_timeout = timeout; + ft->param.tcp_rst_timeout = timeout; else if (strcmp(name, "tcp.fin") == 0) - ft->tcp_fin_timeout = timeout; + ft->param.tcp_fin_timeout = timeout; else if (strcmp(name, "udp") == 0) - ft->udp_timeout = timeout; + ft->param.udp_timeout = timeout; else if (strcmp(name, "icmp") == 0) - ft->icmp_timeout = timeout; + ft->param.icmp_timeout = timeout; else if (strcmp(name, "general") == 0) - ft->general_timeout = timeout; + ft->param.general_timeout = timeout; else if (strcmp(name, "maxlife") == 0) - ft->maximum_lifetime = timeout; + ft->param.maximum_lifetime = timeout; else if (strcmp(name, "expint") == 0) - ft->expiry_interval = timeout; + ft->param.expiry_interval = timeout; else { fprintf(stderr, "Invalid -t name.\n"); usage(); exit(1); } - if (ft->general_timeout == 0) { + if (ft->param.general_timeout == 0) { fprintf(stderr, "\"general\" flow timeout must be " "greater than zero\n"); exit(1); @@ -1765,11 +1764,11 @@ break; case 'T': if (strcasecmp(optarg, "full") == 0) - flowtrack.track_level = TRACK_FULL; + flowtrack.param.track_level = TRACK_FULL; else if (strcasecmp(optarg, "proto") == 0) - flowtrack.track_level = TRACK_IP_PROTO; + flowtrack.param.track_level = TRACK_IP_PROTO; else if (strcasecmp(optarg, "ip") == 0) - flowtrack.track_level = TRACK_IP_ONLY; + flowtrack.param.track_level = TRACK_IP_ONLY; else { fprintf(stderr, "Unknown flow tracking " "level\n"); @@ -1786,7 +1785,7 @@ } break; case 'm': - if ((flowtrack.max_flows = atoi(optarg)) < 0) { + if ((flowtrack.param.max_flows = atoi(optarg)) < 0) { fprintf(stderr, "Invalid maximum flows\n\n"); usage(); exit(1); @@ -1819,9 +1818,9 @@ target.dialect = &nf[i]; break; case 's': - flowtrack.option.sample = atoi(optarg); - if (flowtrack.option.sample < 2) { - flowtrack.option.sample = 0; + flowtrack.param.option.sample = atoi(optarg); + if (flowtrack.param.option.sample < 2) { + flowtrack.param.option.sample = 0; } break; default: @@ -1891,7 +1890,7 @@ } /* Main processing loop */ - gettimeofday(&flowtrack.system_boot_time, NULL); + gettimeofday(&flowtrack.param.system_boot_time, NULL); stop_collection_flag = 0; memset(&cb_ctxt, '\0', sizeof(cb_ctxt)); cb_ctxt.ft = &flowtrack; @@ -1935,7 +1934,7 @@ /* If we have data, run it through libpcap */ if (!stop_collection_flag && (capfile != NULL || pl[0].revents != 0)) { - r = pcap_dispatch(pcap, flowtrack.max_flows, flow_cb, + r = pcap_dispatch(pcap, flowtrack.param.max_flows, flow_cb, (void*)&cb_ctxt); if (r == -1) { logit(LOG_ERR, "Exiting on pcap_dispatch: %s", @@ -1961,7 +1960,7 @@ * or whenever we have exceeded the maximum number of active * flows */ - if (flowtrack.num_flows > flowtrack.max_flows || + if (flowtrack.param.num_flows > flowtrack.param.max_flows || next_expire(&flowtrack) == 0) { expiry_check: /* @@ -1978,9 +1977,9 @@ * If we are over max_flows, force-expire the oldest * out first and immediately reprocess to evict them */ - if (flowtrack.num_flows > flowtrack.max_flows) { + if (flowtrack.param.num_flows > flowtrack.param.max_flows) { force_expire(&flowtrack, - flowtrack.num_flows - flowtrack.max_flows); + flowtrack.param.num_flows - flowtrack.param.max_flows); goto expiry_check; } } --- a/softflowd.h +++ b/softflowd.h @@ -80,19 +80,8 @@ struct OPTION { uint32_t sample; }; -/* - * This structure is the root of the flow tracking system. - * It holds the root of the tree of active flows and the head of the - * tree of expiry events. It also collects miscellaneous statistics - */ -struct FLOWTRACK { - /* The flows and their expiry events */ - FLOW_HEAD(FLOWS, FLOW) flows; /* Top of flow tree */ - EXPIRY_HEAD(EXPIRIES, EXPIRY) expiries; /* Top of expiries tree */ - - struct freelist flow_freelist; /* Freelist for flows */ - struct freelist expiry_freelist; /* Freelist for expiry events */ +struct FLOWTRACKPARAMETERS { unsigned int num_flows; /* # of active flows */ unsigned int max_flows; /* Max # of active flows */ u_int64_t next_flow_seq; /* Next flow ID */ @@ -147,6 +136,21 @@ /* Optional information */ struct OPTION option; }; +/* + * This structure is the root of the flow tracking system. + * It holds the root of the tree of active flows and the head of the + * tree of expiry events. It also collects miscellaneous statistics + */ +struct FLOWTRACK { + /* The flows and their expiry events */ + FLOW_HEAD(FLOWS, FLOW) flows; /* Top of flow tree */ + EXPIRY_HEAD(EXPIRIES, EXPIRY) expiries; /* Top of expiries tree */ + + struct freelist flow_freelist; /* Freelist for flows */ + struct freelist expiry_freelist; /* Freelist for expiry events */ + + struct FLOWTRACKPARAMETERS param; +}; /* * This structure is an entry in the tree of flows that we are @@ -212,14 +216,14 @@ /* Prototypes for functions to send NetFlow packets, from netflow*.c */ int send_netflow_v1(struct FLOW **flows, int num_flows, int nfsock, - u_int16_t ifidx, u_int64_t *flows_exported, struct timeval *system_boot_time, - int verbose_flag, struct OPTION *option); + u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, + int verbose_flag); int send_netflow_v5(struct FLOW **flows, int num_flows, int nfsock, - u_int16_t ifidx, u_int64_t *flows_exported, struct timeval *system_boot_time, - int verbose_flag, struct OPTION *option); + u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, + int verbose_flag); int send_netflow_v9(struct FLOW **flows, int num_flows, int nfsock, - u_int16_t ifidx, u_int64_t *flows_exported, struct timeval *system_boot_time, - int verbose_flag, struct OPTION *option); + u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, + int verbose_flag); /* Force a resend of the flow template */ void netflow9_resend_template(void);