/* 1655, Thu 17 Feb 00 X_SUPPORT.C: Interface between x_ob.c and x_nm_rc.c Copyright (C) 1996-2002 by Nevil Brownlee, CAIDA | University of Auckland */ /* * $Log: x_support.c,v $ * Revision 1.1.1.2.2.10 2002/02/23 01:57:25 nevil * Moving srl examples to examples/ directory. Modified examples/Makefile.in * * Revision 1.1.1.2.2.6 2000/08/08 19:44:48 nevil * 44b8 release * * Revision 1.1.1.2.2.4 2000/06/06 03:38:15 nevil * Combine NEW_ATR with TCP_ATR, various bug fixes * * Revision 1.1.1.2.2.1 1999/11/29 00:17:24 nevil * Make changes to support NetBSD on an Alpha (see version.history for details) * * Revision 1.1.1.2 1999/10/03 21:06:21 nevil * *** empty log message *** * * Revision 1.1.1.1.2.2 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.1 1999/01/08 01:38:34 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:42 nevil * Only include malloc.h if we HAVE_MALLOC_H * * Revision 1.1.1.1 1998/10/28 20:31:26 nevil * Import of NeTraMet 4.3b1 * * Revision 1.1.3.2 1998/10/18 23:44:17 nevil * Added Nicolai's patches, some 'tidying up' of the source * * Revision 1.1.3.1 1998/10/13 02:48:32 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.4 1998/05/07 04:28:53 rtfm * Implement NetFlowMet, the Cisco NetFlow RTFM meter */ #if HAVE_CONFIG_H #include #endif #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" #include "ausnmp.h" #include "asn1.h" #include "snmp.h" #include "snmpimpl.h" #include "snmpapi.h" #include "snmpclnt.h" #include "mib.h" #include "nmc.h" #include "nmc_c64.h" #include "x_nm_rc.h" String colors[] = { "Black", "Navy", "Blue", "LimeGreen", "Orange", "Red", "Magenta", "Purple" }; #define NCOLORS 8 void set_log_type(XtPointer lt) { switch ((IntFromPtr)lt) { case LGSAMPLE: logging_samples = 1; break; case LGPOINT: logging_points = 1; break; case LGNONE: logging_samples = logging_points = 0; break; } } void set_name_type(XtPointer nt) { show_names = (IntFromPtr)nt ? 1 : 0; /* No compiler warning on Alpha NetBSD! */ } void set_initial_parameters(void) { n_flows_to_plot = n_selected_flows = 0; ordinate = (XtPointer)PQPKTS; /* Byte */ ptype = (XtPointer)PTSAMPKB; /* Rate */ selection = (XtPointer)STRECENT; /* Recent samples */ set_axis_range((XtPointer)SX15M); set_axis_range((XtPointer)SY900); } void set_ordinate_type(XtPointer ot) { ordinate = ot; nm_select_points(); /* Change selection */ nm_compute_points(); /* Reflect new scale factors */ } void set_metric_type(XtPointer pt) { char *msg; ptype = pt; nm_select_points(); /* Change selection */ nm_compute_points(); /* Reflect new scale factors */ if (logging_points) { switch ((IntFromPtr)(ptype = pt)) { case PTSAMPPC: /* Sample % */ msg = "Plotting sample %%"; break; case PTSAMPKB: /* Sample kbps */ msg = "Plotting sample counts"; break; case PTFLOWKB: /* Total flow kB */ msg = "Plotting total counts"; break; } log_msg(LOG_INFO, FALSE, "\n%s\n", msg); } } void set_select_type(XtPointer st) { selection = st; nm_select_points(); /* Change selection */ nm_compute_points(); /* Reflect new scale factors */ } void set_axis_range(XtPointer at) { switch ((IntFromPtr)at) { case SX100S: pxmin = 0.7; pxaxis = 1.0; pxmax = 100.0; pxscale = 1.0; xtype = at; break; case SX15M: pxmin = 0.7; pxaxis = 1.0; pxmax = 1000.0; pxscale = 1.0; xtype = at; break; case SX2H: pxmin = 0.7; pxaxis = 1.0; pxmax = 120.0; pxscale = 60.0; xtype = at; break; case SY40P: pymin = 0.06; pyaxis = 0.1; pymax = 40.0; pyscale = 1.0; ytype = at; break; case SY900: pymin = 0.55; pyaxis = 1.0; pymax = 900.0; pyscale = 1.0; ytype = at; break; case SY9K: pymin = 0.07; pyaxis = 0.1; pymax = 9.0; pyscale = 1000.0; ytype = at; break; case SY90K: pymin = 0.7; pyaxis = 1.0; pymax = 90.0; pyscale = 1000.0; ytype = at; break; case SY900K: pymin = 7.0; pyaxis = 10.0; pymax = 900.0; pyscale = 1000.0; ytype = at; break; case SY9M: pymin = 0.07; pyaxis = 0.1; pymax = 9.0; pyscale = 1000000.0; ytype = at; break; case SY90M: pymin = 0.7; pyaxis = 1.0; pymax = 90.0; pyscale = 1000000.0; ytype = at; break; } nm_compute_points(); /* Reflect new scale factors */ } void draw_xaxis(void) { switch ((IntFromPtr)xtype) { case SX100S: case SX15M: xaxis(pxaxis,pyaxis, 10.0); xaxis(pxaxis/5,pyaxis, 10.0); xaxis(pxaxis/2,pyaxis, 10.0); aoutst("seconds",-7); break; case SX2H: xaxis(pxaxis/2,pyaxis, 10.0); xaxis(pxaxis/5,pyaxis, 10.0); xaxis(pxaxis,pyaxis, 10.0); aoutst("minutes",-7); break; } } static char *y_units(void) { switch ((IntFromPtr)ptype) { case PTSAMPPC: return "%"; break; case PTSAMPKB: switch ((IntFromPtr)ordinate) { case PQBYTES: switch ((IntFromPtr)ytype) { case SY40P: case SY900: return "bps"; break; case SY9K: case SY90K: case SY900K: return "kbps"; break; case SY9M: case SY90M: return "Mbps"; break; } break; case PQPKTS: switch ((IntFromPtr)ytype) { case SY40P: case SY900: return "pps"; break; case SY9K: case SY90K: case SY900K: return "kpps"; break; case SY9M: case SY90M: return "Mpps"; break; } break; } break; case PTFLOWKB: switch ((IntFromPtr)ordinate) { case PQBYTES: switch ((IntFromPtr)ytype) { case SY40P: case SY900: return "B"; break; case SY9K: case SY90K: case SY900K: return "kB"; break; case SY9M: case SY90M: return "MB"; break; } break; case PQPKTS: switch ((IntFromPtr)ytype) { case SY40P: case SY900: return "pkt"; break; case SY9K: case SY90K: case SY900K: return "kpkt"; break; case SY9M: case SY90M: return "Mpkt"; break; } break; } break; } } void draw_yaxis(void) { char *yu = y_units(); switch ((IntFromPtr)ytype) { case SY40P: yaxis(pxaxis,pyaxis, 10.0); yaxis(pxaxis,pyaxis/2, 10.0); yaxis(pxaxis,pyaxis/5, 10.0); break; case SY900: case SY9K: case SY90K: case SY900K: case SY9M: case SY90M: yaxis(pxaxis,pyaxis, 10.0); yaxis(pxaxis,pyaxis/5, 10.0); yaxis(pxaxis,pyaxis/2, 10.0); break; } aoutst(yu, -strlen(yu)); } void draw_title(void) { char buf[100], *bp; switch ((IntFromPtr)ordinate) { case PQBYTES: bp = strmov(buf, "Byte "); break; case PQPKTS: bp = strmov(buf, "Packet "); break; } switch ((IntFromPtr)ptype) { case PTSAMPPC: bp = strmov(bp, "%"); break; case PTSAMPKB: bp = strmov(bp, "Rate"); break; case PTFLOWKB: bp = strmov(bp, "Count"); break; } bp = strmov(bp, " vs Flow Duration for "); switch ((IntFromPtr)selection) { case STLAST: bp = strmov(bp, "Last Sample"); break; case STRECENT: bp = strmov(bp, "Recent Samples"); break; case STALL: bp = strmov(bp, "All Samples"); break; } *bp = '\0'; aoutst(buf,-strlen(buf)); } int sort_cmp(const void *a, const void *b) { if (((struct flow_select *)a)->traffic < /* Reverse numeric order */ ((struct flow_select *)b)->traffic) return 1; else if (((struct flow_select *)a)->traffic == ((struct flow_select *)b)->traffic) return 0; else return -1; } void nm_select_points(void) { unsigned int fi; unsigned long ft; n_flows_to_plot = n_selected_flows = 0; for (fi = 1; fi != max_flows+2; ++fi) { if (selection == STLAST) { if (flow_table[fi].active > 0) continue; } else if ((IntFromPtr)selection == STRECENT) { if (flow_table[fi].active >= n_recent) continue; } if (ordinate == PQBYTES) { /* Compute traffic */ switch ((IntFromPtr)ptype) { case PTSAMPPC: case PTSAMPKB: ft = flow_table[fi].up_byte_rate + flow_table[fi].down_byte_rate; break; case PTFLOWKB: sum64(ft, flow_table[fi].up_byte_count, flow_table[fi].down_byte_count); break; } } else { switch ((IntFromPtr)ptype) { case PTSAMPPC: case PTSAMPKB: ft = flow_table[fi].up_pkt_rate + flow_table[fi].down_pkt_rate; break; case PTFLOWKB: sum64(ft, flow_table[fi].up_pkt_count, flow_table[fi].down_pkt_count); break; } } tt += ft; select_table[n_selected_flows].traffic = ft; select_table[n_selected_flows].flownbr = fi; ++n_selected_flows; } qsort(select_table, n_selected_flows, sizeof(struct flow_select), sort_cmp); } void nm_compute_points(void) { unsigned short i; struct flow_select *fsp; struct display_data *ddp; unsigned long s_time; float s_scale; n_flows_to_plot = 0; if (n_selected_flows == 0) return; if (n_selected_flows > nd_flows) /* nd_flows = max nbr of flows to plot */ n_selected_flows = nd_flows; for (i = 0; i != n_selected_flows; ++i) { /* Build plot data */ fsp = &select_table[i]; if (fsp->traffic == 0) break; /* Very few active flows! */ ddp = &dflows[n_flows_to_plot]; ddp->flownbr = fsp->flownbr; ddp->active = flow_table[fsp->flownbr].active; ddp->vx = (float)(flow_table[fsp->flownbr].lasttime - flow_table[fsp->flownbr].starttime)/(100.0*pxscale); if (ddp->vx <= 0) /* NetFlow sometimes has LastTime < FirstTime */ ddp->vx = 0.01; switch ((IntFromPtr)ptype) { case PTSAMPPC: ddp->vy = (float)(fsp->traffic)*100.0/ /* traffic % */ ((float)tt*pyscale); break; case PTSAMPKB: s_time = flow_table[fsp->flownbr].interval; if (s_time == 0) s_time = 10; /* Avoid divide by zero */ /* NetFlow sometimes gives FirstTime <= LastTime. Rather than ignore them, we use a time of 10ms */ s_scale = ((float)s_time/100.0)*pyscale; switch ((IntFromPtr)ordinate) { case PQBYTES: ddp->vy = ((float)fsp->traffic*8.0)/s_scale; /* rate bps */ break; case PQPKTS: ddp->vy = (float)fsp->traffic/s_scale; /* rate pps */ break; } break; case PTFLOWKB: ddp->vy = (float)fsp->traffic/pyscale; /* flow bytes */ break; } ++n_flows_to_plot; } } void nm_plot_points(void) { int i; struct display_data *ddp; float px,py; unsigned char s_active = MXIDLE; for (i = 0; i != n_flows_to_plot; ++i) { ddp = &dflows[i]; if (ddp->vx < pxmin) px = pxmin; else if (ddp->vx > pxmax) px = pxmax; else px = ddp->vx; if (ddp->vy < pymin) py = pymin; else if (ddp->vy > pymax) py = pymax; else py = ddp->vy; vtostransform(&ddp->sx,&ddp->sy, px,py); movabs(ddp->sx,ddp->sy); if (ddp->active != s_active) { s_active = ddp->active >= NCOLORS ? NCOLORS-1 : ddp->active; set_plot_color(colors[s_active]); } pltsym(flow_table[ddp->flownbr].flowkind); } } int nm_nearest_flow(int sx,int sy) { int i; struct display_data *ddp; struct flow_info fi; int d, mind, mini; if (n_flows_to_plot == 0) return -1; ddp = &dflows[0]; mini = 0; mind = (sx-ddp->sx)*(sx-ddp->sx) + (sy-ddp->sy)*(sy-ddp->sy); for (i = 1; i != n_flows_to_plot; ++i) { ddp = &dflows[i]; d = (sx-ddp->sx)*(sx-ddp->sx) + (sy-ddp->sy)*(sy-ddp->sy); if (d < mind) { mind = d; mini = i; } } if (mind > 100) /* Not close enough to a point */ return -1; else return mini; } void nm_flow_details(char *msg, int action, int mini) { struct display_data *ddp; struct flow_info fi; unsigned char a,col; char buf[300], *mp; ddp = &dflows[mini]; sprintf(buf,"(%.2f ", ddp->vx); mp = strmov(msg,buf); switch ((IntFromPtr)xtype) { case SX100S: case SX15M: mp = strmov(mp,"s, "); break; case SX2H: mp = strmov(mp,"m, "); break; } sprintf(buf,"%.2f %s) ", ddp->vy,y_units()); mp = strmov(mp,buf); switch (action) { case 1: /* Button 1 up */ memset(&fi, 0, sizeof(fi)); if (flow_info(plot_ms, &fi, ddp->flownbr) == 0) { mp = strmov(mp, "no info (flow memory recovered by meter)"); *mp = '\0'; break; } for (col = plot_ms->format[a = 0]; ; ) { if (col != '\0') mp = sdisplay_attrib(mp, &fi,col,plot_ms); if ((col = plot_ms->format[a+1]) == '\0') break; mp = strmov(mp,plot_ms->separator[a++]); } *mp = '\0'; if (logging_points) { log_msg(LOG_INFO, FALSE, "%s\n",msg); } break; case 2: /* Button 2 down */ sprintf(buf, "Packets: Total %lu fwd %lu back, " "Sample %lu fwd %lu back in %.2f s", #if SIZEOF_LONG_LONG == 8 || SIZEOF_LONG == 8 flow_table[ddp->flownbr].up_pkt_count, flow_table[ddp->flownbr].down_pkt_count, flow_table[ddp->flownbr].up_pkt_rate, flow_table[ddp->flownbr].down_pkt_rate, #else flow_table[ddp->flownbr].up_pkt_count.low, flow_table[ddp->flownbr].down_pkt_count.low, flow_table[ddp->flownbr].up_pkt_rate, flow_table[ddp->flownbr].down_pkt_rate, #endif (float)flow_table[ddp->flownbr].interval/100.0 ); mp = strmov(mp,buf); *mp = '\0'; break; case 3: /* Button 3 down */ sprintf(buf, "kBytes: Total %.1f fwd %.1f back, " "Sample %.1f fwd %.1f back in %.2f s", (float)fraction64(flow_table[ddp->flownbr].up_byte_count, 1000.0), (float)fraction64(flow_table[ddp->flownbr].down_byte_count, 1000.0), (float)flow_table[ddp->flownbr].up_byte_rate/1000.0, (float)flow_table[ddp->flownbr].down_byte_rate/1000.0, (float)flow_table[ddp->flownbr].interval/100.0 ); mp = strmov(mp,buf); *mp = '\0'; break; } }