diff options
Diffstat (limited to 'apps/snmpnetstat/if.c')
-rw-r--r-- | apps/snmpnetstat/if.c | 867 |
1 files changed, 867 insertions, 0 deletions
diff --git a/apps/snmpnetstat/if.c b/apps/snmpnetstat/if.c new file mode 100644 index 0000000..2d8e372 --- /dev/null +++ b/apps/snmpnetstat/if.c @@ -0,0 +1,867 @@ +/* $OpenBSD: if.c,v 1.42 2005/03/13 16:05:50 mpf Exp $ */ +/* $NetBSD: if.c,v 1.16.4.2 1996/06/07 21:46:46 thorpej Exp $ */ + +/* + * Copyright (c) 1983, 1988, 1993 + * The Regents of the University of California. 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. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#ifdef INHERITED_CODE +#ifndef lint +#if 0 +static char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94"; +#else +static char *rcsid = "$OpenBSD: if.c,v 1.42 2005/03/13 16:05:50 mpf Exp $"; +#endif +#endif /* not lint */ +#endif + +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-includes.h> + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_NET_IF_H +#include <net/if.h> +#endif +#define __USE_XOPEN +#define __USE_XOPEN_EXTENDED +#include <signal.h> + +#include "main.h" +#include "netstat.h" + +#define YES 1 +#define NO 0 + +static void sidewaysintpr(u_int); +static void timerSet(int interval_seconds); +static void timerPause(void); + + struct _if_info { + char name[128]; + char ip[128], route[128]; + int mtu; + int drops; + int ifindex; + /* + * Save "expandable" fields as string values + * rather than integer statistics + */ + char s_ipkts[20], s_ierrs[20]; + char s_opkts[20], s_oerrs[20]; + char s_ibytes[20], s_obytes[20]; + char s_outq[20]; + unsigned long ipkts, opkts; /* Need to combine 2 MIB values */ + int operstatus; +/* + u_long netmask; + struct in_addr ifip, ifroute; + */ + struct _if_info *next; + }; + + +/* + * Retrieve the interface addressing information + * XXX - This could also be extended to handle non-IP interfaces + */ +void +_set_address( struct _if_info *cur_if ) +{ + oid ipaddr_oid[] = { 1,3,6,1,2,1,4,20,1,0 }; + size_t ipaddr_len = OID_LENGTH( ipaddr_oid ); + static netsnmp_variable_list *addr_if_var =NULL; + static netsnmp_variable_list *addr_mask_var=NULL; + netsnmp_variable_list *vp, *vp2; + union { + in_addr_t addr; + char data[4]; + } tmpAddr; + char *cp; + in_addr_t ifAddr, mask; + + /* + * Note that this information only needs to be retrieved + * once, and can be re-used for subsequent calls. + */ + if ( addr_if_var == NULL ) { + ipaddr_oid[ 9 ] = 2; /* ipAdEntIfIndex */ + snmp_varlist_add_variable( &addr_if_var, ipaddr_oid, ipaddr_len, + ASN_NULL, NULL, 0); + netsnmp_query_walk( addr_if_var, ss ); + + ipaddr_oid[ 9 ] = 3; /* ipAdEntNetMask */ + snmp_varlist_add_variable( &addr_mask_var, ipaddr_oid, ipaddr_len, + ASN_NULL, NULL, 0); + netsnmp_query_walk( addr_mask_var, ss ); + } + + /* + * Find the address row relevant to this interface + */ + for (vp=addr_if_var, vp2=addr_mask_var; vp; + vp=vp->next_variable, vp2=vp2->next_variable) { + if ( vp->val.integer && *vp->val.integer == cur_if->ifindex ) + break; + } + if (vp2) { + /* + * Always want a numeric interface IP address + */ + snprintf( cur_if->ip, 128, "%lu.%lu.%lu.%lu", + vp2->name[10], + vp2->name[11], + vp2->name[12], + vp2->name[13]); + + /* + * But re-use the routing table utilities/code for + * displaying the local network information + */ + cp = tmpAddr.data; + cp[0] = vp2->name[ 10 ] & 0xff; + cp[1] = vp2->name[ 11 ] & 0xff; + cp[2] = vp2->name[ 12 ] & 0xff; + cp[3] = vp2->name[ 13 ] & 0xff; + ifAddr = tmpAddr.addr; + cp = tmpAddr.data; + cp[0] = vp2->val.string[ 0 ] & 0xff; + cp[1] = vp2->val.string[ 1 ] & 0xff; + cp[2] = vp2->val.string[ 2 ] & 0xff; + cp[3] = vp2->val.string[ 3 ] & 0xff; + mask = tmpAddr.addr; + snprintf( cur_if->route, 128, "%s", netname(ifAddr, mask)); + } +} + + +/* + * Print a description of the network interfaces. + */ +void +intpr(int interval) +{ + oid ifcol_oid[] = { 1,3,6,1,2,1,2,2,1,0 }; + size_t ifcol_len = OID_LENGTH( ifcol_oid ); + + struct _if_info *if_head, *if_tail, *cur_if; + netsnmp_variable_list *var, *vp; + /* + * Track maximum field widths, expanding as necessary + * This is one reason why results can't be + * displayed immediately they are retrieved. + */ + int max_name = 4, max_ip = 7, max_route = 7, max_outq = 5; + int max_ipkts = 5, max_ierrs = 5, max_opkts = 5, max_oerrs = 5; + int max_ibytes = 6, max_obytes = 6; + int i; + + + if (interval) { + sidewaysintpr((unsigned)interval); + return; + } + + /* + * The traditional "netstat -i" output combines information + * from two SNMP tables: + * ipAddrTable (for the IP address/network) + * ifTable (for the interface statistics) + * + * The previous approach was to retrieve (and save) the + * address information first. Then walk the main ifTable, + * add the relevant stored addresses, and saving the + * full information for each interface, before displaying + * the results as a separate pass. + * + * This code reverses this general structure, by first retrieving + * (and storing) the interface statistics for the whole table, + * then inserting the address information obtained from the + * ipAddrTable, and finally displaying the results. + * Such an arrangement should make it easier to extend this + * to handle non-IP interfaces (hence not in ipAddrTable) + */ + if_head = NULL; + if_tail = NULL; + var = NULL; + +#define ADD_IFVAR( x ) ifcol_oid[ ifcol_len-1 ] = x; \ + snmp_varlist_add_variable( &var, ifcol_oid, ifcol_len, ASN_NULL, NULL, 0) + ADD_IFVAR( 2 ); /* ifName */ + ADD_IFVAR( 4 ); /* ifMtu */ + ADD_IFVAR( 8 ); /* ifOperStatus */ + /* + * The Net/Open-BSD behaviour is to display *either* byte + * counts *or* packet/error counts (but not both). FreeBSD + * integrates the byte counts into the traditional display. + * + * The previous 'snmpnetstat' implementation followed the + * separatist model. This re-write offers an opportunity + * to adopt the (more useful, IMO) Free-BSD approach. + * + * Or we could perhaps support both styles? :-) + */ + if (bflag || oflag) { + ADD_IFVAR( 10 ); /* ifInOctets */ + ADD_IFVAR( 16 ); /* ifOutOctets */ + } + if (!oflag) { + ADD_IFVAR( 11 ); /* ifInUcastPkts */ + ADD_IFVAR( 12 ); /* ifInNUcastPkts */ + ADD_IFVAR( 14 ); /* ifInErrors */ + ADD_IFVAR( 17 ); /* ifOutUcastPkts */ + ADD_IFVAR( 18 ); /* ifOutNUcastPkts */ + ADD_IFVAR( 20 ); /* ifOutErrors */ + ADD_IFVAR( 21 ); /* ifOutQLen */ + } +#if 0 + if (tflag) { + ADD_IFVAR( XX ); /* ??? */ + } +#endif + if (dflag) { + ADD_IFVAR( 19 ); /* ifOutDiscards */ + } +#undef ADD_IFVAR + + /* + * Now walk the ifTable, creating a list of interfaces + */ + while ( 1 ) { + if (netsnmp_query_getnext( var, ss ) != SNMP_ERR_NOERROR) + break; + ifcol_oid[ ifcol_len-1 ] = 2; /* ifDescr */ + if ( snmp_oid_compare( ifcol_oid, ifcol_len, + var->name, ifcol_len) != 0 ) + break; /* End of Table */ + cur_if = SNMP_MALLOC_TYPEDEF( struct _if_info ); + if (!cur_if) + break; + cur_if->ifindex = var->name[ var->name_length-1 ]; + for ( vp=var; vp; vp=vp->next_variable ) { + if ( ! vp->val.integer ) + continue; + if ( var->name[ var->name_length-1 ] != cur_if->ifindex ) { + /* + * Inconsistent index information + * XXX - Try to recover ? + */ + SNMP_FREE( cur_if ); + cur_if = NULL; + break; /* not for now, no */ + } + switch ( vp->name[ var->name_length-2 ] ) { + case 2: /* ifDescr */ + if (vp->val_len >= sizeof(cur_if->name)) + vp->val_len = sizeof(cur_if->name)-1; + memmove( cur_if->name, vp->val.string, vp->val_len ); + cur_if->name[vp->val_len] = 0; + if ((i = strlen(cur_if->name) + 1) > max_name) + max_name = i; + break; + case 4: /* ifMtu */ + cur_if->mtu = *vp->val.integer; + break; + case 8: /* ifOperStatus */ + cur_if->operstatus = *vp->val.integer; + /* XXX - any special processing ?? */ + break; + case 10: /* ifInOctets */ + sprintf(cur_if->s_ibytes, "%lu", *vp->val.integer); + i = strlen(cur_if->s_ibytes); + if (i > max_ibytes) + max_ibytes = i; + break; + case 11: /* ifInUcastPkts */ + cur_if->ipkts += *vp->val.integer; + sprintf(cur_if->s_ipkts, "%lu", cur_if->ipkts); + i = strlen(cur_if->s_ipkts); + if (i > max_ipkts) + max_ipkts = i; + break; + case 12: /* ifInNUcastPkts */ + cur_if->ipkts += *vp->val.integer; + sprintf(cur_if->s_ipkts, "%lu", cur_if->ipkts); + i = strlen(cur_if->s_ipkts); + if (i > max_ipkts) + max_ipkts = i; + break; + case 14: /* ifInErrors */ + sprintf(cur_if->s_ierrs, "%lu", *vp->val.integer); + i = strlen(cur_if->s_ierrs); + if (i > max_ierrs) + max_ierrs = i; + break; + case 16: /* ifOutOctets */ + sprintf(cur_if->s_obytes, "%lu", *vp->val.integer); + i = strlen(cur_if->s_obytes); + if (i > max_obytes) + max_obytes = i; + break; + case 17: /* ifOutUcastPkts */ + cur_if->opkts += *vp->val.integer; + sprintf(cur_if->s_opkts, "%lu", cur_if->opkts); + i = strlen(cur_if->s_opkts); + if (i > max_opkts) + max_opkts = i; + break; + case 18: /* ifOutNUcastPkts */ + cur_if->opkts += *vp->val.integer; + sprintf(cur_if->s_opkts, "%lu", cur_if->opkts); + i = strlen(cur_if->s_opkts); + if (i > max_opkts) + max_opkts = i; + break; + case 19: /* ifOutDiscards */ + cur_if->drops = *vp->val.integer; + break; + case 20: /* ifOutErrors */ + sprintf(cur_if->s_oerrs, "%lu", *vp->val.integer); + i = strlen(cur_if->s_oerrs); + if (i > max_oerrs) + max_oerrs = i; + break; + case 21: /* ifOutQLen */ + sprintf(cur_if->s_outq, "%lu", *vp->val.integer); + i = strlen(cur_if->s_outq); + if (i > max_outq) + max_outq = i; + break; + } + } + + /* + * XXX - Perhaps query ifXTable for additional info ?? + * (ifName/ifAlias, or HC counters) + */ + + /* + * If we're to monitor a particular interface, then + * ignore all others. It would be more efficient + * to check this earlier (as part of processing + * the varbind list). But performing this test here + * means we can recognise ifXTable names as well) + */ + if ( intrface && strcmp( cur_if->name, intrface ) != 0) { + SNMP_FREE( cur_if ); + cur_if = NULL; + } + + /* + * Insert the IP address and network settings, and + * add the new _if_stat structure to the list. + */ + if ( cur_if ) { + _set_address( cur_if ); + i = strlen(cur_if->ip); + if (i > max_ip) + max_ip = i; + i = strlen(cur_if->route); + if (i > max_route) + max_route = i; + + if ( if_tail ) { + if_tail->next = cur_if; + if_tail = cur_if; + } else { + if_head = cur_if; + if_tail = cur_if; + } + } + } /* while (1) */ + + /* + * Now display the specified results (in Free-BSD format) + * setting the field widths appropriately.... + */ + printf("%*.*s %5.5s %*.*s %*.*s", + -max_name, max_name, "Name", "Mtu", + -max_route, max_route, "Network", + -max_ip, max_ip, "Address"); + if (oflag) { + printf(" %*s %*s", max_ibytes, "Ibytes", + max_obytes, "Obytes"); + } else { + printf(" %*s %*s", max_ipkts, "Ipkts", + max_ierrs, "Ierrs"); + if (bflag) + printf(" %*s", max_ibytes, "Ibytes"); + + printf(" %*s %*s", max_opkts, "Opkts", + max_oerrs, "Oerrs"); + if (bflag) + printf(" %*s", max_obytes, "Obytes"); + + printf(" %*s", max_outq, "Queue"); + } + /* if (tflag) + printf(" %s", "Time"); + */ + if (dflag) + printf(" %s", "Drop"); + putchar('\n'); + + for (cur_if = if_head; cur_if; cur_if=cur_if->next) { + if (cur_if->name[0] == 0) + continue; + printf( "%*.*s %5d", -max_name, max_name, cur_if->name, cur_if->mtu); + printf(" %*.*s", -max_route, max_route, cur_if->route); + printf(" %*.*s", -max_ip, max_ip, cur_if->ip); + + if (oflag) { + printf(" %*s %*s", max_ibytes, cur_if->s_ibytes, + max_obytes, cur_if->s_obytes); + } else { + printf(" %*s %*s", max_ipkts, cur_if->s_ipkts, + max_ierrs, cur_if->s_ierrs); + if (bflag) + printf(" %*s", max_ibytes, cur_if->s_ibytes); + + printf(" %*s %*s", max_opkts, cur_if->s_opkts, + max_oerrs, cur_if->s_oerrs); + if (bflag) + printf(" %*s", max_obytes, cur_if->s_obytes); + printf(" %*s", max_outq, cur_if->s_outq); + } + /* if (tflag) + printf(" %4d", cur_if->???); + */ + if (dflag) + printf(" %4d", cur_if->drops); + putchar('\n'); + } + + /* + * ... and tidy up. + */ + for (cur_if = if_head; cur_if; cur_if=if_head) { + if_head=cur_if->next; + cur_if->next = NULL; + SNMP_FREE( cur_if ); + } +} + + +#define MAXIF 100 +struct iftot { + char ift_name[128]; /* interface name */ + int ifIndex; + u_long ift_ip; /* input packets */ + u_long ift_ib; /* input bytes */ + u_long ift_ie; /* input errors */ + u_long ift_op; /* output packets */ + u_long ift_ob; /* output bytes */ + u_long ift_oe; /* output errors */ + u_long ift_co; /* collisions */ + u_long ift_dr; /* drops */ +}; + +int signalled; /* set if alarm goes off "early" */ + +/* + * Print a running summary of interface statistics. + * Repeat display every interval seconds, showing statistics + * collected over that interval. Assumes that interval is non-zero. + * First line printed at top of screen is always cumulative. + */ +static void +sidewaysintpr(unsigned int interval) +{ + /* + * As with the "one-shot" interface display, there are + * two different possible output formats. The Net/ + * Open-BSD style displays both information about a + * single interface *and* the overall totals. + * The equivalent Free-BSD approach is to report on one + * or the other (rather than both). This is probably + * more useful (IMO), and significantly more efficient. + * So that's the style implemented here. + * + * Note that the 'ifcol' OID buffer can represent a full + * instance (including ifIndex), rather than just a + * column object OID, as with the one-shot code. + */ + oid ifcol_oid[] = { 1,3,6,1,2,1,2,2,1,0,0 }; + size_t ifcol_len = OID_LENGTH( ifcol_oid ); + netsnmp_variable_list *var, *vp; + struct iftot *ip = NULL, *cur_if = NULL; /* single I/F display */ + struct iftot *sum = NULL, *total = NULL; /* overall summary */ + int line; + int first; + int i; + + var = NULL; + if ( intrface ) { + /* + * Locate the ifIndex of the interface to monitor, + * by walking the ifDescr column of the ifTable + */ + ifcol_oid[ ifcol_len-2 ] = 2; /* ifDescr */ + snmp_varlist_add_variable( &var, ifcol_oid, ifcol_len-1, + ASN_NULL, NULL, 0); + i = strlen(intrface); + netsnmp_query_walk( var, ss ); + for (vp=var; vp; vp=vp->next_variable) { + if (strncmp(intrface, (char *)vp->val.string, i) == 0 && + i == vp->val_len) + break; /* found requested interface */ + } + /* + * XXX - Might be worth searching ifName/ifAlias as well + */ + if (!vp) { + fprintf(stderr, "%s: unknown interface\n", intrface ); + exit(1); + } + + /* + * Prepare the current and previous 'iftot' structures, + * and set the ifIndex value in the OID buffer. + */ + ip = SNMP_MALLOC_TYPEDEF( struct iftot ); + cur_if = SNMP_MALLOC_TYPEDEF( struct iftot ); + if (!ip || !cur_if) { + fprintf(stderr, "internal error\n"); + exit(1); + } + ifcol_oid[ ifcol_len-1 ] = vp->name[ ifcol_len-1 ]; + snmp_free_var( var ); + var = NULL; + } else { + /* + * Prepare the current and previous 'iftot' structures. + * (using different pointers, for consistency with *BSD code) + */ + sum = SNMP_MALLOC_TYPEDEF( struct iftot ); + total = SNMP_MALLOC_TYPEDEF( struct iftot ); + if (!sum || !total) { + fprintf(stderr, "internal error\n"); + exit(1); + } + } + + timerSet( interval ); + first = 1; +banner: + printf( "%17s %14s %16s", "input", + intrface ? intrface : "(Total)", "output"); + putchar('\n'); + printf( "%10s %5s %10s %10s %5s %10s %5s", + "packets", "errs", "bytes", "packets", "errs", "bytes", "colls"); + if (dflag) + printf(" %5.5s", "drops"); + putchar('\n'); + fflush(stdout); + line = 0; +loop: + if ( intrface ) { +#define ADD_IFVAR( x ) ifcol_oid[ ifcol_len-2 ] = x; \ + snmp_varlist_add_variable( &var, ifcol_oid, ifcol_len, ASN_NULL, NULL, 0) + /* if (bflag) { */ + ADD_IFVAR( 10 ); /* ifInOctets */ + ADD_IFVAR( 16 ); /* ifOutOctets */ + /* } */ + ADD_IFVAR( 11 ); /* ifInUcastPkts */ + ADD_IFVAR( 12 ); /* ifInNUcastPkts */ + ADD_IFVAR( 14 ); /* ifInErrors */ + ADD_IFVAR( 17 ); /* ifOutUcastPkts */ + ADD_IFVAR( 18 ); /* ifOutNUcastPkts */ + ADD_IFVAR( 20 ); /* ifOutErrors */ + ADD_IFVAR( 21 ); /* ifOutQLen */ + if (dflag) { + ADD_IFVAR( 19 ); /* ifOutDiscards */ + } +#undef ADD_IFVAR + + netsnmp_query_get( var, ss ); /* Or parallel walk ?? */ + cur_if->ift_ip = 0; + cur_if->ift_ib = 0; + cur_if->ift_ie = 0; + cur_if->ift_op = 0; + cur_if->ift_ob = 0; + cur_if->ift_oe = 0; + cur_if->ift_co = 0; + cur_if->ift_dr = 0; + cur_if->ifIndex = var->name[ ifcol_len-1 ]; + for (vp=var; vp; vp=vp->next_variable) { + if ( ! vp->val.integer ) + continue; + switch (vp->name[ifcol_len-2]) { + case 10: /* ifInOctets */ + cur_if->ift_ib = *vp->val.integer; + break; + case 11: /* ifInUcastPkts */ + cur_if->ift_ip += *vp->val.integer; + break; + case 12: /* ifInNUcastPkts */ + cur_if->ift_ip += *vp->val.integer; + break; + case 14: /* ifInErrors */ + cur_if->ift_ie = *vp->val.integer; + break; + case 16: /* ifOutOctets */ + cur_if->ift_ob = *vp->val.integer; + break; + case 17: /* ifOutUcastPkts */ + cur_if->ift_op += *vp->val.integer; + break; + case 18: /* ifOutNUcastPkts */ + cur_if->ift_op += *vp->val.integer; + break; + case 19: /* ifOutDiscards */ + cur_if->ift_dr = *vp->val.integer; + break; + case 20: /* ifOutErrors */ + cur_if->ift_oe = *vp->val.integer; + break; + case 21: /* ifOutQLen */ + cur_if->ift_co = *vp->val.integer; + break; + } + } + snmp_free_varbind( var ); + var = NULL; + + if (!first) { + printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu", + cur_if->ift_ip - ip->ift_ip, + cur_if->ift_ie - ip->ift_ie, + cur_if->ift_ib - ip->ift_ib, + cur_if->ift_op - ip->ift_op, + cur_if->ift_oe - ip->ift_oe, + cur_if->ift_ob - ip->ift_ob, + cur_if->ift_co - ip->ift_co); + if (dflag) + printf(" %5lu", cur_if->ift_dr - ip->ift_dr); + putchar('\n'); + fflush(stdout); + } + ip->ift_ip = cur_if->ift_ip; + ip->ift_ie = cur_if->ift_ie; + ip->ift_ib = cur_if->ift_ib; + ip->ift_op = cur_if->ift_op; + ip->ift_oe = cur_if->ift_oe; + ip->ift_ob = cur_if->ift_ob; + ip->ift_co = cur_if->ift_co; + ip->ift_dr = cur_if->ift_dr; + } /* (single) interface */ + else { + sum->ift_ip = 0; + sum->ift_ib = 0; + sum->ift_ie = 0; + sum->ift_op = 0; + sum->ift_ob = 0; + sum->ift_oe = 0; + sum->ift_co = 0; + sum->ift_dr = 0; +#define ADD_IFVAR( x ) ifcol_oid[ ifcol_len-2 ] = x; \ + snmp_varlist_add_variable( &var, ifcol_oid, ifcol_len-1, ASN_NULL, NULL, 0) + ADD_IFVAR( 11 ); /* ifInUcastPkts */ + ADD_IFVAR( 12 ); /* ifInNUcastPkts */ + ADD_IFVAR( 14 ); /* ifInErrors */ + ADD_IFVAR( 17 ); /* ifOutUcastPkts */ + ADD_IFVAR( 18 ); /* ifOutNUcastPkts */ + ADD_IFVAR( 20 ); /* ifOutErrors */ + ADD_IFVAR( 21 ); /* ifOutQLen */ + /* if (bflag) { */ + ADD_IFVAR( 10 ); /* ifInOctets */ + ADD_IFVAR( 16 ); /* ifOutOctets */ + /* } */ + if (dflag) { + ADD_IFVAR( 19 ); /* ifOutDiscards */ + } +#undef ADD_IFVAR + + ifcol_oid[ ifcol_len-2 ] = 11; /* ifInUcastPkts */ + while ( 1 ) { + if (netsnmp_query_getnext( var, ss ) != SNMP_ERR_NOERROR) + break; + if ( snmp_oid_compare( ifcol_oid, ifcol_len-2, + var->name, ifcol_len-2) != 0 ) + break; /* End of Table */ + + for ( vp=var; vp; vp=vp->next_variable ) { + if ( ! vp->val.integer ) + continue; + switch ( vp->name[ ifcol_len-2 ] ) { + case 10: /* ifInOctets */ + sum->ift_ib += *vp->val.integer; + break; + case 11: /* ifInUcastPkts */ + sum->ift_ip += *vp->val.integer; + break; + case 12: /* ifInNUcastPkts */ + sum->ift_ip += *vp->val.integer; + break; + case 14: /* ifInErrors */ + sum->ift_ie += *vp->val.integer; + break; + case 16: /* ifOutOctets */ + sum->ift_ob += *vp->val.integer; + break; + case 17: /* ifOutUcastPkts */ + sum->ift_op += *vp->val.integer; + break; + case 18: /* ifOutNUcastPkts */ + sum->ift_op += *vp->val.integer; + break; + case 19: /* ifOutDiscards */ + sum->ift_dr += *vp->val.integer; + break; + case 20: /* ifOutErrors */ + sum->ift_oe += *vp->val.integer; + break; + case 21: /* ifOutQLen */ + sum->ift_co += *vp->val.integer; + break; + } + } + /* + * Now loop to retrieve the next entry from the table. + */ + } /* while (1) */ + + snmp_free_varbind( var ); + var = NULL; + + if (!first) { + printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu", + sum->ift_ip - total->ift_ip, + sum->ift_ie - total->ift_ie, + sum->ift_ib - total->ift_ib, + sum->ift_op - total->ift_op, + sum->ift_oe - total->ift_oe, + sum->ift_ob - total->ift_ob, + sum->ift_co - total->ift_co); + if (dflag) + printf(" %5lu", sum->ift_dr - total->ift_dr); + putchar('\n'); + fflush(stdout); + } + total->ift_ip = sum->ift_ip; + total->ift_ie = sum->ift_ie; + total->ift_ib = sum->ift_ib; + total->ift_op = sum->ift_op; + total->ift_oe = sum->ift_oe; + total->ift_ob = sum->ift_ob; + total->ift_co = sum->ift_co; + total->ift_dr = sum->ift_dr; + } /* overall summary */ + + timerPause(); + timerSet(interval); + line++; + first = 0; + if (line == 21) + goto banner; + else + goto loop; + /*NOTREACHED*/ +} + + +/* + * timerSet sets or resets the timer to fire in "interval" seconds. + * timerPause waits only if the timer has not fired. + * timing precision is not considered important. + */ + +#if (defined(WIN32) || defined(cygwin)) +static int sav_int; +static time_t timezup; +static void +timerSet(int interval_seconds) +{ + sav_int = interval_seconds; + timezup = time(0) + interval_seconds; +} + +/* + * you can do better than this ! + */ +static void +timerPause(void) +{ + time_t now; + while (time(&now) < timezup) +#ifdef WIN32 + Sleep(400); +#else + { + struct timeval tx; + tx.tv_sec = 0; + tx.tv_usec = 400 * 1000; /* 400 milliseconds */ + select(0, 0, 0, 0, &tx); + } +#endif +} + +#else + +/* + * Called if an interval expires before sidewaysintpr has completed a loop. + * Sets a flag to not wait for the alarm. + */ +RETSIGTYPE +catchalarm(int sig) +{ + signalled = YES; +} + +static void +timerSet(int interval_seconds) +{ +#ifdef HAVE_SIGSET + (void) sigset(SIGALRM, catchalarm); +#else + (void) signal(SIGALRM, catchalarm); +#endif + signalled = NO; + (void) alarm(interval_seconds); +} + +static void +timerPause(void) +{ +#ifdef HAVE_SIGHOLD + sighold(SIGALRM); + if (!signalled) { + sigpause(SIGALRM); + } +#else + int oldmask; + oldmask = sigblock(sigmask(SIGALRM)); + if (!signalled) { + sigpause(0); + } + sigsetmask(oldmask); +#endif +} + +#endif /* !WIN32 && !cygwin */ |