
SNMP & Protocols, Network Monitoring
Interface counters explained: octets, errors, discards and the 32-bit wrap
An interface graph is two numbers subtracted from each other and divided by the time between them. Nearly every argument I have seen about a "wrong" graph came down to one of three things: the tool read a different counter than people assumed, the counter wrapped or reset between readings, or someone read errors and discards as the same thing. This piece walks through the counters in IF-MIB, then works through the arithmetic with real-looking numbers, including the case where a 600 Mbit/s port graphs as 27.
The counters you will actually use
IF-MIB, defined in RFC 2863, gives every interface two tables:
ifTable with the original 32-bit counters and ifXTable with the high-capacity ones and a few extras. These
are the objects that matter for traffic and health:
| Object | OID | Type | Counts |
|---|---|---|---|
ifInOctets / ifOutOctets |
1.3.6.1.2.1.2.2.1.10 / .16 | Counter32 | Bytes in and out, framing included |
ifHCInOctets / ifHCOutOctets |
1.3.6.1.2.1.31.1.1.1.6 / .10 | Counter64 | The same bytes, 64 bits wide |
ifHCInUcastPkts |
1.3.6.1.2.1.31.1.1.1.7 | Counter64 | Unicast packets delivered upward |
ifHCInMulticastPkts / ifHCInBroadcastPkts |
1.3.6.1.2.1.31.1.1.1.8 / .9 | Counter64 | Multicast and broadcast packets |
ifInDiscards / ifOutDiscards |
1.3.6.1.2.1.2.2.1.13 / .19 | Counter32 | Good packets dropped anyway |
ifInErrors / ifOutErrors |
1.3.6.1.2.1.2.2.1.14 / .20 | Counter32 | Packets that could not be delivered because of errors |
ifSpeed |
1.3.6.1.2.1.2.2.1.5 | Gauge32 | Speed in bits per second |
ifHighSpeed |
1.3.6.1.2.1.31.1.1.1.15 | Gauge32 | Speed in units of 1,000,000 bits per second |
ifCounterDiscontinuityTime |
1.3.6.1.2.1.31.1.1.1.19 | TimeStamp | When this interface's counters last broke continuity |
The old ifInNUcastPkts lumped multicast and broadcast together and is deprecated; use the separate columns.
Errors and discards exist only as 32-bit counters, which is fine, because they count problem packets and rarely
climb fast enough to wrap.
Octets: the 32-bit and the 64-bit pair
ifInOctets and ifHCInOctets count the same bytes. The difference is where they roll over: a Counter32 wraps
at 4,294,967,296, a Counter64 at about 18.4 quintillion. RFC 2863 asks for 64-bit octet counters on interfaces
faster than 20 Mbit/s and 64-bit packet counters as well from 650 Mbit/s up, and the reason is in the wrap times:
34.4 seconds for a 32-bit octet counter at 1 Gbit/s, 3.4 seconds at 10 Gbit/s. Reading the 64-bit columns needs
SNMP v2c or v3, which is covered in the SNMP versions article.
"Framing included" means the octet counters usually include the Ethernet header and the frame check sequence, but not the preamble or the gap between frames. That is why a saturated port never graphs at exactly 100 percent. With minimum-size 64-byte frames, each frame takes 84 bytes of wire time, so the octet counters top out near 76 percent of line rate. With full 1,518-byte frames they reach about 98.7 percent. Implementations differ a little here, so treat the last percent or two of any utilization graph with suspicion.
On some platforms, virtual interfaces (VLAN interfaces, tunnels, port-channel members) return the high-capacity columns as zero or not at all. Before you trust a flat line, walk the column once by hand.
Speed: ifSpeed and ifHighSpeed
ifSpeed is a Gauge32 in bits per second, so it cannot go above 4,294,967,295. Any interface faster than that
reports exactly 4,294,967,295 and leaves the real figure to ifHighSpeed, in megabits. A 10 Gbit/s port looks
like this:
IF-MIB::ifSpeed.49 = Gauge32: 4294967295
IF-MIB::ifHighSpeed.49 = Gauge32: 10000
A tool that divides by ifSpeed will draw a 10 Gbit/s port running at 4 Gbit/s as 93 percent full. Use
ifHighSpeed everywhere and multiply by 1,000,000. Two more traps: on many routers the speed of a tunnel or
subinterface is whatever bandwidth value someone configured, not a physical rate, and a port that is down may
report its maximum speed or zero depending on the vendor. The interface types guide
covers how a monitor should treat the different kinds of interface.
Full duplex links have the full speed in each direction. A 1 Gbit/s port at 600 Mbit/s in and 600 Mbit/s out is 60 percent used, not 120.
Worked example 1: two readings to a rate
A switch uplink, interface index 49, 1 Gbit/s. The poller reads it twice:
snmpget -v2c -c n0c-r34d 10.20.0.2 IF-MIB::ifHCInOctets.49 IF-MIB::ifHighSpeed.49
14:00:00 IF-MIB::ifHCInOctets.49 = Counter64: 918274650112
14:05:02 IF-MIB::ifHCInOctets.49 = Counter64: 930052650112
IF-MIB::ifHighSpeed.49 = Gauge32: 1000
The second poll ran two seconds late, which happens all the time on a busy poller. The arithmetic:
delta bytes = 930052650112 - 918274650112 = 11778000000
delta bits = 11778000000 * 8 = 94224000000
elapsed = 302 seconds
rate = 94224000000 / 302 = 312000000 bit/s (312 Mbit/s)
utilization = 312 / 1000 = 31.2 percent
Divide by the nominal 300 seconds instead of the measured 302 and you get 314.08 Mbit/s, about two-thirds of a
percent too high. Small here, larger when a poll is 20 seconds late, which is why rates should always use the
timestamps the poller recorded. If ifHCInUcastPkts went up by 8,600,000 in the same window, the port moved about
28,477 packets per second with an average size near 1,370 bytes, which looks like bulk transfers rather than
voice or chatty small-packet traffic. The counter rate calculator does this
arithmetic for you if you paste in two readings.
Worked example 2: the wrap that hides 95 percent of the traffic
Now the same port read through the 32-bit ifInOctets, with a steady 600 Mbit/s (75,000,000 bytes per second)
coming in.
Polled every 30 seconds, the first reading is 3,500,000,000 and the second is 1,455,032,704. The second is smaller, so the poller assumes one wrap:
delta bytes = (4294967296 - 3500000000) + 1455032704 = 2250000000
rate = 2250000000 * 8 / 30 = 600000000 bit/s
Correct, because exactly one wrap happened. Now poll every 300 seconds. The port really moved 22,500,000,000 bytes, which is 5.24 trips around a 32-bit counter. The poller only ever sees the remainder:
true bytes = 75000000 * 300 = 22500000000
seen bytes = 22500000000 mod 2^32 = 1025163520
graphed rate = 1025163520 * 8 / 300 = 27337694 bit/s
The graph shows 27 Mbit/s for a port carrying 600. Nothing about it looks broken, which is the dangerous part: a plausible small number on a busy uplink. The fix is the 64-bit counter, not a shorter interval, and the interval side of the story is in choosing a polling interval.
Resets are not wraps
A reading that goes down can mean a wrap, but it can also mean the agent restarted, a line card was reset, the interface was deleted and re-created, or someone cleared counters on a platform where that touches SNMP. Treat them differently:
- On a Counter64, assume a decrease is a reset, never a wrap, and drop that sample.
- Read
sysUpTime(1.3.6.1.2.1.1.3.0) with every poll. If it went down, the agent restarted and every counter on the box is suspect for that interval. - Read
ifCounterDiscontinuityTimewhere the agent supports it. If it changed, that interface had a break even though the device did not reboot. - Discard any computed rate above
ifHighSpeed. RRD-based tools do this for you if the data source has a sensible maximum, storing the sample as unknown instead of a spike.
Errors and discards on a real port
They sound similar and mean very different things.
ifInErrors counts received packets that could not be delivered because something was wrong with them. On
Ethernet that is mostly frames that failed the checksum, plus runts, oversized frames and alignment errors. The
cause is nearly always physical: a crushed patch cable, a bad keystone, a dirty fiber connector, a failing
optic, or a duplex mismatch. In the mismatch case, the full-duplex side logs checksum errors and runts, and the
half-duplex side logs late collisions.
ifOutDiscards counts packets the port was told to send and dropped because its queue was full. That is
congestion, not a cable fault. ifInDiscards is fuzzier, and what lands in it varies by vendor: full input
queues, policy drops, frames for VLANs the port does not carry.
Worked example 3: errors on a desk port
A desk port over five minutes: ifHCInUcastPkts went up by 2,400,000 and ifInErrors by 1,850. Unicast
packets that arrive with errors are not counted as delivered, so the share of bad packets is errors divided by
everything that arrived, ignoring the small multicast and broadcast counts:
1850 / (2400000 + 1850) = 0.077 percent, about 6 errors per second
That number should be zero. A healthy wired link logs no input errors at all, apart from a few at the moment a cable is plugged in or the link renegotiates. Six a second, steadily, is a cable or optic to replace, and the far end's counters usually tell you which side to start with.
Worked example 4: discards on a server port
A 1 Gbit/s port feeding a file server from a 10 Gbit/s uplink. Over five minutes, ifHCOutUcastPkts went up by
12,000,000 and ifOutDiscards by 9,000, while average utilization in that window was 35 percent. The output
packet counters include packets that were later discarded, so the share is simply:
9000 / 12000000 = 0.075 percent, 30 discards per second
At 35 percent average load this is microbursts: the 10 Gbit/s side delivers bursts faster than the 1 Gbit/s port can drain them, the buffer fills for a few milliseconds and the tail of the burst is dropped. TCP recovers, users see slow copies, and the 5-minute utilization graph insists the port is fine. The fixes are about capacity and buffers (a faster server link, queue tuning, spreading the load), not cabling.
Since counters are cumulative from boot, alert on the rate of errors and discards, never on the raw total. A port with 40,000 errors since last year and none this week is healthy. The alert fatigue article has more on keeping those alerts worth reading.
Unicast, multicast and broadcast
The three packet columns tell you what kind of traffic you have. Broadcast is mostly ARP, DHCP and discovery chatter and should be a low, steady background. A sudden broadcast jump on many ports in the same VLAN at the same moment is the signature of a loop or a broadcast storm. A multicast jump on access ports often means IGMP snooping is off and a stream is being flooded everywhere.
What I check first when a port is "slow"
ifOperStatusandifHighSpeed: did it come up at 100 Mbit/s instead of 1,000?- The rate of
ifInErrorson both ends of the link. - The rate of
ifOutDiscardson the port facing the person who is complaining. - Utilization per direction at 1-minute resolution, from the 64-bit counters.
- Broadcast and multicast rates, if the whole VLAN is slow and not just one port.
Most of the time the answer is in steps 1 to 3, and none of them needs a packet capture.


