/* 1600, Wed 3 Jun 98 X_NM_RC.C: An X/Motif remote display console for NeTraMet Copyright (C) 1992-2002 by Nevil Brownlee, CAIDA | University of Auckland */ /* * $Log: x_nm_rc.c,v $ * Revision 1.1.1.2.2.9 2002/02/23 01:57:23 nevil * Moving srl examples to examples/ directory. Modified examples/Makefile.in * * Revision 1.1.1.2.2.5 2000/08/08 19:44:47 nevil * 44b8 release * * Revision 1.1.1.2.2.3 2000/06/06 03:38:14 nevil * Combine NEW_ATR with TCP_ATR, various bug fixes * * Revision 1.1.1.2 1999/10/03 21:06:19 nevil * *** empty log message *** * * Revision 1.1.1.1.2.4 1999/09/22 05:38:38 nevil * Improve code to work properly on 64-bit machines * - Add OS=ALPHA handling to configure.in * - Clean up the Alpha compiler warnings * - Change all the snmp-related code to use Bit32 instead of unsigned long * * Revision 1.1.1.1.2.3 1999/05/25 22:30:51 nevil * Make sure IPv6 managers interwork properly with IPv4 meters * - Determine meter's RULE_ADDR_SIZE by reading mask from rule 1 * of default ruleset. * - Print warning if meter rulesize < manager rulesize. * - Use smaller of these when downloading rules. * * Revision 1.1.1.1.2.2 1999/01/27 04:26:15 nevil * Minor corrections to fix compiler warnings * * Revision 1.1.1.1.2.1 1999/01/08 01:38:33 nevil * Distribution file for 4.3b7 * * Revision 1.1.1.1 1998/11/16 03:57:28 nevil * Import of NeTraMet 4.3b3 * * Revision 1.1.1.1 1998/11/16 03:22:01 nevil * Import of release 4.3b3 * * Revision 1.1.1.1.2.1 1998/11/11 23:14:41 nevil * Only include malloc.h if we HAVE_MALLOC_H * * Revision 1.1.1.1 1998/10/28 20:31:25 nevil * Import of NeTraMet 4.3b1 * * Revision 1.1.3.2 1998/10/18 23:44:15 nevil * Added Nicolai's patches, some 'tidying up' of the source * * Revision 1.1.3.1 1998/10/13 02:48:30 nevil * Import of Nicolai's 4.2.2 * * Revision 1.1.1.1 1998/08/24 12:09:29 nguba * NetraMet 4.2 Original Distribution * * Revision 1.6 1998/06/03 04:52:11 rtfm * Don't set snmp_delay (only done in nmc_snmp.c) * Use LastTime instead of sysUptime */ #if HAVE_CONFIG_H #include #endif #define TEST_GET_FLOWS 0 #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_SYS_SELECT_H # include #endif #if HAVE_MALLOC_H # include #endif #include #include #include "n_plot.h" #define EXTSNMP #include "ausnmp.h" #include "asn1.h" #include "snmp.h" #include "snmpimpl.h" #include "snmpapi.h" #include "snmpclnt.h" #include "mib.h" #define EXTERN #include "nmc.h" #include "nmc_c64.h" #define XNMRC #include "x_nm_rc.h" struct meter_status *nms; void sigint_handler(int x) { request_stop = 1; } void shutdown_nifty(void) { reader_util(nms, CU_DESTROY, CU_CURRENT); nms->mi_u_Index = nms->mi_Index; task_util(nms, TU_DESTROY); ruleset_util(nms, RU_DESTROY, &nms->c_ruleset); exit(1); } char rfname[NAME_LN], meter[NAME_LN], owner[NAME_LN], community[NAME_LN]; unsigned int def_sync, def_sample_interval, def_lag, def_ci_Timeout, def_ci_MinPDUs, def_download, def_no_write_meter, def_GCIntervalReqd, def_InactivityTime, def_HighWaterMark, def_FloodMark; int no_user_format; unsigned char rc_format[1+N_ATTRIBS], rc_required[1+N_ATTRIBS], /* Min attribs needed to determine 'top n' flows */ user_format[1+N_ATTRIBS], user_required[1+N_ATTRIBS]; /* Attributes for user's format */ void set_sample_columns(void) { /* Note: we get both packet and byte info so that the user can look at both types of plot without having to wait until we collect the next sample! */ memset(rc_required, 0, 1+N_ATTRIBS); rc_format[0] = FTRULESET; rc_required[FTRULESET] = 1; rc_format[1] = FTFLOWINDEX; rc_required[FTFLOWINDEX] = 1; rc_format[2] = FTFIRSTTIME; rc_required[FTFIRSTTIME] = 1; rc_format[3] = FTFLOWKIND; rc_required[FTFLOWKIND] = 1; rc_format[4] = FTLASTTIME; rc_required[FTLASTTIME] = 1; rc_format[5] = FTUPOCTETS; rc_required[FTUPOCTETS] = 1; rc_format[6] = FTDOWNOCTETS; rc_required[FTDOWNOCTETS] = 1; rc_format[7] = FTUPPDUS; rc_required[FTUPPDUS] = 1; rc_format[8] = FTDOWNPDUS; rc_required[FTDOWNPDUS] = 1; rc_format[9] = 0; } void no_write_warning(struct meter_status *ms) { if (ms->no_write_warned) return; fprintf(stdout,"Community %s doesn't have write access to meter %s!\n" " Collections won't trigger recovery of idle flows <<<\n", ms->community,ms->name); ms->no_write_warned = 1; } void add_event(struct calendar_entry *entry, struct meter_status *ms) { struct calendar_entry *cp, *lcp; entry->next_event = ms->next_event; entry->ms = ms; entry->next = NULL; if (calendar == NULL) { /* First entry in queue */ calendar = entry; return; } lcp = NULL; cp = calendar; do { if (ms->next_event < cp->next_event) { entry->next = cp; if (lcp == NULL) calendar = entry; /* Add to head */ else lcp->next = entry; /* Link into queue */ return; } lcp = cp; cp = cp->next; } while (cp != NULL); lcp->next = entry; /* Add to tail */ } void ruleset_row(struct meter_status *ms, struct row_info *rip) { struct meter_rule_info mri; if (strcmp(rip->tr_Owner, ms->owner_name) == 0) { mri.ri_Index = rip->tr_Index; ruleset_util(ms, RU_DESTROY, &mri); } else if (strcmp(rip->tr_Owner, "NeTraMet") == 0) { /* We've found NeTraMet meter's default ruleset */ ms->d_ruleset.ri_Index = rip->tr_Index; } } void manager_row(struct meter_status *ms, struct row_info *rip) { if (strcmp(rip->tr_Owner, ms->owner_name) == 0 || strcmp(rip->tr_Owner, "NeTraMet") == 0) { ms->mi_u_Index = rip->tr_Index; task_util(ms, TU_DESTROY); } } void reader_row(struct meter_status *ms, struct row_info *rip) { if (strcmp(rip->tr_Owner, ms->owner_name) == 0) { ms->ci_u_Index = rip->tr_Index; reader_util(ms, CU_DESTROY, CU_UTIL); } } int create_meter(struct meter_status *ms, time_t first_t, char *pn) { struct calendar_entry *entry; int a,b,n, syntax; if (ms->name[0] == '\0' || ms->community[0] == '\0') { fprintf(stdout,"Meter name or community not specified !!!\n"); return 0; } if (testing) printf("About to create_meter name=%s, community=%s\n", ms->name, ms->community); if (!start_snmp_session(ms)) return 0; ms->status = MT_MANAGE; if (meter_info(ms)) { ms->status |= (MT_UP | MT_INFO); ms->next_event = ms->next_sample = first_t; /* Get first sample immediately */ entry = (struct calendar_entry *)calloc( sizeof(struct calendar_entry), 1); add_event(entry,ms); if (testing) printf("t=%u, next_event=%u, next_keepalive=%u, next_sample=%u\n", first_t, ms->next_event, ms->next_keepalive, ms->next_sample); #ifndef _AIX if (!meter_is_current(ms)) { fprintf(stdout,"Warning: meter %s (version %s) not same as %s!\n", ms->name,ms->version, pn); } #endif #if V6 if (ms->meter_ra_len < RULE_ADDR_LEN) fprintf(stdout, "Meter %s is not IPv6 capable!\n", ms->name); #endif if (ms->MaxFlows > max_flows) max_flows = ms->MaxFlows; } else { fprintf(stdout,"Couldn't get meter info from %s!\n" " Does community %s have read or write access to the meter?\n", ms->name,ms->community); return 0; } set_meter_params(ms); if (ms->ci_Timeout == 0) /* Reader row timeout */ ms->ci_Timeout = 10*ms->sample_interval; search_table(ms, ST_READER, reader_row); search_table(ms, ST_MANAGER, manager_row); search_table(ms, ST_RULESET, ruleset_row); syntax = ms->download_level != 0; /* 0 => initial download of rules */ if (ms->c_ruleset.filename[0] == '\0') { /* No rule file specified */ fprintf(stdout,"No rule set specified !!!\n"); return 0; /* Can't just pick one already running! */ } else { /* Download the rules we want to use */ n = parse_rulefile(ms,listrules,syntax,0,0); /* Initial load */ if (!n || rferrors != 0) return 0; } /* search_table() finds NeTraMet's default ruleset */ reader_util(ms, CU_INIT, CU_CURRENT); reader_util(ms, CU_SET_MINPDUS, CU_CURRENT); if (no_user_format = ms->format[0] == 0) { /* No format specified */ ms->format[0] = FTLOWPEERTYPE; ms->required[FTLOWPEERTYPE] = 1; ms->format[1] = FTLOWPEERADDRESS; ms->required[FTLOWPEERADDRESS] = 1; ms->format[2] = FTHIPEERADDRESS; ms->required[FTHIPEERADDRESS] = 1; ms->format[3] = FTLOWTRANSTYPE; ms->required[FTLOWTRANSTYPE] = 1; ms->format[4] = FTLOWTRANSADDRESS; ms->required[FTLOWTRANSADDRESS] = 1; ms->format[5] = FTHITRANSADDRESS; ms->required[FTHITRANSADDRESS] = 1; ms->format[6] = 0; for (a = 0; a != 6; ++a) ms->separator[a] = " "; } memcpy(user_format, ms->format, 1+N_ATTRIBS); memcpy(user_required, ms->required, 1+N_ATTRIBS); ++nmeters; if (!ms->write_OK) no_write_warning(ms); ms->OurLastCollectTime = 0; /* Was 1L */ fprintf(stdout, "#Format: "); if ((n = ms->format[a = 0]) != 0) for (;;) { for (b = 1; b <= SZ_ATTRIBS && attribs[b].index != n; ++b) ; if (b <= SZ_ATTRIBS) fprintf(stdout,attribs[b].name); else fprintf(stdout,"attr*%u", n); /* Unknown attribute */ if ((n = ms->format[a+1]) == 0) break; fprintf(stdout,ms->separator[a++]); } fprintf(stdout,"\n"); } int main(int argc, char *argv[]) { int syntax; char *ap, arg[NAME_LN]; int a, j; time_t t1,t2; int busy_seconds; struct meter_status *ms; struct calendar_entry *cp; struct stat stat_buf; char have_config_file; FILE *cnf; char download_only; if (argc < 2) { fprintf(stderr,"%s [options] meter-name community\n\n", argv[0]); exit(0); } request_stop = 0; signal(SIGINT, sigint_handler); signal(SIGTERM, sigint_handler); incl_depth = syntax = verbose = testing = listrules = standard = 0; def_sync = 1; /* Samples synchronised with TOD clock */ def_sample_interval = 120; /* Default 2 minutes */ def_lag = 0; /* No time lag for collections */ rfname[0] = meter[0] = owner[0] = community[0] = '\0'; max_flows = 0; def_download = 0; /* Download rule sets on startup */ def_no_write_meter = 0; nd_flows = DEF_ND_FLOWS; def_HighWaterMark = 35; /* 35% for nm_rc and nifty */ def_ci_Timeout = 0; def_ci_MinPDUs = 20; /* Reader MinPDU filter value */ def_GCIntervalReqd = /* Use meter defaults for MIB variables */ def_InactivityTime = def_FloodMark = 0; logging_samples = logging_points = 0; show_names = 0; n_recent = 8; for (a = 1; a < argc; ++a) { if (argv[a][0] == '-') { ap = argv[a]+2; switch (argv[a][1]) { case 'a': if (*ap == '\0') ap = argv[++a]; def_lag = atoi(ap); break; case 'c': if (*ap == '\0') ap = argv[++a]; j = atoi(ap); if (j == 0) download_only = 1; else def_sample_interval = j; break; case 'd': snmp_dump_packet++; break; case 'g': if (*ap == '\0') ap = argv[++a]; def_GCIntervalReqd = atoi(ap); break; case 'h': if (*ap == '\0') ap = argv[++a]; def_HighWaterMark = atoi(ap); break; case 'i': if (*ap == '\0') ap = argv[++a]; def_InactivityTime = atoi(ap); break; case 'l': listrules++; break; case 'm': if (*ap == '\0') ap = argv[++a]; au_snmp_port = atoi(ap); break; case 'n': if (*ap == '\0') ap = argv[++a]; nd_flows = atoi(ap); /* Nbr of flows to display */ break; case 'o': if (*ap == '\0') ap = argv[++a]; def_FloodMark = atoi(ap); break; case 'r': if (*ap == '\0') ap = argv[++a]; strcpy(rfname, ap); /* Rule file name */ break; case 's': syntax++; break; case 't': testing++; break; case 'u': def_sync = 0; /* Unsynchronised */ break; case 'v': verbose++; break; case 'w': if (*ap == '\0') ap = argv[++a]; def_download = atoi(ap); break; case 'x': def_no_write_meter++; break; case 'E': if (*ap == '\0') ap = argv[++a]; def_ci_Timeout = atoi(ap); break; case 'L': if (*ap == '\0') ap = argv[++a]; strcpy(user_logfile, ap); /* Log file name */ logging_samples = logging_points = 1; break; case 'M': if (*ap == '\0') ap = argv[++a]; def_ci_MinPDUs = atoi(ap); break; case 'S': standard++; break; default: fprintf(stderr,"Invalid option: -%c\n", argv[a][1]); break; } continue; } if (meter[0] == '\0') strcpy(meter,argv[a]); else if (community[0] == '\0') strcpy(community,argv[a]); else if (owner[0] == '\0') { strncpy(owner,argv[a],NAMESZ); owner[NAMESZ] = '\0'; } } if (syntax) { /* Test a rule file */ ms = (struct meter_status *)calloc(sizeof(struct meter_status), 1); strcpy(ms->c_ruleset.filename,rfname); if (ms->s_ruleset.filename[0] != '\0') parse_rulefile(ms,listrules,1,1,0); /* syntax, standby */ parse_rulefile(ms,1,1,0,0); /* list, syntax, current, restart */ fprintf(stderr,"\n%d errors in rule file(s) %s\n\n", rferrors,rfname); exit(0); } if (nd_flows < 1) nd_flows = 1; logfile[0] = '\0'; if (user_logfile[0] != '\0') { strcpy(logfile,user_logfile); if ((logfl = fopen(logfile,"w")) == 0) { fprintf(stderr, "Failed to open %s as log file", logfile); exit(10); } } else logfl = wfopen(logfile, LOGFILE); init_mib(); /* Initialise SNMP handler */ time(&t1); first_meter = (struct meter_status *)calloc (sizeof(struct meter_status), 1); strcpy(first_meter->c_ruleset.filename,rfname); strcpy(first_meter->name,meter); strcpy((char *)first_meter->owner_name, owner[0] != '\0' ? owner : "nifty"); strcpy((char *)first_meter->community, community[0] != '\0' ? community : "public"); first_meter->synchronised = def_sync; first_meter->sample_interval = def_sample_interval; first_meter->lag_seconds = def_lag; first_meter->download_level = def_download; first_meter->no_write_meter = rfname[0] == '\0' ? 1 : def_no_write_meter; first_meter->write_OK = 1; first_meter->ci_Timeout = def_ci_Timeout; first_meter->ci_MinPDUs = def_ci_MinPDUs; first_meter->GCIntervalReqd = def_GCIntervalReqd; first_meter->InactivityTime = def_InactivityTime; first_meter->lag_seconds = def_lag; first_meter->HighWaterMark = def_HighWaterMark; first_meter->FloodMark = def_FloodMark; time(&t1); nms = first_meter; for (nmeters = 0, ms = first_meter; ms; ms = ms->next) create_meter(ms, t1, argv[0]); if (nmeters == 0) { fprintf(stderr,"No meters to monitor !!!\n"); exit(0); } /* Make sure we get the info we need to select 'top n' flows */ selection = STLAST; ordinate = PQBYTES; set_sample_columns(); plot_ms = NULL; /* Allocate two extra flows since they start from 2 not 0 */ if ((flow_table = (struct flow_data *)calloc( max_flows+2, sizeof(struct flow_data))) == NULL) { fprintf(stderr, "Failed to allocate memory for flow table!\n"); exit(11); } if ((select_table = (struct flow_select *)calloc( max_flows+2, sizeof(struct flow_select))) == NULL) { fprintf(stderr, "Failed to allocate memory for select table!\n"); exit(11); } if ((dflows = (struct display_data *)calloc( nd_flows, sizeof(struct display_data))) == NULL) { fprintf(stderr, "Failed to allocate memory for display data!\n"); exit(11); } for (j = 1; j != max_flows+2; ++j) flow_table[j].active = MXIDLE; for (;;) { for (;;) { time(&t1); if (calendar->next_event > t1) break; /* Wait a while */ cp = calendar; calendar = cp->next; /* Take entry from queue */ ms = cp->ms; if (ms->status & MT_MANAGE) monitor(ms); add_event(cp,ms); } if (testing) fflush(stdout); time(&t1); if (calendar->next_event > t1) break; if (request_stop) /* Set by sigint_handler() */ shutdown_nifty(); } nm_x_startup(1,argv, calendar->next_event-t1); /* We only go round this loop once to get communication with the target meter established properly */ } static int display_ready = 0; static char *display_msg; int nm_timer_callback(char *msg, int OK_to_display) /* Returns nbr of seconds to sleep */ { time_t t1,t2; int busy_seconds; struct meter_status *ms; struct calendar_entry *cp; display_ready = OK_to_display; display_msg = msg; for (;;) { for (;;) { time(&t1); if (calendar->next_event > t1) break; /* Wait a while */ cp = calendar; calendar = cp->next; /* Take entry from queue */ ms = cp->ms; if (ms->status & MT_MANAGE) monitor(ms); add_event(cp,ms); } if (testing) fflush(stdout); time(&t1); if (calendar->next_event > t1) break; if (request_stop) /* Set by sigint_handler() */ shutdown_nifty(); } return calendar->next_event-t1; /* Seconds before next event */ } int activeflows; /* Nbr of flows active this sample */ unsigned long sb,sp; /* Total bytes/packets this sample */ unsigned long sample_LastCollectTime; void process_row(struct flow_info *fp) { struct flow_data *fdp; unsigned int fi; fdp = &flow_table[fi = fp->FlowIndex]; if (fdp->ruleset != fp->FlowRuleSet || fdp->starttime != fp->FirstTime) { /* It's a new flow */ memset(fdp, 0, sizeof(struct flow_data)); fdp->ruleset = fp->FlowRuleSet; fdp->flowkind = fp->FlowKind; fdp->starttime = fp->FirstTime; fdp->interval = fp->LastTime-fp->FirstTime; } else { fdp->active = 0; /* Active this sample */ fdp->interval = fp->LastTime - fdp->lasttime; } fdp->lasttime = fp->LastTime; #if TEST_GET_FLOWS printf("flow %d, topkt=%lu, frompkt=%lu\n", fi, fp->FwdPackets.low, fp->BackPackets.low); #endif if (display_ready) { /* 64-bit counts => 32-bit rates !!! */ diff64(fdp->up_pkt_rate, fp->FwdPackets,fdp->up_pkt_count); if (fdp->up_pkt_rate != 0) { diff64(fdp->up_byte_rate, fp->FwdBytes,fdp->up_byte_count); if (fdp->up_byte_rate/fdp->up_pkt_rate > 1500) fdp->up_byte_rate = fdp->up_pkt_rate = 0L; } else fdp->up_byte_rate = 0; diff64(fdp->down_pkt_rate, fp->BackPackets,fdp->down_pkt_count); if (fdp->down_pkt_rate != 0) { diff64(fdp->down_byte_rate, fp->BackBytes,fdp->down_byte_count); if (fdp->down_byte_rate/fdp->down_pkt_rate > 1500) fdp->down_byte_rate = fdp->down_pkt_rate = 0L; } else fdp->down_byte_rate = 0; } assign64(fdp->up_pkt_count, fp->FwdPackets); assign64(fdp->up_byte_count, fp->FwdBytes); assign64(fdp->down_pkt_count, fp->BackPackets); assign64(fdp->down_byte_count, fp->BackBytes); sb += (fdp->up_byte_rate+fdp->down_byte_rate); /* Sample totals */ sp += (fdp->up_pkt_rate+fdp->down_pkt_rate); ++activeflows; } void monitor( /* Called every interval for each meter */ struct meter_status *ms) { time_t t, nst,si; char *ts; int mir, reachable, n,r; unsigned long last_uptime; struct flow_info *fp; struct flow_data *fdp; char buf[150], *dbp; time(&t); ts = fmt_time(&t); if (!ms->write_OK) no_write_warning(ms); last_uptime = ms->uptime; reachable = 1; ms->ci_TimeMark = ms->OurLastCollectTime; /* Associate TimeFilter with rdr row */ if (ms->MIBver == 4) { /* Tell meter we want to start a collection */ if (ms->c_ruleset.ri_Index != 0) { mir = reader_util(ms, CU_SET_TIME, CU_CURRENT); } else mir = 1; /* No current ruleset (yet) */ } else { /* V3 MIB */ mir = reader_util(ms, CU_SET_TIME, CU_CURRENT); } if (mir) { /* LastTime was set OK */ mir = meter_info(ms); /* ms->uptime = LastTime */ } if (mir == 0) { /* Lost contact */ if (restart_snmp_session(ms)) { ms->uptime = 0; mir = meter_info(ms); } } if (mir == 0) { /* Couldn't re-establish contact */ fprintf(stderr, "%s -- %s: No response\n", ts,ms->name); reachable = 0; } /* Meter processing .. */ if (reachable) { if (ms->uptime < last_uptime ) { /* Meter has restarted */ fprintf(stderr, "%s: Meter has restarted\n", ms->name); ms->write_OK = 1; ms->no_write_warned = 0; ms->OurLastCollectTime = 0; /* Was 1L */ set_meter_params(ms); /* Clear old (e.g. NeTraMet) tasks from meter */ search_table(ms, ST_READER, reader_row); ms->use_meter_rows = 0; search_table(ms, ST_MANAGER, manager_row); search_table(ms, ST_RULESET, ruleset_row); /* Forget our control rows - mustn't confuse the download */ ms->ci_c_Index = 0; ms->mi_Index = 0; ms->c_ruleset.ri_Index = 0; n = parse_rulefile(ms,listrules,0,0,1); /* Reload */ if (!n || rferrors != 0) return; if (ms->mi_Index != 0) { reader_util(ms, CU_INIT, CU_CURRENT); if (!ms->write_OK) no_write_warning(ms); } ms->ci_TimeMark = ms->OurLastCollectTime; /* Associate TimeFilter with rdr row */ if (ms->MIBver == 4) { /* Tell meter we want to start a collection */ if (ms->c_ruleset.ri_Index != 0) reader_util(ms, CU_SET_TIME, CU_CURRENT); } else reader_util(ms, CU_SET_TIME, CU_CURRENT); /* V3 MIB */ meter_info(ms); } if (ms->mi_Index == 0 && ms->MIBver == 4) ms->uptime = last_uptime; /* Haven't got our task running yet */ plot_ms = ms; for (r = 0; r != max_flows+2; ++r) { fdp = &flow_table[r]; if (fdp->active != MXIDLE) ++fdp->active; } tt = 0; /* Used by x_support.c */ sb = sp = 0; sample_LastCollectTime = ms->OurLastCollectTime; memset(dflows, 0, nd_flows*sizeof(struct display_data)); activeflows = 0; memcpy(ms->format, rc_format, 1+N_ATTRIBS); memcpy(ms->required, rc_required, 1+N_ATTRIBS); /* Only get the attribs needed to determine 'top n' flows */ if (ms->MIBver == 4) get_package_info(ms, ms->c_ruleset.ri_Index, ms->OurLastCollectTime, process_row); else get_colblob_data(ms, ms->c_ruleset.ri_Index, ms->OurLastCollectTime, process_row); memcpy(ms->format, user_format, 1+N_ATTRIBS); memcpy(ms->required, user_required, 1+N_ATTRIBS); if (display_ready) { sprintf(buf,"%s, %s %s, %s, %us sample, ", ts, ms->name,ms->interface, ms->c_ruleset.filename, ms->sample_interval); dbp = strmov(display_msg,buf); if (ms->statsreqd) { sprintf(buf,"%u flows, %u active, ", ms->NbrFlows,activeflows); dbp = strmov(dbp,buf); } else { sprintf(buf,"%u flows (%u read), ", ms->ActiveFlows, activeflows); /* $$$ sprintf(buf,"%u active flows, ", activeflows); */ dbp = strmov(dbp,buf); } if (ordinate == PQBYTES) sprintf(buf,"%.3f Mbps", ((float)sb*8.0)/((float)ms->sample_interval*1000000.0) ); else sprintf(buf,"%.3f kpps", (float)sp/((float)ms->sample_interval*1000.0) ); dbp = strmov(dbp,buf); if (logging_samples) { log_msg(LOG_INFO, FALSE, "%s\n",display_msg); } } } ms->OurLastCollectTime = ms->uptime - 1L; /* -1 to make sure we don't miss any flows. We may collect some of them twice, but we don't mind that */ if (testing) printf("Sample: t=%u",ms->next_event); if (ms->synchronised) { nst = ms->next_sample + (si = ms->sample_interval); ms->next_sample = (nst / si) * si + ms->lag_seconds; } else ms->next_sample += ms->sample_interval; ms->next_event = ms->next_sample; if (testing) printf(", sync=%d, next_sample=%u, next_keepalive=%u\n", ms->synchronised, ms->next_sample, ms->next_keepalive); }