/* * $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. */ #include #include #include #if HAVE_UNISTD_H #include #endif #if HAVE_NET_IF_H #include #endif #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 1 #endif #ifndef _XOPEN_SOURCE_EXTENDED #define _XOPEN_SOURCE_EXTENDED 1 #endif #include #include "main.h" #include "netstat.h" #define YES 1 #define NO 0 static void sidewaysintpr(u_int); struct _if_info { char name[128]; char descr[128]; char ip[128], route[128]; int mtu; int drops; unsigned 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; }; static struct timeval deadline; static void timerSet(int interval_seconds) { const struct timeval interval = { interval_seconds, 0 }; netsnmp_get_monotonic_clock(&deadline); NETSNMP_TIMERADD(&deadline, &interval, &deadline); } static void timerPause(void) { struct timeval now, delta; netsnmp_get_monotonic_clock(&now); NETSNMP_TIMERSUB(&deadline, &now, &delta); if (delta.tv_sec < 0) return; #ifdef WIN32 Sleep(delta.tv_sec * 1000 + delta.tv_usec / 1000); #else if (select(0, NULL, NULL, NULL, &delta) < 0) snmp_perror("select"); #endif } /* * 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 == (int) cur_if->ifindex) break; } if (vp2) { /* * Always want a numeric interface IP address */ snprintf(cur_if->ip, 128, "%" NETSNMP_PRIo "u.%" NETSNMP_PRIo "u." "%" NETSNMP_PRIo "u.%" NETSNMP_PRIo "u", 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] = (uint8_t) vp2->name[10]; cp[1] = (uint8_t) vp2->name[11]; cp[2] = (uint8_t) vp2->name[12]; cp[3] = (uint8_t) vp2->name[13]; ifAddr = tmpAddr.addr; cp = tmpAddr.data; cp[0] = (uint8_t) vp2->val.string[0]; cp[1] = (uint8_t) vp2->val.string[1]; cp[2] = (uint8_t) vp2->val.string[2]; cp[3] = (uint8_t) vp2->val.string[3]; 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); oid ifxcol_oid[] = { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 0 }; size_t ifxcol_len = OID_LENGTH(ifxcol_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 #define ADD_IFXVAR( x ) ifxcol_oid[ ifxcol_len-1 ] = x; \ snmp_varlist_add_variable( &var, ifxcol_oid, ifxcol_len, ASN_NULL, NULL, 0) ADD_IFXVAR(1); /* ifName */ #undef ADD_IFXVAR /* * Now walk the ifTable, creating a list of interfaces */ while (1) { if (netsnmp_query_getnext(var, ss) != SNMP_ERR_NOERROR) break; if ((var->type & 0xF0) == 0x80) /* Exception */ 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->type & 0xF0) == 0x80) /* Exception */ continue; 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); 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; memmove(cur_if->descr, vp->val.string, vp->val_len); cur_if->descr[vp->val_len] = 0; 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; case 1: /* ifName */ 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; } } /* * 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 && strcmp(cur_if->descr, intrface) != 0) { SNMP_FREE(cur_if); } /* * Insert the IP address and network settings, and * add the new _if_stat structure to the list. */ if (cur_if) { if ((i = strlen(cur_if->name) + 1) > max_name) max_name = i; _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) */ snmp_free_varbind(var); /* * 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; size_t 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) { oid ifname_oid[] = { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 1, 0 }; size_t ifname_len = OID_LENGTH(ifname_oid); snmp_free_var(var); var = NULL; snmp_varlist_add_variable(&var, ifname_oid, ifname_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 */ } } if (!vp) { oid ifalias_oid[] = { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 18, 0 }; size_t ifalias_len = OID_LENGTH(ifalias_oid); snmp_free_var(var); var = NULL; snmp_varlist_add_variable(&var, ifalias_oid, ifalias_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 */ } } 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 ((var->type & 0xF0) == 0x80) /* Exception */ continue; 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 ((var->type & 0xF0) == 0x80) /* Exception */ 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->type & 0xF0) == 0x80) /* Exception */ continue; 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*/ }