From c6a4e65805493d60db441038b190794c13cbed07 Mon Sep 17 00:00:00 2001 From: Hartmut Brandt Date: Mon, 13 Feb 2006 14:11:18 +0000 Subject: [PATCH] Vendor fix: make mibII HC counters really 64-bit on 32-bit platforms by polling the kernel periodically. Submitted by: glebius (partly) --- contrib/bsnmp/oid-list | 1 + contrib/bsnmp/snmp_mibII/mibII.c | 159 +++++++++++++++++++- contrib/bsnmp/snmp_mibII/mibII.h | 32 +++- contrib/bsnmp/snmp_mibII/mibII_interfaces.c | 14 +- contrib/bsnmp/snmp_mibII/mibII_tree.def | 17 +++ contrib/bsnmp/snmp_mibII/snmp_mibII.h | 3 + 6 files changed, 207 insertions(+), 19 deletions(-) diff --git a/contrib/bsnmp/oid-list b/contrib/bsnmp/oid-list index 32a1c0e8c54c..c831f15fd6ec 100644 --- a/contrib/bsnmp/oid-list +++ b/contrib/bsnmp/oid-list @@ -11,6 +11,7 @@ enterprises 1 BEGEMOT 1 BEGEMOT-SNMPD 2 BEGEMOT-NETGRAPH snmpd netgraph module + 3 BEGEMOT-IP snmpd mibII module 100 BEGEMOT-ILMID snmpd ILMID module 101 BEGEMOT-ATM snmpd ATM module 200 BEGEMOT-PF snmpd PF module (phillip@freebsd.org) diff --git a/contrib/bsnmp/snmp_mibII/mibII.c b/contrib/bsnmp/snmp_mibII/mibII.c index 98a16d4c4726..9dbec012e377 100644 --- a/contrib/bsnmp/snmp_mibII/mibII.c +++ b/contrib/bsnmp/snmp_mibII/mibII.c @@ -105,6 +105,18 @@ struct clockinfo clockinfo; /* list of all New if registrations */ static struct newifreg_list newifreg_list = TAILQ_HEAD_INITIALIZER(newifreg_list); +/* baud rate of fastest interface */ +uint64_t mibif_maxspeed; + +/* user-forced update interval */ +u_int mibif_force_hc_update_interval; + +/* current update interval */ +u_int mibif_hc_update_interval; + +/* HC update timer handle */ +static void *hc_update_timer; + /*****************************/ static const struct asn_oid oid_ifMIB = OIDX_ifMIB; @@ -280,16 +292,15 @@ link_trap(struct mibif *ifp, int up) (struct snmp_value *)NULL); } -/* - * Fetch new MIB data. +/** + * Fetch the GENERIC IFMIB and update the HC counters */ -int -mib_fetch_ifmib(struct mibif *ifp) +static int +fetch_generic_mib(struct mibif *ifp, const struct ifmibdata *old) { int name[6]; size_t len; - void *newmib; - struct ifmibdata oldmib = ifp->mib; + struct mibif_private *p = ifp->private; name[0] = CTL_NET; name[1] = PF_LINK; @@ -306,6 +317,113 @@ mib_fetch_ifmib(struct mibif *ifp) return (-1); } + /* + * Assume that one of the two following compounds is optimized away + */ + if (ULONG_MAX >= 0xffffffffffffffffULL) { + p->hc_inoctets = ifp->mib.ifmd_data.ifi_ibytes; + p->hc_outoctets = ifp->mib.ifmd_data.ifi_obytes; + p->hc_omcasts = ifp->mib.ifmd_data.ifi_omcasts; + p->hc_opackets = ifp->mib.ifmd_data.ifi_opackets; + p->hc_imcasts = ifp->mib.ifmd_data.ifi_imcasts; + p->hc_ipackets = ifp->mib.ifmd_data.ifi_ipackets; + + } else if (ULONG_MAX >= 0xffffffff) { + +#define UPDATE(HC, MIB) \ + if (old->ifmd_data.MIB > ifp->mib.ifmd_data.MIB) \ + p->HC += (0x100000000ULL + \ + ifp->mib.ifmd_data.MIB) - \ + old->ifmd_data.MIB; \ + else \ + p->HC += ifp->mib.ifmd_data.MIB - \ + old->ifmd_data.MIB; + + UPDATE(hc_inoctets, ifi_ibytes) + UPDATE(hc_outoctets, ifi_obytes) + UPDATE(hc_omcasts, ifi_omcasts) + UPDATE(hc_opackets, ifi_opackets) + UPDATE(hc_imcasts, ifi_imcasts) + UPDATE(hc_ipackets, ifi_ipackets) + +#undef UPDATE + } else + abort(); + return (0); +} + +/** + * Update the 64-bit interface counters + */ +static void +update_hc_counters(void *arg __unused) +{ + struct mibif *ifp; + struct ifmibdata oldmib; + + TAILQ_FOREACH(ifp, &mibif_list, link) { + oldmib = ifp->mib; + (void)fetch_generic_mib(ifp, &oldmib); + } +} + +/** + * Recompute the poll timer for the HC counters + */ +void +mibif_reset_hc_timer(void) +{ + u_int ticks; + + if ((ticks = mibif_force_hc_update_interval) == 0) { + if (mibif_maxspeed <= 10000000) { + /* at 10Mbps overflow needs 3436 seconds */ + ticks = 3000 * 100; /* 50 minutes */ + } else if (mibif_maxspeed <= 100000000) { + /* at 100Mbps overflow needs 343 seconds */ + ticks = 300 * 100; /* 5 minutes */ + } else if (mibif_maxspeed < 650000000) { + /* at 622Mbps overflow needs 53 seconds */ + ticks = 40 * 100; /* 40 seconds */ + } else if (mibif_maxspeed <= 1000000000) { + /* at 1Gbps overflow needs 34 seconds */ + ticks = 20 * 100; /* 20 seconds */ + } else { + /* at 10Gbps overflow needs 3.4 seconds */ + ticks = 100; /* 1 seconds */ + } + } + + if (ticks == mibif_hc_update_interval) + return; + + if (hc_update_timer != NULL) { + timer_stop(hc_update_timer); + hc_update_timer = NULL; + } + update_hc_counters(NULL); + if ((hc_update_timer = timer_start_repeat(ticks * 10, ticks * 10, + update_hc_counters, NULL, module)) == NULL) { + syslog(LOG_ERR, "timer_start(%u): %m", ticks); + return; + } + mibif_hc_update_interval = ticks; +} + +/* + * Fetch new MIB data. + */ +int +mib_fetch_ifmib(struct mibif *ifp) +{ + int name[6]; + size_t len; + void *newmib; + struct ifmibdata oldmib = ifp->mib; + + if (fetch_generic_mib(ifp, &oldmib) == -1) + return (-1); + /* * Quoting RFC2863, 3.1.15: "... LinkUp and linkDown traps are * generated just after ifOperStatus leaves, or just before it @@ -324,10 +442,19 @@ mib_fetch_ifmib(struct mibif *ifp) if (ifp->mib.ifmd_data.ifi_baudrate > 650000000) ifp->flags |= MIBIF_VERYHIGHSPEED; } + if (ifp->mib.ifmd_data.ifi_baudrate > mibif_maxspeed) { + mibif_maxspeed = ifp->mib.ifmd_data.ifi_baudrate; + mibif_reset_hc_timer(); + } /* * linkspecific MIB */ + name[0] = CTL_NET; + name[1] = PF_LINK; + name[2] = NETLINK_GENERIC; + name[3] = IFMIB_IFDATA; + name[4] = ifp->sysindex; name[5] = IFDATA_LINKSPECIFIC; if (sysctl(name, 6, NULL, &len, NULL, 0) == -1) { syslog(LOG_WARNING, "sysctl linkmib estimate (%s): %m", @@ -519,6 +646,7 @@ get_physaddr(struct mibif *ifp, struct sockaddr_dl *sdl, u_char *ptr) static void mibif_free(struct mibif *ifp) { + struct mibif *ifp1; struct mibindexmap *map; struct mibifa *ifa, *ifa1; struct mibrcvaddr *rcv, *rcv1; @@ -531,6 +659,18 @@ mibif_free(struct mibif *ifp) (void)mib_ifstack_delete(NULL, ifp); TAILQ_REMOVE(&mibif_list, ifp, link); + + /* if this was the fastest interface - recompute this */ + if (ifp->mib.ifmd_data.ifi_baudrate == mibif_maxspeed) { + mibif_maxspeed = ifp->mib.ifmd_data.ifi_baudrate; + TAILQ_FOREACH(ifp1, &mibif_list, link) + if (ifp1->mib.ifmd_data.ifi_baudrate > mibif_maxspeed) + mibif_maxspeed = + ifp1->mib.ifmd_data.ifi_baudrate; + mibif_reset_hc_timer(); + } + + free(ifp->private); if (ifp->physaddr != NULL) free(ifp->physaddr); if (ifp->specmib != NULL) @@ -589,6 +729,13 @@ mibif_create(u_int sysindex, const char *name) return (NULL); } memset(ifp, 0, sizeof(*ifp)); + if ((ifp->private = malloc(sizeof(struct mibif_private))) == NULL) { + syslog(LOG_WARNING, "%s: %m", __func__); + free(ifp); + return (NULL); + } + memset(ifp->private, 0, sizeof(struct mibif_private)); + ifp->sysindex = sysindex; strcpy(ifp->name, name); strcpy(ifp->descr, name); diff --git a/contrib/bsnmp/snmp_mibII/mibII.h b/contrib/bsnmp/snmp_mibII/mibII.h index 4b0803d12f2b..65c14cc1f9f8 100644 --- a/contrib/bsnmp/snmp_mibII/mibII.h +++ b/contrib/bsnmp/snmp_mibII/mibII.h @@ -56,7 +56,6 @@ #include "snmp_mibII.h" #include "mibII_tree.h" - /* * Interface list and flags. */ @@ -66,12 +65,19 @@ enum { MIBIF_HIGHSPEED = 0x0002, MIBIF_VERYHIGHSPEED = 0x0004, }; -#define hc_inoctets mib.ifmd_data.ifi_ibytes -#define hc_outoctets mib.ifmd_data.ifi_obytes -#define hc_omcasts mib.ifmd_data.ifi_omcasts -#define hc_opackets mib.ifmd_data.ifi_opackets -#define hc_imcasts mib.ifmd_data.ifi_imcasts -#define hc_ipackets mib.ifmd_data.ifi_ipackets + +/* + * Private mibif data - hang off from the mibif. + */ +struct mibif_private { + uint64_t hc_inoctets; + uint64_t hc_outoctets; + uint64_t hc_omcasts; + uint64_t hc_opackets; + uint64_t hc_imcasts; + uint64_t hc_ipackets; +}; +#define MIBIF_PRIV(IFP) ((struct mibif_private *)((IFP)->private)) /* * Interface addresses. @@ -193,6 +199,18 @@ extern uint64_t mibarpticks; /* info on system clocks */ extern struct clockinfo clockinfo; +/* baud rate of fastest interface */ +extern uint64_t mibif_maxspeed; + +/* user-forced update interval */ +extern u_int mibif_force_hc_update_interval; + +/* current update interval */ +extern u_int mibif_hc_update_interval; + +/* re-compute update interval */ +void mibif_reset_hc_timer(void); + /* get interfaces and interface addresses. */ void mib_fetch_interfaces(void); diff --git a/contrib/bsnmp/snmp_mibII/mibII_interfaces.c b/contrib/bsnmp/snmp_mibII/mibII_interfaces.c index d3211d01192a..50ad630ecf47 100644 --- a/contrib/bsnmp/snmp_mibII/mibII_interfaces.c +++ b/contrib/bsnmp/snmp_mibII/mibII_interfaces.c @@ -463,19 +463,20 @@ op_ifxtable(struct snmp_context *ctx, struct snmp_value *value, case LEAF_ifHCInOctets: if (!(ifp->flags & MIBIF_HIGHSPEED)) goto again; - value->v.counter64 = ifp->hc_inoctets; + value->v.counter64 = MIBIF_PRIV(ifp)->hc_inoctets; break; case LEAF_ifHCInUcastPkts: if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) goto again; - value->v.counter64 = ifp->hc_ipackets - ifp->hc_imcasts; + value->v.counter64 = MIBIF_PRIV(ifp)->hc_ipackets - + MIBIF_PRIV(ifp)->hc_imcasts; break; case LEAF_ifHCInMulticastPkts: if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) goto again; - value->v.counter64 = ifp->hc_imcasts; + value->v.counter64 = MIBIF_PRIV(ifp)->hc_imcasts; break; case LEAF_ifHCInBroadcastPkts: @@ -487,19 +488,20 @@ op_ifxtable(struct snmp_context *ctx, struct snmp_value *value, case LEAF_ifHCOutOctets: if (!(ifp->flags & MIBIF_HIGHSPEED)) goto again; - value->v.counter64 = ifp->hc_outoctets; + value->v.counter64 = MIBIF_PRIV(ifp)->hc_outoctets; break; case LEAF_ifHCOutUcastPkts: if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) goto again; - value->v.counter64 = ifp->hc_opackets - ifp->hc_omcasts; + value->v.counter64 = MIBIF_PRIV(ifp)->hc_opackets - + MIBIF_PRIV(ifp)->hc_omcasts; break; case LEAF_ifHCOutMulticastPkts: if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) goto again; - value->v.counter64 = ifp->hc_omcasts; + value->v.counter64 = MIBIF_PRIV(ifp)->hc_omcasts; break; case LEAF_ifHCOutBroadcastPkts: diff --git a/contrib/bsnmp/snmp_mibII/mibII_tree.def b/contrib/bsnmp/snmp_mibII/mibII_tree.def index f8e250dc7cc0..79e134561b7d 100644 --- a/contrib/bsnmp/snmp_mibII/mibII_tree.def +++ b/contrib/bsnmp/snmp_mibII/mibII_tree.def @@ -230,6 +230,23 @@ (50 udpMIB ) )) + (4 private + (1 enterprises + (12325 fokus + (1 begemot + (3 begemotIp + (1 begemotIpObjects + (1 begemotMib2 + (1 begemotIfMaxspeed COUNTER64 op_begemot_mibII GET) + (2 begemotIfPoll TIMETICKS op_begemot_mibII GET) + (3 begemotIfForcePoll TIMETICKS op_begemot_mibII GET SET) + ) + ) + ) + ) + ) + ) + ) (6 snmpV2 (3 snmpModules (1 snmpMIB diff --git a/contrib/bsnmp/snmp_mibII/snmp_mibII.h b/contrib/bsnmp/snmp_mibII/snmp_mibII.h index 98f2a728219c..93451843b06e 100644 --- a/contrib/bsnmp/snmp_mibII/snmp_mibII.h +++ b/contrib/bsnmp/snmp_mibII/snmp_mibII.h @@ -79,6 +79,9 @@ struct mibif { /* to be set by ifType specific modules. This is ifSpecific. */ struct asn_oid spec_oid; + + /* private data - don't touch */ + void *private; }; /*