<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Kyle Brandt &#187; Kernel</title>
	<atom:link href="http://www.kbrandt.com/tag/kernel/feed" rel="self" type="application/rss+xml" />
	<link>http://www.kbrandt.com</link>
	<description>Original computing and productivity articles by a Linux administrator</description>
	<lastBuildDate>Tue, 06 Jul 2010 01:04:34 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Debuging a script that parses /proc/net/dev</title>
		<link>http://www.kbrandt.com/2009/07/debuging-a-script-that-parses-procnetdev.html</link>
		<comments>http://www.kbrandt.com/2009/07/debuging-a-script-that-parses-procnetdev.html#comments</comments>
		<pubDate>Wed, 08 Jul 2009 17:31:08 +0000</pubDate>
		<dc:creator>Kyle</dc:creator>
				<category><![CDATA[C]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Kernel]]></category>

		<guid isPermaLink="false">http://www.kbrandt.com/?p=351</guid>
		<description><![CDATA[A Intermittent Problem:
I wrote a Perl script for Nagios that would figure out the bandwidth of an interface by parsing TX (transmit) and RX (receive) bytes from /proc/net/dev.  The proc file system is a virtual file system that provides the ability to view various kernel statistics as well as modify some kernel parameters. My [...]]]></description>
			<content:encoded><![CDATA[<p><strong>A Intermittent Problem:</strong><br />
I wrote a Perl script for Nagios that would figure out the bandwidth of an interface by parsing TX (transmit) and RX (receive) bytes from /proc/net/dev.  The proc file system is a virtual file system that provides the ability to view various kernel statistics as well as modify some kernel parameters. My script parses the file twice at a specified interval, and then subtracts the old value from the new value to return bytes per second.  I realized that this wasn&#8217;t the most accurate method, but it was good enough for my purposes and I didn&#8217;t have to install snmp. Also, the larger the interval, the smaller the error would generally be assuming light load.  </p>
<p>The problem was that this script would fail every so often with &#8216;Not numeric subtraction&#8217;.  So I started saving snapshots of /proc/net/dev and noticed that the script would fail after when the values were around 4 billion something.  This I knew to be in the neighborhood of 2^32 (The max of a positive only 32-bit integer value).  To confirm my thoughts that this was the max value for this counter, I decided to have a poke around the kernel source code.</p>
<p><strong>Into the Kernel:</strong><br />
I didn&#8217;t know where to look in the source for this, but /proc/net/dev has the string &#8216;Inter-|&#8217; which I figured would be a unique enough string to give me a place to start.  Sure enough, a recursive grep for this string returned only 3 lines of code.  The function I wanted was dev_seq_printf_stats in dev/core/dev.c:</p>
<pre class="brush: c">
static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
{
        struct net_device_stats *stats = dev-&gt;get_stats(dev);
        seq_printf(seq, &quot;%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu &quot;
                   &quot;%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n&quot;,
                   dev-&gt;name, stats-&gt;rx_bytes, stats-&gt;rx_packets,
                   stats-&gt;rx_errors,
                   ///.....
</pre>
<p>Looking at the printf specifiers for this they were %ul &#8212; unsigned long integer, which on my system was indeed a max of 4294967295 ( 32^2 &#8211; 1).  I wanted to be extra sure, so I traced the net_device_stats struct to include/linux/netdevice.h and confirmed that the net_device_stats->rx_bytes member was in fact an unsigned long integer.   So now I knew the error happened when the counter maxed out and then reset to zero, but why a non-numeric subtraction error?</p>
<p><strong>Problem Found:</strong><br />
%8lu as a ANSI C standard library printf specifier defaults to 8 characters wide, and also defaults to right justify since there is no hyphen flag.  To find out if the kernel did the same I traced seq_printf to lib/vsprintf.c and saw that the Linux kernel version formatted this in the same way.  When the bytes value was less than 8 characters long, there was leading white space that threw off my parser.  All I needed was to add the extra line at line 9 to eliminate any leading whitespace:</p>
<pre class="brush: perl">
sub parseBandwidth {
    my $interface = shift;
    my @ifconfigOutput = @_;
    foreach my $line (@ifconfigOutput) {
        if ( $line =~ /:/ ) {
            my @interfaceLine = split( /:/, $line);
            if ($interfaceLine[0] =~ /$interface/) {
                # Next line is to sanitize leading whitespace
                $interfaceLine[1] =~ s/^\s+//;
                my @interfaceStats = split( /\s+/, $interfaceLine[1] );
                print( LOG &quot;DEBUG I have parsed out: @interfaceStats\n&quot;) if $debug;
                return @interfaceStats;
            }
        }
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.kbrandt.com/2009/07/debuging-a-script-that-parses-procnetdev.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
