Windows
banshee/windows-collection/windows/snmp/
interfaces
The state, traffic, errors and IPv4 addresses of each network interface of a Windows, by SNMP
by banshee1 installation2 versions
v2Latest
Published on October 28, 2026. One naming convention across collections; documentation completed.
// The network interfaces of a Windows, by SNMP (IF-MIB, IP-MIB): the state, the traffic and the errors of
// each link, and its IPv4 addresses. The software interfaces of Windows (loopback, tunnels, WAN
// Miniport, filters of the network stack) are left out by the default selection. Neither the duplex nor the
// link changes are served by the Windows SNMP agent.
need('protocol:snmp');
per('interface', 'Interfaces', array('ignore' => array(
'Software Loopback Interface*', 'WAN Miniport*', 'Microsoft ISATAP Adapter*', 'Teredo Tunneling*',
'Microsoft 6to4 Adapter*', 'Microsoft IP-HTTPS*', 'Microsoft Kernel Debug Network Adapter*',
'*-WFP Native MAC Layer LightWeight Filter-*', '*-WFP 802.3 MAC Layer LightWeight Filter-*',
'*-QoS Packet Scheduler-*', '*-Npcap Packet Driver*', '*-Virtual WiFi Filter Driver-*',
'*-Native WiFi Filter Driver-*',
)));
output('link', 'text', array('label' => 'Link state', 'per' => 'interface'));
output('speed', 'number', array('label' => 'Negotiated speed', 'unit' => 'Mbit/s', 'per' => 'interface'));
output('mtu', 'number', array('label' => 'MTU', 'per' => 'interface'));
output('traffic-in', 'number', array('label' => 'Inbound traffic', 'unit' => 'bit/s', 'per' => 'interface'));
output('traffic-out', 'number', array('label' => 'Outbound traffic', 'unit' => 'bit/s', 'per' => 'interface'));
output('traffic', 'number', array('label' => 'Total traffic', 'unit' => 'bit/s', 'per' => 'interface'));
output('in-percent', 'number', array('label' => 'Inbound usage', 'unit' => '%', 'per' => 'interface'));
output('out-percent', 'number', array('label' => 'Outbound usage', 'unit' => '%', 'per' => 'interface'));
output('packets', 'number', array('label' => 'Packets', 'unit' => 'packets/s', 'per' => 'interface'));
output('errors', 'number', array('label' => 'Errors', 'unit' => 'errors/s', 'per' => 'interface'));
output('drops', 'number', array('label' => 'Drops', 'unit' => 'packets/s', 'per' => 'interface'));
output('drop-percent', 'number', array('label' => 'Share of packets dropped', 'unit' => '%', 'per' => 'interface'));
output('addresses', 'number', array('label' => 'IPv4 addresses', 'per' => 'interface'));
watch.state('link-down', 'Link down', 'link', array('critical' => array('down', 'lowerlayerdown')));
watch.custom('speed-degraded', 'Negotiated speed degraded', array(
'help' => 'Warning when the negotiated speed is below the expected speed.',
'settings' => array(
'expected' => array('label' => 'Expected speed', 'form' => 'number', 'unit' => 'Mbit/s', 'default' => 1000),
),
'enabled' => false,
));
watch.above('saturation-in', 'Inbound saturation', 'in-percent', array('warning' => 70, 'critical' => 90, 'for' => '5 min'));
watch.above('saturation-out', 'Outbound saturation', 'out-percent', array('warning' => 70, 'critical' => 90, 'for' => '5 min'));
watch.custom('errors', 'Errors', array(
'help' => 'Warning above a number of errors per minute; critical above a share of the traffic.',
'settings' => array(
'per-minute' => array('label' => 'Warning above', 'form' => 'number', 'unit' => 'errors/min', 'default' => 1),
'share' => array('label' => 'Critical above', 'form' => 'number', 'unit' => '% of traffic', 'default' => 0.1),
),
));
watch.above('drops', 'Packets dropped', 'drop-percent', array('warning' => 0.5, 'critical' => 2));
watch.habit('traffic-unusual', 'Unusual traffic', 'traffic', array('floor' => 10000000, 'enabled' => false));
watch.silence('mute', 'Silent interface', 'packets', array('warning' => '10 min', 'enabled' => false));
watch.missing('missing', 'Interface missing', 'link', array('enabled' => false));
watch.expect('mtu', 'Unexpected MTU', 'mtu', array('warning' => array(1500), 'enabled' => false));
watch.below('no-address', 'No IPv4 address left', 'addresses', array('critical' => 1, 'enabled' => false));
// Indexed by ifIndex. IF-MIB, ifTable: ifDescr (the name Windows gives the card), ifMtu, ifAdminStatus
// and ifOperStatus, ifInDiscards, ifInErrors, ifOutDiscards, ifOutErrors. ifXTable: ifHighSpeed (in Mbit/s)
// and the 64-bit counters, octets and unicast, multicast and broadcast packets, in each direction.
$interfaces = snmp.table(array(
'descr' => '1.3.6.1.2.1.2.2.1.2',
'mtu' => '1.3.6.1.2.1.2.2.1.4',
'admin' => '1.3.6.1.2.1.2.2.1.7',
'status' => '1.3.6.1.2.1.2.2.1.8',
'in-discards' => '1.3.6.1.2.1.2.2.1.13',
'in-errors' => '1.3.6.1.2.1.2.2.1.14',
'out-discards' => '1.3.6.1.2.1.2.2.1.19',
'out-errors' => '1.3.6.1.2.1.2.2.1.20',
'in-octets' => '1.3.6.1.2.1.31.1.1.1.6',
'in-ucast' => '1.3.6.1.2.1.31.1.1.1.7',
'in-mcast' => '1.3.6.1.2.1.31.1.1.1.8',
'in-bcast' => '1.3.6.1.2.1.31.1.1.1.9',
'out-octets' => '1.3.6.1.2.1.31.1.1.1.10',
'out-ucast' => '1.3.6.1.2.1.31.1.1.1.11',
'out-mcast' => '1.3.6.1.2.1.31.1.1.1.12',
'out-bcast' => '1.3.6.1.2.1.31.1.1.1.13',
'speed' => '1.3.6.1.2.1.31.1.1.1.15',
));
// IP-MIB, ipAddrTable, indexed by address: ipAdEntIfIndex says which interface holds it.
$addresses = snmp.table(array('ifindex' => '1.3.6.1.2.1.4.20.1.2'));
$address_count = array();
foreach ($addresses as $entry) {
$address_count[$entry['ifindex']] = list.get($address_count, $entry['ifindex'], 0) + 1;
}
// ifOperStatus in words; an interface disabled by the administrator (ifAdminStatus 2) is said "disabled",
// so that it does not pass for a link down.
$states = array(1 => 'up', 2 => 'down', 3 => 'testing', 4 => 'unknown', 5 => 'dormant', 6 => 'notpresent', 7 => 'lowerlayerdown');
$expected_speed = watch.setting('speed-degraded', 'expected');
$errors_per_minute = watch.setting('errors', 'per-minute');
$errors_share = watch.setting('errors', 'share');
$seen = array();
foreach ($interfaces as $index => $row) {
if (!list.has($row, 'descr')) {
continue;
}
// Two cards of the same name each keep their own: the second carries its ifIndex.
$name = $row['descr'];
if (list.has($seen, $name)) {
$name = $name . ' #' . $index;
}
$seen[$name] = true;
$link = list.get($states, list.get($row, 'status', 4), 'unknown');
if (list.get($row, 'admin', 1) == 2) {
$link = 'disabled';
}
value('link', $link, $name);
value('addresses', list.get($address_count, $index, 0), $name);
if (list.has($row, 'mtu')) {
value('mtu', $row['mtu'], $name);
}
// An interface that is down has no negotiated speed (0).
$speed = list.get($row, 'speed', 0);
if ($speed > 0) {
value('speed', $speed, $name);
if ($expected_speed != '' && $speed < $expected_speed) {
watch.raise('speed-degraded', 'warning', $name . ' negotiated at ' . $speed . ' Mbit/s', $name);
}
}
// The traffic, from the counters of this run and those of the previous one; nothing at the first run, nor for
// an interface without 64-bit counters.
if (!list.has($row, 'in-octets') || !list.has($row, 'out-octets')) {
continue;
}
$in_packets = list.get($row, 'in-ucast', 0) + list.get($row, 'in-mcast', 0) + list.get($row, 'in-bcast', 0);
$out_packets = list.get($row, 'out-ucast', 0) + list.get($row, 'out-mcast', 0) + list.get($row, 'out-bcast', 0);
$in = counter.rate('in', $row['in-octets'] * 8, $name);
$out = counter.rate('out', $row['out-octets'] * 8, $name);
$packets = counter.rate('packets', $in_packets + $out_packets, $name);
$errors = counter.rate('errors', list.get($row, 'in-errors', 0) + list.get($row, 'out-errors', 0), $name);
$drops = counter.rate('drops', list.get($row, 'in-discards', 0) + list.get($row, 'out-discards', 0), $name);
if ($in == '' || $out == '' || $packets == '' || $errors == '' || $drops == '') {
continue;
}
value('traffic-in', number.round($in), $name);
value('traffic-out', number.round($out), $name);
value('traffic', number.round($in + $out), $name);
value('packets', number.round($packets, 2), $name);
value('errors', number.round($errors, 3), $name);
value('drops', number.round($drops, 3), $name);
if ($packets + $drops > 0) {
value('drop-percent', number.round(100 * $drops / ($packets + $drops), 2), $name);
}
if ($speed > 0) {
// The negotiated speed is in Mbit/s: one percent of it is 10,000 bit/s.
value('in-percent', number.round($in / ($speed * 10000), 1), $name);
value('out-percent', number.round($out / ($speed * 10000), 1), $name);
}
// The errors: per minute for the warning, as a share of the traffic for the critical.
if ($errors_per_minute != '' && $errors * 60 > $errors_per_minute) {
watch.raise('errors', 'warning', $name . ': ' . number.round($errors * 60, 1) . ' errors per minute', $name);
}
if ($errors_share != '' && $packets + $errors > 0) {
$share = 100 * $errors / ($packets + $errors);
if ($share > $errors_share) {
watch.raise('errors', 'critical', $name . ': ' . number.round($share, 2) . ' % of the traffic in error', $name);
}
}
}