Skip to content

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:

  1. On a Counter64, assume a decrease is a reset, never a wrap, and drop that sample.
  2. 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.
  3. Read ifCounterDiscontinuityTime where the agent supports it. If it changed, that interface had a break even though the device did not reboot.
  4. 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"

  1. ifOperStatus and ifHighSpeed: did it come up at 100 Mbit/s instead of 1,000?
  2. The rate of ifInErrors on both ends of the link.
  3. The rate of ifOutDiscards on the port facing the person who is complaining.
  4. Utilization per direction at 1-minute resolution, from the 64-bit counters.
  5. 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.