Monitor the Airport Extreme with Munin

    

I already configured Munin to monitor my Synology DS409slim . Today, I’m going to configure Munin to monitor my Apple Airport Extreme, using SNMP.

Setup the Munin server

If your Munin instance server is not configured for SNMP polling yet, have a look here .

Enable SNMP

To enable SNMP on the Airport Extreme, start the “AirPort Utility” and browse to the “Advanced” tab. Check the “Allow SNMP” option and fill-in the community string. Then apply the configuration.

To check if it works, issue a simple snmp command. For example, on my Mac, I did:

# snmpwalk -c public -v 2c airport system
SNMPv2-MIB::sysDescr.0 = STRING: Apple AirPort - Apple Inc., 2006-2009.  All rights Reserved.
(...)
SNMPv2-MIB::sysORID.1 = OID: SNMPv2-MIB::snmpMIB
SNMPv2-MIB::sysORID.2 = OID: TCP-MIB::tcpMIB
SNMPv2-MIB::sysORID.3 = OID: IP-MIB::ip
SNMPv2-MIB::sysORID.4 = OID: UDP-MIB::udpMIB
SNMPv2-MIB::sysORID.5 = OID: SNMP-VIEW-BASED-ACM-MIB::vacmBasicGroup
SNMPv2-MIB::sysORID.6 = OID: IF-MIB::ifMIB
SNMPv2-MIB::sysORDescr.1 = STRING: The MIB module for SNMPv2 entities
SNMPv2-MIB::sysORDescr.2 = STRING: The MIB module for managing TCP implementations
SNMPv2-MIB::sysORDescr.3 = STRING: The MIB module for managing IP and ICMP implementations
SNMPv2-MIB::sysORDescr.4 = STRING: The MIB module for managing UDP implementations
SNMPv2-MIB::sysORDescr.5 = STRING: View-based Access Control Model for SNMP.
SNMPv2-MIB::sysORDescr.6 = STRING: The MIB module to describe generic objects for network interface sub-layers

Now, let’s grab the data.

Configure the node

In the munin.conf file, add the entry for the Airport:

[airport.tumfatig.net]
    address 192.168.0.5
# the Munin server IP

As usual, create or links the plugins in the etc/munin/plugins/ directory:

snmp_airport.tumfatig.net_if_1  
snmp_airport.tumfatig.net_if_2 -> snmp_airport.tumfatig.net_if_1
snmp_airport.tumfatig.net_if_3 -> snmp_airport.tumfatig.net_if_1
snmp_airport.tumfatig.net_if_5 -> snmp_airport.tumfatig.net_if_1
snmp_airport.tumfatig.net_if_6 -> snmp_airport.tumfatig.net_if_1
snmp_airport.tumfatig.net_if_7 -> snmp_airport.tumfatig.net_if_1
snmp_airport.tumfatig.net_if_err_1  
snmp_airport.tumfatig.net_if_err_2 -> snmp_airport.tumfatig.net_if_err_1
snmp_airport.tumfatig.net_if_err_3 -> snmp_airport.tumfatig.net_if_err_1
snmp_airport.tumfatig.net_if_err_5 -> snmp_airport.tumfatig.net_if_err_1
snmp_airport.tumfatig.net_if_err_6 -> snmp_airport.tumfatig.net_if_err_1
snmp_airport.tumfatig.net_if_err_7 -> snmp_airport.tumfatig.net_if_err_1
snmp_airport.tumfatig.net_netstat -> /usr/local/libexec/munin/plugins/snmp__netstat
snmp_airport.tumfatig.net_uptime -> /usr/local/libexec/munin/plugins/snmp__uptime
snmp_airport.tumfatig.net_wireless_users  

I used the default plugins for netstat and uptime but did modifications on the snmp__if_, snmp__if_err and snmp__rdp_users.

Fix the interface scripts

The native interface scripts look for 64bits value which are not available on the Airport (AFAIK). The SNMP server still replies “No Such Object available on this agent at this OID” when prompting for those value. This disables the script from understanding that the value does not exist.

I’m no Perl expert and couldn’t solve it properly. So I just removed the non-existant OID. Here’s the full patch to apply:

--- /usr/local/libexec/munin/plugins/snmp__if_  Thu Aug 18 14:42:28 2011
+++ /etc/munin/plugins/snmp_airport.tumfatig.net_if_1   Fri Aug 19 15:23:38 2011
@@ -120,8 +120,4 @@
 # .1.3.6.1.2.1.2.2.1.8.1 = INTEGER: up(1)
 # .1.3.6.1.2.1.2.2.1.8.65539 = INTEGER: up(1)
-#
-# 64 bit counters:
-# .1.3.6.1.2.1.31.1.1.1.6.   Counter64 ifHCInOctets
-# .1.3.6.1.2.1.31.1.1.1.10.  Counter64 ifHCOutOctets
 
 if (defined $ARGV[0] and $ARGV[0] eq "snmpconf") {
@@ -145,9 +141,4 @@
 my $ifEntryOutOctets   = "1.3.6.1.2.1.2.2.1.16.$iface";
 
-# Only available with SNMPv2 and up.
-my $ifEntryAlias       = "1.3.6.1.2.1.31.1.1.1.18.$iface";
-my $ifEntryIn64Octets  = "1.3.6.1.2.1.31.1.1.1.6.$iface";
-my $ifEntryOut64Octets = "1.3.6.1.2.1.31.1.1.1.10.$iface";
-
 my ($session, $error);
 
@@ -160,6 +151,5 @@
     print "host_name $host\n" unless $host eq 'localhost';
 
-    my $alias = $session->get_single($ifEntryAlias) ||
-      $session->get_single($ifEntryDescr) ||
+    my $alias = $session->get_single($ifEntryDescr) ||
        "Interface $iface";
 
@@ -194,11 +184,4 @@
     }
 
-    if (defined ($session->get_single($ifEntryIn64Octets))) {
-
-       # If we get an answer at the 64 bit OID then this switch
-       # supports the extended MIB
-
-       $extrainfo .= " This switch supports 64 bit byte counters and these are used by this plugin.";
-    } else {
        # If not we only have a 32 bit counter and are lost.
        $extrainfo .= " NOTE! This switch supports only 32 bit byte counters which makes the plugin unreliable and unsuitable for most 100Mb (or faster) interfaces, where bursts are expected to exceed 50Mbps.  This means that for interfaces where much traffic is sent this plugin will report false thruputs and cannot be trusted.";
@@ -207,5 +190,4 @@
        $extrainfo .= " I notice that you use SNMP version 1 which does not support 64 bit quantities.  You may get better results if you switch to SNMP version 2c or 3.  Please refer to the plugin documentation."
          if $version == 1;
-    }
 
     print "graph_title Interface $alias traffic\n";
@@ -242,6 +224,5 @@
 }
 
-if (defined ($response = ($session->get_single($ifEntryIn64Octets) ||
-                        $session->get_single($ifEntryInOctets)))) {
+if (defined ($response = $session->get_single($ifEntryInOctets))) {
     print "recv.value ", $response, "\n";
 } else {
@@ -250,6 +231,5 @@
 }
 
-if (defined ($response = $session->get_single($ifEntryOut64Octets) ||
-                        $session->get_single($ifEntryOutOctets))) {
+if (defined ($response = $session->get_single($ifEntryOutOctets))) {
     print "send.value ", $response, "\n";
 } else {
--- /usr/local/libexec/munin/plugins/snmp__if_err_      Thu Feb 24 06:58:48 2011
+++ /etc/munin/plugins/snmp_airport.tumfatig.net_if_err_1       Fri Aug 19 15:27:04 2011
@@ -97,5 +97,4 @@
 
 my $ifEntryDescr     = "1.3.6.1.2.1.2.2.1.2.$iface";
-my $ifEntryAlias     = "1.3.6.1.2.1.31.1.1.1.18.$iface";
 
 my $ifStatus         = "1.3.6.1.2.1.2.2.1.8.$iface";
@@ -114,6 +113,5 @@
     print "host_name $host\n" unless $host eq 'localhost';
 
-    my $alias = $session->get_single($ifEntryAlias) ||
-      $session->get_single($ifEntryDescr) ||
+    my $alias = $session->get_single($ifEntryDescr) ||
        "Interface $iface";

I kept the original files because they work with the Synology ; and probably any decent SNMP server :)

Fix the user script

By default, Munin expect RDP users from SNMP polling. On the Airport, there are no RDP users but you can graph the number of wireless clients connected to the box. So I modified the default rdp script and created a new wireless client script:

--- /usr/local/libexec/munin/plugins/snmp__rdp_users    Thu Feb 24 06:58:49 2011
+++ /etc/munin/plugins/snmp_airport.tumfatig.net_wireless_users Tue Aug 23 11:47:06 2011
@@ -35,9 +35,9 @@
 
 if(defined $ARGV[0] and $ARGV[0] eq "snmpconf") {
-       print "require 1.3.6.1.2.1.25.4.2.1.2. rdpclip\\.exe\n";
+       print "require 1.3.6.1.4.1.63.501.3.2.1\n";
        exit 0;
 }
 
-if($0 =~ /^(?:|.*\/)snmp_([^_]+)_rdp_users$/) {
+if($0 =~ /^(?:|.*\/)snmp_([^_]+)_wireless_users$/) {
     $host  = $1;
     if($host =~ /^([^:]+):(\d+)$/) {
@@ -63,13 +63,13 @@
 if(defined $ARGV[0] and $ARGV[0] eq "config") {
     print "host_name $host\n";
-    print "graph_title Number of RDP users
+    print "graph_title Number of wireless users
 graph_args --base 1000 -l 0 
-graph_vlabel number of RDP users
+graph_vlabel number of wireless users
 graph_scale no
 graph_category system
-graph_info This graph shows the number of remote users on the Windows system.
+graph_info This graph shows the number of wireless users on the Airport system.
 users.label users
 users.draw LINE2
-users.info Number of users logged in.
+users.info Number of users attached.
 ";
     exit 0;
@@ -80,20 +80,14 @@
 sub get_users {
     my $handle = shift;
-    my $oid    = "1.3.6.1.2.1.25.4.2.1.2";
+    my $oid    = "1.3.6.1.4.1.63.501.3.2.1";
     
     print "# Getting single $oid...\n" if $DEBUG;
     
     my $response = $handle->get_table($oid);
-    my $count = 0;
     
     if(!defined($response)) {
        return "";
     } else {
-       foreach my $key (keys(%{$response})) {
-           if($response->{$key} =~ /^rdpclip\.exe$/i) {
-               $count++;
-           }
-       }
-       return $count;
+       return $response->{"$oid.0"};
     }
 }

Restart the munin-node, wait & see!
Hope it helps.