<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>
        Disruptive Ninja | Vincent Bernat
    </title>
    <link href="http://vincent.bernat.im/en/blog/atom.xml" rel="self" />
    <link href="http://vincent.bernat.im/en"/>
    <id>http://www.luffy.cx/en/blog/atom.xml/</id>

            <updated>2012-05-19T09:44:15+02:00</updated>

            <entry>
            <title type="html">XBMC Eden on Debian Wheezy</title>
            <author><name>Vincent Bernat</name></author>
            <link href="http://vincent.bernat.im/en/blog/2012-xbmc-debian-wheezy.html"/>
            <updated>2012-04-25T20:29:49+02:00</updated>
            <id>http://www.luffy.cx/en/blog/2012-xbmc-debian-wheezy.html</id>

            <content type="html">
<![CDATA[
<p>I bought some <abbr title="Home Theather Personal Computer"><span class="caps">HTPC</span></abbr> a few years ago to run <a href="http://xbmc.org/" title="XBMC Media Center"><span class="caps">XBMC</span></a>, a neat media
center solution. At the time, to avoid any problems, I installed it on
top of a minimal Ubuntu Lucid installation with the official packages
from the team <span class="caps">XBMC</span>. Recently, <a href="http://xbmc.org/natethomas/2012/03/24/xbmc-11-0-eden/" title="XBMC 11.0: Eden"><span class="caps">XBMC</span> Eden has been released</a> and
<a href="http://xbmc.org/theuni/2012/04/10/xbmc-accepted-into-debian/" title="XBMC accepted into Debian"><span class="caps">XBMC</span> has landed into Debian unstable</a>. It was a good
occasion to make the&nbsp;switch.</p>
<p><img alt="Unofficial XBMC logo for Eden" src="//d1g3mdmxf8zbo9.cloudfront.net/images/xbmc-eden-logo.jpg" title="XBMC Media Center: Eden. Logo by FiroPyro. CC BY-NC 3.0"></p>
<p><strong><span class="caps">TL</span>;<span class="caps">DR</span></strong>: Installing <span class="caps">XBMC</span> on Debian Wheezy is quite easy: it almost
works out of the box. The big difficulty is the configuration of the
remote control: either it works as you expect or you will have to
scratch your head over the pile of layers needed to work with a remote&nbsp;control.</p>
<p>The configuration of my <abbr title="Home Theather Personal Computer"><span class="caps">HTPC</span></abbr> is as&nbsp;follows:</p>
<ul>
<li>an <a href="http://store.antec.com/Product/enclosure-veris_media/micro-fusion-remote-350/0-761345-15737-7.aspx" title="Antec Micro Fusion Remote 350 housing">Antec Micro Fusion 350 housing</a> featuring a SoundGraph
   iMON <abbr title="Infrared"><span class="caps">IR</span></abbr> receiver and <span class="caps">LCD</span> screen<sup id="fnref:lcd"><a href="#fn:lcd" rel="footnote">1</a></sup>,</li>
<li>a Zotac <span class="caps">ION</span>-<span class="caps">ITX</span>-D-E motherboard with an Intel Atom 330 <span class="caps">CPU</span> and an
   nVidia <span class="caps">ION</span>&nbsp;chipset,</li>
<li>some Onkyo <abbr title="Audio Video"><span class="caps">AV</span></abbr> receiver connected through&nbsp;<span class="caps">HDMI</span>,</li>
<li>a <a href="http://www.logitech.com/en-roeu/440/376" title="Logitech Harmony® 555 Advanced Universal Remote">Logitech Harmony 555</a> as remote&nbsp;control.</li>
</ul>
<div class="toc">
<ul>
<li><a href="#installation">Installation</a><ul>
<li><a href="#installing-debian-wheezy">Installing Debian&nbsp;Wheezy</a></li>
<li><a href="#configuring-x">Configuring&nbsp;X</a></li>
<li><a href="#installing-xbmc">Installing&nbsp;<span class="caps">XBMC</span></a></li>
</ul>
</li>
<li><a href="#configuration">Configuration</a><ul>
<li><a href="#sound">Sound</a></li>
<li><a href="#lcd-display"><span class="caps">LCD</span>&nbsp;display</a></li>
<li><a href="#remote-control">Remote control</a><ul>
<li><a href="#remote-controls-and-linux">Remote controls and&nbsp;Linux</a></li>
<li><a href="#the-easy-way">The easy&nbsp;way</a></li>
<li><a href="#the-hard-way">The hard&nbsp;way</a></li>
</ul>
</li>
<li><a href="#ftp"><span class="caps">FTP</span></a></li>
<li><a href="#miscellaneous">Miscellaneous</a></li>
</ul>
</li>
</ul>
</div>
<h1 id="installation">Installation</h1>
<h2 id="installing-debian-wheezy">Installing Debian&nbsp;Wheezy</h2>
<p>Installing Debian Wheezy<sup id="fnref:wheezy"><a href="#fn:wheezy" rel="footnote">2</a></sup> is pretty easy.  Nowadays, getting a
bootable <span class="caps">USB</span> key from a
<a href="http://www.debian.org/devel/debian-installer/" title="Development version of the Debian Installer"><em>netinst</em> image of Debian Installer for Wheezy</a> is&nbsp;simplified:</p>
<div class="codehilite"><pre><span class="gp">$</span> sudo dd <span class="k">if</span><span class="o">=</span>debian-testing-i386-netinst.iso <span class="se">\</span>
<span class="gp">&gt;</span>         <span class="nv">of</span><span class="o">=</span>/dev/disk/by-id/usb...
</pre></div>


<p>The installation was smooth with the exception of <abbr title="GRand Unified Bootloader"><span class="caps">GRUB</span></abbr> which was
unable to install itself on the disk. This is a
<a href="http://bugs.debian.org/662086" title="Bug #662086: grub-install failed with raid+lvm">known bug</a> when dealing with <span class="caps">LVM</span> and it comes with a
simple workaround. I hope it will be corrected in time for Wheezy&nbsp;release.</p>
<p>While this has little to do with the installation of <span class="caps">XBMC</span>, I wanted to
test <a href="http://www.freedesktop.org/wiki/Software/systemd" title="systemd, a system and service manager for Linux">systemd</a> which may become the default <em>init</em> in Debian (at
least in Debian <span class="caps">GNU</span>/Linux). From <code>README.Debian</code>:</p>
<blockquote>
<p><code>systemd</code> can be installed alongside <code>sysvinit</code> and will not change
the behaviour of the system out of the box.  This is intentional.
To test <code>systemd</code>, add <code>init=/bin/systemd</code> to the kernel command
line and then rebooting, or install the <code>systemd-sysv</code> package.</p>
</blockquote>
<p>The final system boots in about 15&nbsp;seconds.</p>
<h2 id="configuring-x">Configuring&nbsp;X</h2>
<p>Because <a href="http://nouveau.freedesktop.org/wiki/VideoDecoding" title="Video decoding support for nouveau driver">video decoding in <em>nouveau</em> driver</a> is still a
work in progress, the use of the proprietary <span class="caps">NVIDIA</span> drivers is
mandatory to be able to watch high resolution videos. Therefore,
<code>/etc/apt/sources.list</code> should be completed with <code>contrib</code> and
<code>non-free</code> repository. Then, you can install the appropriate packages:
<code>xserver-xorg-video-nvidia</code>, <code>nvidia-vdpau-driver</code> and <code>xserver-xorg</code>.</p>
<p>Here is my <code>/etc/X11/xorg.conf.d/nvidia.conf</code>:</p>
<div class="codehilite"><pre><span class="n">Section</span> &quot;<span class="n">Device</span>&quot;
    <span class="n">Identifier</span>     &quot;<span class="n">NVidia</span> <span class="n"><span class="caps">ION</span></span>&quot;
    <span class="n">Driver</span>         &quot;<span class="n">nvidia</span>&quot;
    <span class="n">VendorName</span>     &quot;<span class="n"><span class="caps">NVIDIA</span></span> <span class="n">Corporation</span>&quot;
    <span class="n">Option</span>         &quot;<span class="n">HWCursor</span>&quot; &quot;<span class="n">False</span>&quot;
    <span class="n">Option</span>         &quot;<span class="n">NoFlip</span>&quot; &quot;<span class="n">False</span>&quot;
    <span class="n">Option</span>         &quot;<span class="n">FlatPanelProperties</span>&quot; &quot;<span class="n">Scaling</span> <span class="p">=</span> <span class="n">Native</span>&quot;
    <span class="n">Option</span>         &quot;<span class="n">DynamicTwinView</span>&quot; &quot;<span class="n">False</span>&quot;
    <span class="n">Option</span>         &quot;<span class="n">ConnectedMonitor</span>&quot; &quot;<span class="n"><span class="caps">DFP</span></span><span class="o">-</span>1&quot;
    <span class="n">Option</span>         &quot;<span class="n">CustomEDID</span>&quot; &quot;<span class="n"><span class="caps">DFP</span></span><span class="o">-</span>1<span class="p">:</span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">X11</span><span class="o">/</span><span class="n">edid</span><span class="p">.</span><span class="n">bin</span>&quot;
    <span class="n">Option</span>         &quot;<span class="n">NoLogo</span>&quot; &quot;<span class="n">True</span>&quot;
<span class="n">EndSection</span>

<span class="n">Section</span> &quot;<span class="n">Extensions</span>&quot;
    <span class="n">Option</span> &quot;<span class="n">Composite</span>&quot; &quot;<span class="n">false</span>&quot;
<span class="n">EndSection</span>
</pre></div>


<p>The <code>CustomEDID</code> option allows the driver to get an appropriate <abbr title="Extended Display Identification Data"><span class="caps">EDID</span></abbr>
even when the <abbr title="Audio Video"><span class="caps">AV</span></abbr> receiver is off. You can get yours, free of charge,
with <code>get-edid</code> from <code>read-edid</code> package.</p>
<h2 id="installing-xbmc">Installing&nbsp;<span class="caps">XBMC</span></h2>
<p>Thanks to the work of Andrés Mejía, <span class="caps">XBMC</span> is now available in Debian
Wheezy. To install it, just type <code>aptitude install xbmc</code>. I have
dropped the following <code>xbmc.service</code> in <code>/etc/systemd/system</code>
directory:</p>
<div class="codehilite"><pre><span class="k">[Unit]</span>
<span class="na">Description</span> <span class="o">=</span> <span class="s"><span class="caps">XBMC</span> media center</span>
<span class="na">After</span> <span class="o">=</span> <span class="s">syslog.target</span>

<span class="k">[Service]</span>
<span class="na">User</span> <span class="o">=</span> <span class="s">xbmc</span>
<span class="na">Group</span> <span class="o">=</span> <span class="s">xbmc</span>
<span class="na">Type</span> <span class="o">=</span> <span class="s">simple</span>
<span class="na">ExecStart</span> <span class="o">=</span> <span class="s">/usr/bin/xinit /usr/bin/xbmc-standalone -- :0</span>
<span class="na">Restart</span> <span class="o">=</span> <span class="s">on-failure</span>

<span class="k">[Install]</span>
<span class="na">WantedBy</span> <span class="o">=</span> <span class="s">multi-user.target</span>
</pre></div>


<p>Enable this service on boot with <code>systemctl enable xbmc.service</code>. You
need to allow <code>xbmc</code> user to run X. The simplest way is to run
<code>dpkg-reconfigure -plow x11-common</code> and to allow anybody to run
X. <code>sudo</code> may be an&nbsp;alternative.</p>
<h1 id="configuration">Configuration</h1>
<h2 id="sound">Sound</h2>
<p>While I wanted to use PulseAudio, I want the <abbr title="Audio Video"><span class="caps">AV</span></abbr> receiver to be
able to upmix stereo streams itself. With PulseAudio, it would always
receive a 6-channel signal. Therefore, I directly use <abbr title="Advanced Linux Sound Architecture"><span class="caps">ALSA</span></abbr>.</p>
<p>First, unmute the appropriate&nbsp;outputs:</p>
<div class="codehilite"><pre><span class="gp">$</span> amixer scontrols | grep <span class="caps">IEC958</span>
<span class="go">Simple mixer control &#39;<span class="caps">IEC958</span>&#39;,0</span>
<span class="go">Simple mixer control &#39;<span class="caps">IEC958</span> Default <span class="caps">PCM</span>&#39;,0</span>
<span class="go">Simple mixer control &#39;<span class="caps">IEC958</span>&#39;,1</span>
<span class="gp">$</span> amixer sset <span class="s1">&#39;<span class="caps">IEC958</span>&#39;</span>,0 unmute
<span class="gp">$</span> amixer sset <span class="s1">&#39;<span class="caps">IEC958</span> Default <span class="caps">PCM</span>&#39;</span>,0 unmute
<span class="gp">$</span> amixer sset <span class="s1">&#39;<span class="caps">IEC958</span>&#39;</span>,1 unmute
<span class="gp">$</span> sudo systemctl stop alsa-utils.service
</pre></div>


<p>The order of channels is incorrect. With the following
<code>/etc/asound.conf</code>, we declare a new output, <code>hdmi2</code>, with a different&nbsp;mapping:</p>
<div class="codehilite"><pre><span class="n">pcm</span><span class="p">.</span><span class="n">hdmi2</span> <span class="p">{</span>
  <span class="n">type</span> <span class="n">asym</span>
  <span class="n">playback</span><span class="p">.</span><span class="n">pcm</span> <span class="p">{</span>
    <span class="n">type</span> <span class="n">plug</span>
    <span class="n">slave</span><span class="p">.</span><span class="n">pcm</span> &quot;<span class="n">remap</span><span class="o">-</span><span class="n">surround51</span>&quot;
  <span class="p">}</span>
<span class="p">}</span>

<span class="n">pcm</span><span class="p">.</span>!<span class="n">remap</span><span class="o">-</span><span class="n">surround51</span> <span class="p">{</span>
  <span class="n">type</span> <span class="n">route</span>
  <span class="n">slave</span><span class="p">.</span><span class="n">pcm</span> &quot;<span class="n">hdmi</span>&quot;
  <span class="n">ttable</span> <span class="p">{</span>
    0<span class="p">.</span>0<span class="p">=</span> 1
    1<span class="p">.</span>1<span class="p">=</span> 1
    2<span class="p">.</span>4<span class="p">=</span> 1
    3<span class="p">.</span>5<span class="p">=</span> 1
    4<span class="p">.</span>2<span class="p">=</span> 1
    5<span class="p">.</span>3<span class="p">=</span> 1
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>


<p>In <span class="caps">XBMC</span>, this output should be used instead of the default one. <code>hdmi</code>
should still be used for passthrough. To check if each speaker is
mapped correctly, one can use <code>speaker-test -D hdmi2 -c 6</code>.</p>
<h2 id="lcd-display"><span class="caps">LCD</span>&nbsp;display</h2>
<p>The <span class="caps">LCD</span> display integrated into the SoundGraph iMON is supported by
the <code>imon</code> kernel module and the <code>lcdproc</code> package. I have only
modified a few lines of <code>/etc/LCDd.conf</code> to make it&nbsp;work:</p>
<div class="codehilite"><pre><span class="k">[server]</span>
<span class="na">Driver</span><span class="o">=</span><span class="s">imonlcd</span>
<span class="na">ServerScreen</span><span class="o">=</span><span class="s">off</span>

<span class="k">[imonlcd]</span>
<span class="na">Protocol</span><span class="o">=</span><span class="s">1</span>
<span class="na">OnExit</span><span class="o">=</span><span class="s">2</span>
<span class="na">Contrast</span><span class="o">=</span><span class="s">400</span>
</pre></div>


<p><strong><span class="caps">UPDATED</span>:</strong> The use of the <span class="caps">LCD</span> screen triggers various bugs
including segfaults of <code>ir-keytable</code> and freezes. Since its
readibility is less than ideal, I don&#8217;t use it any more. I have
uninstalled <code>lcdproc</code> and I am using this simple script to switch it
off on&nbsp;start:</p>
<div class="codehilite"><pre><span class="c">#!/usr/bin/python</span>

<span class="kn">import</span> <span class="nn">struct</span>
<span class="nb">open</span><span class="p">(</span><span class="s">&quot;/dev/lcd0&quot;</span><span class="p">,</span> <span class="s">&quot;w&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s">&quot;Q&quot;</span><span class="p">,</span><span class="mh">0x8800000000000008</span><span class="p">))</span>
</pre></div>


<p>This script is triggered by the following rule for <code>udev</code>:</p>
<div class="codehilite"><pre><span class="c"># Disable <span class="caps">LCD</span> screen</span>
<span class="n"><span class="caps">ACTION</span></span><span class="o">==</span><span class="s">&quot;add&quot;</span><span class="p">,</span> <span class="n"><span class="caps">NAME</span></span><span class="o">==</span><span class="s">&quot;lcd0&quot;</span><span class="p">,</span>
   <span class="n"><span class="caps">RUN</span></span><span class="o">+=</span><span class="s">&quot;/usr/local/bin/disable_lcd&quot;</span>
</pre></div>


<h2 id="remote-control">Remote&nbsp;control</h2>
<p>This is the most difficult part. I have a Logitech Harmony remote
which is a great universal remote. Its support in Linux is acceptable:
you can configure through <a href="http://members.harmonyremote.com/" title="Configure your Logitech Harmony">Logitech website</a> and use
<a href="http://sourceforge.net/projects/congruity/" title="GUI application to program your Logitech Harmony">congruity</a> to push the new&nbsp;configuration.</p>
<h3 id="remote-controls-and-linux">Remote controls and&nbsp;Linux</h3>
<p><strong>Before Linux 2.6.36</strong>, most remote controls would need <abbr title="Linux Infrared Remote Control"><span class="caps">LIRC</span></abbr> to&nbsp;work:</p>
<ul>
<li>The driver receives the signal from the <abbr title="Infrared"><span class="caps">IR</span></abbr> receiver and make it
   available through <code>/dev/lirc</code>.</li>
<li><code>lircd</code>, with the help of a configuration file describing the
   protocol used by the remote control, will read the signal and turn
   it into the appropriate <abbr title="Linux Infrared Remote Control"><span class="caps">LIRC</span></abbr>&nbsp;code.</li>
<li><span class="caps">XBMC</span> connects to <code>lircd</code> and receives incoming <abbr title="Linux Infrared Remote Control"><span class="caps">LIRC</span></abbr> codes. It will
   translate them to an <span class="caps">XBMC</span> command. This translation is specified in
   <code>Lircmap.xml</code>.</li>
<li><span class="caps">XBMC</span> maps each command to an action (like <code>Play</code>, <code>Fullscreen</code>,
   &#8230;)  using a <em>keymap</em>. This keymap can handle commands received by
   a remote control, but also by a keyboard, a mouse or a&nbsp;joystick.</li>
</ul>
<p><strong>Since Linux 2.6.36</strong>, remote controls will be mapped as a generic
input device (just like a&nbsp;keyboard):</p>
<ul>
<li>The driver receives the signal from the <abbr title="Infrared"><span class="caps">IR</span></abbr>&nbsp;receiver.</li>
<li>The signal will be handled by a decoder. The configuration of this
   decoder is done in userland by <code>ir-keytable</code>. The decoder will
   turn the signal into the appropriate event (usually, some&nbsp;keypress).</li>
<li>X will listen to those events and turn them into X key&nbsp;events.</li>
<li><span class="caps">XBMC</span> will receive them and use the appropriate <em>keymap</em> to turn
   them into&nbsp;actions.</li>
</ul>
<p>And to add more complexity to the mix, in this last case, you can
still use <abbr title="Linux Infrared Remote Control"><span class="caps">LIRC</span></abbr>: <code>lircd</code> will listen to events generated by the kernel
and turn them into <abbr title="Linux Infrared Remote Control"><span class="caps">LIRC</span></abbr> codes. This can be very&nbsp;confusing.</p>
<p>Moreover, the SoundGraph iMON <abbr title="Infrared"><span class="caps">IR</span></abbr> receiver accepts two <abbr title="Infrared"><span class="caps">IR</span></abbr> protocols:
the iMON protocol and the <span class="caps">RC</span>-6 one. The Linux driver accepts both of
them but uses the first one by default. The <span class="caps">RC</span>-6 protocol is the
protocol used by many <abbr title="Media Center Edition"><span class="caps">MCE</span></abbr> remote&nbsp;controls.</p>
<p>I hope you are still with me&nbsp;here.</p>
<h3 id="the-easy-way">The easy&nbsp;way</h3>
<p>To get a reasonable configuration out of the box, here is how to
configure each&nbsp;layer:</p>
<dl>
<dt>Logitech Harmony&nbsp;remote</dt>
<dd>Configure it as a <em>Microsoft</em> branded <em>Media Center <span class="caps">PC</span></em>: <em>Windows
  Media Center <span class="caps">SE</span></em>.</dd>
<dt>iMON <abbr title="Infrared"><span class="caps">IR</span></abbr>&nbsp;receiver</dt>
<dd>It must use <span class="caps">RC</span>-6 protocol. See below for more&nbsp;details.</dd>
<dt><abbr title="Linux Infrared Remote Control"><span class="caps">LIRC</span></abbr></dt>
<dd>In <code>/etc/lirc/hardware.conf</code>, put
  <code>DEVICE=/dev/input/by-id/usb-15c2_0038-event-if00</code> and
  <code>DRIVER=devinput</code>. In <code>/etc/lirc/lircd.conf</code>, just put <code>include
  "/usr/share/lirc/remotes/devinput/lircd.conf.devinput"</code>.</dd>
<dt><span class="caps">XBMC</span></dt>
<dd>With the previous bits done, it should just work out of the&nbsp;box.</dd>
</dl>
<p>To switch to <span class="caps">RC</span>-6 protocol, install the <code>ir-keytable</code> package and use
the following&nbsp;commands:</p>
<div class="codehilite"><pre><span class="gp">$</span> sudo modprobe rc-imon-mce
<span class="gp">$</span> sudo ir-keytable -s rc0 -p rc-6 -c -w /lib/udev/rc_keymaps/imon_mce
<span class="go">Read imon_mce table</span>
<span class="go">Old keytable cleared</span>
<span class="go">Wrote 77 keycode(s) to driver</span>
<span class="go">Protocols changed to <span class="caps">RC</span>-6</span>
</pre></div>


<p>To make the change permanent, add the <code>rc-imon-mce</code> module to
<code>/etc/modules</code> and create <code>/etc/udev/rules.d/90-imon.rules</code> with the
following&nbsp;content:</p>
<div class="codehilite"><pre><span class="c"># Override the keytable for iMON</span>
<span class="n"><span class="caps">ACTION</span></span><span class="o">==</span><span class="s">&quot;add|change&quot;</span><span class="p">,</span> <span class="n"><span class="caps">SUBSYSTEM</span></span><span class="o">==</span><span class="s">&quot;rc&quot;</span><span class="p">,</span> <span class="n">DRV_NAME</span><span class="p">=</span><span class="s">&quot;imon&quot;</span><span class="p">,</span> <span class="o">\</span>
   <span class="n"><span class="caps">RUN</span></span><span class="o">+=</span><span class="s">&quot;/usr/bin/ir-keytable -s $name -p rc-6 -c -w /lib/udev/rc_keymaps/imon_mce&quot;</span>
</pre></div>


<h3 id="the-hard-way">The hard&nbsp;way</h3>
<p>Now, you may want to bind custom actions to some (physical or virtual)
buttons. Basically, you are left with two&nbsp;solutions:</p>
<ol>
<li>Start from the basic configuration with <abbr title="Linux Infrared Remote Control"><span class="caps">LIRC</span></abbr> and add more buttons
    at each levels (there are five of&nbsp;them!).</li>
<li>Remove <abbr title="Linux Infrared Remote Control"><span class="caps">LIRC</span></abbr> and start with the Logitech Harmony acting as a
    Microsoft <abbr title="Media Center Edition"><span class="caps">MCE</span></abbr>&nbsp;keyboard.</li>
</ol>
<p>The first option can be quite difficult. You need to find an unused
code for the Logitech Harmony. You can try to make it learn a new code
if you have some <span class="caps">RC</span>-6 remote control. Then, you need to ensure that
this code will be present in the keytable used by <code>ir-keytable</code>. If
not, you need to add it. That&#8217;s not easy since you need a
<a href="http://www.kernel.org/doc/local/pr_debug.txt" title="Enabling debug output in some Linux module">to enable some debug stuff in the kernel</a> to find the
appropriate scancode. After that, the code needs to be translated in
<code>lircd.conf</code>. You will then have to translate it again in
<code>Lircmap.xml</code>. At least, you need to add it to a keymap in&nbsp;<span class="caps">XBMC</span>.</p>
<p>The other way is not ideal but seems less cumbersome. The first step
is to configure the Logitech Harmony as a <em>Microsoft <abbr title="Media Center Edition"><abbr title="Media Center Edition"><span class="caps">MCE</span></abbr></abbr> keyboard</em>: it
has a lot of available keys. Because of the lack of multimedia keys,
let&#8217;s match the keyboard configuration of&nbsp;<span class="caps">XBMC</span>:</p>
<table>
<thead>
<tr>
<th>Button</th>
<th>Command</th>
<th>Button</th>
<th>Command</th>
</tr>
</thead>
<tbody>
<tr>
<td>Channel Down</td>
<td><code>PageDown</code></td>
<td>Stop</td>
<td><code>X</code></td>
</tr>
<tr>
<td>Channel Up</td>
<td><code>PageUp</code></td>
<td>Skip back</td>
<td><code>Comma</code></td>
</tr>
<tr>
<td>Prev</td>
<td><code>Backspace</code></td>
<td>Skip forward</td>
<td><code>.</code></td>
</tr>
<tr>
<td>Up</td>
<td><code>DirectionUp</code></td>
<td>Play</td>
<td><code>P</code></td>
</tr>
<tr>
<td>Down</td>
<td><code>DirectionDown</code></td>
<td>Rewind</td>
<td><code>R</code></td>
</tr>
<tr>
<td>Left</td>
<td><code>DirectionLeft</code></td>
<td>Fast forward</td>
<td><code>F</code></td>
</tr>
<tr>
<td>Right</td>
<td><code>DirectionRight</code></td>
<td>Star</td>
<td><code>Delete</code></td>
</tr>
<tr>
<td><span class="caps">OK</span></td>
<td><code>Enter</code></td>
<td>Pound</td>
<td><code>W</code></td>
</tr>
<tr>
<td>Menu</td>
<td><code>C</code></td>
<td>Red</td>
<td><code>F1</code></td>
</tr>
<tr>
<td>Exit</td>
<td><code>Esc</code></td>
<td>Green</td>
<td><code>F2</code></td>
</tr>
<tr>
<td>Guide</td>
<td><code>Tab</code></td>
<td>Yellow</td>
<td><code>F3</code></td>
</tr>
<tr>
<td>Info</td>
<td><code>I</code></td>
<td>Blue</td>
<td><code>F4</code></td>
</tr>
</tbody>
</table>
<p>Unfortunately, the keytables provided with <code>ir-keytable</code> are not
complete enough. I have built a
<a href="https://gist.github.com/2466098#file_imon_mce" title="Keytable for iMON IR receiver with MCE keyboard">more complete table</a><sup id="fnref:missing"><a href="#fn:missing" rel="footnote">3</a></sup>. With this table and the
bindings described above, most functions will work out of the box
without <abbr title="Linux Infrared Remote Control"><span class="caps">LIRC</span></abbr>.</p>
<p>Additional keys can be configured in a dedicated keymap<sup id="fnref:keymap"><a href="#fn:keymap" rel="footnote">4</a></sup>. Here
is an excerpt of <a href="https://gist.github.com/2466098#file_harmony.xml" title="Additional keymap for my setup with an Harmony remote control">mine</a>:</p>
<div class="codehilite"><pre><span class="nt">&lt;keymap&gt;</span>
 <span class="nt">&lt;global&gt;</span>
  <span class="nt">&lt;keyboard&gt;</span>
    <span class="nt">&lt;end&gt;</span><span class="caps">XBMC</span>.ShutDown()<span class="nt">&lt;/end&gt;</span>
    <span class="nt">&lt;f1&gt;</span><span class="caps">XBMC</span>.ActivateWindow(MusicLibrary)<span class="nt">&lt;/f1&gt;</span>
    <span class="nt">&lt;f2&gt;</span><span class="caps">XBMC</span>.ActivateWindow(Videos,TvShowTitles)<span class="nt">&lt;/f2&gt;</span>
    <span class="nt">&lt;f3&gt;</span><span class="caps">XBMC</span>.ActivateWindow(Videos,MovieTitles)<span class="nt">&lt;/f3&gt;</span>
    <span class="nt">&lt;f4&gt;</span><span class="caps">XBMC</span>.ActivateWindow(Weather)<span class="nt">&lt;/f4&gt;</span>
  <span class="nt">&lt;/keyboard&gt;</span>
 <span class="nt">&lt;/global&gt;</span>
 <span class="nt">&lt;FullscreenVideo&gt;</span>
  <span class="nt">&lt;keyboard&gt;</span>
   <span class="nt">&lt;opensquarebracket&gt;</span>SubtitleDelayMinus<span class="nt">&lt;/opensquarebracket&gt;</span>
   <span class="nt">&lt;closesquarebracket&gt;</span>SubtitleDelayPlus<span class="nt">&lt;/closesquarebracket&gt;</span>
   <span class="nt">&lt;f6&gt;</span>xbmc.runscript(script.xbmc.subtitles)<span class="nt">&lt;/f6&gt;</span>
  <span class="nt">&lt;/keyboard&gt;</span>
 <span class="nt">&lt;/FullscreenVideo&gt;</span>
<span class="nt">&lt;/keymap&gt;</span>
</pre></div>


<h2 id="ftp"><span class="caps">FTP</span></h2>
<p>Instead of using <span class="caps">SSH</span>, I prefer to drop new files with anonymous
<span class="caps">FTP</span>. <em>vsftpd</em> fits this purpose. Here is my configuration&nbsp;file:</p>
<div class="codehilite"><pre><span class="n">listen</span><span class="p">=</span><span class="n"><span class="caps">YES</span></span>
<span class="n">xferlog_enable</span><span class="p">=</span><span class="n"><span class="caps">YES</span></span>
<span class="n">use_localtime</span><span class="p">=</span><span class="n"><span class="caps">YES</span></span>
<span class="n">setproctitle_enable</span><span class="p">=</span><span class="n"><span class="caps">YES</span></span>

<span class="n">secure_chroot_dir</span><span class="p">=</span><span class="o">/</span><span class="n">var</span><span class="o">/</span><span class="n">run</span><span class="o">/</span><span class="n">vsftpd</span><span class="o">/</span><span class="n">empty</span>
<span class="n">nopriv_user</span><span class="p">=</span><span class="n">ftp</span>
<span class="n">ftpd_banner</span><span class="p">=</span><span class="n"><span class="caps">XBMC</span></span>
<span class="n">hide_ids</span><span class="p">=</span><span class="n"><span class="caps">YES</span></span>

<span class="n">ftp_username</span><span class="p">=</span><span class="n">xbmc</span>
<span class="n">anon_umask</span><span class="p">=</span>022
<span class="n">anon_root</span><span class="p">=</span><span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">xbmc</span><span class="o">/</span><span class="n">media</span>
<span class="n">anonymous_enable</span><span class="p">=</span><span class="n"><span class="caps">YES</span></span>
<span class="n">write_enable</span><span class="p">=</span><span class="n"><span class="caps">YES</span></span>
<span class="n">anon_upload_enable</span><span class="p">=</span><span class="n"><span class="caps">YES</span></span>
<span class="n">anon_world_readable_only</span><span class="p">=</span><span class="n"><span class="caps">YES</span></span>
</pre></div>


<p>It is currently not compatible with <em>systemd</em> (see bug <a href="http://bugs.debian.org/670308" title="Bug #670308: vsftpd and systemd">#670308</a>). I
have removed the symlink in <code>/etc/rc2.d</code> and I have used the following
unit&nbsp;file:</p>
<div class="codehilite"><pre><span class="k">[Unit]</span>
<span class="na">Description</span><span class="o">=</span><span class="s">Vsftpd ftp daemon</span>
<span class="na">After</span><span class="o">=</span><span class="s">syslog.target network.target</span>

<span class="k">[Service]</span>
<span class="na">Type</span><span class="o">=</span><span class="s">simple</span>
<span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/sbin/vsftpd /etc/vsftpd.conf</span>
<span class="na">ExecReload</span><span class="o">=</span><span class="s">/bin/kill -<span class="caps">HUP</span> $<span class="caps">MAINPID</span></span>
<span class="na">ExecStartPre</span><span class="o">=</span><span class="s">-/bin/mkdir -p /var/run/vsftpd/empty</span>

<span class="k">[Install]</span>
<span class="na">WantedBy</span><span class="o">=</span><span class="s">multi-user.target</span>
</pre></div>


<h2 id="miscellaneous">Miscellaneous</h2>
<ol>
<li>
<p>In <code>/etc/default/grub</code>, reduce <code>TIMEOUT</code> to 0 to shorten the boot&nbsp;time.</p>
</li>
<li>
<p>Enabling <a href="http://wiki.xbmc.org/index.php?title=Dirty_regions" title="Enabling dirty regions in XBMC Eden">dirty regions</a> can help speed up&nbsp;<span class="caps">XBMC</span>.</p>
</li>
<li>
<p><code>aptitude install upower pm-utils</code> to be able to shutdown/suspend
    from <span class="caps">XBMC</span>. Since <span class="caps">XBMC</span> was configured to be started outside any
    session, you need to explicitely give the appropriate rights by
    creating the following
    <code>/var/lib/polkit-1/localauthority/50-local.d/xbmc.pkla</code>:</p>
<div class="codehilite"><pre><span class="k">[Actions for xbmc user]</span>
<span class="na">Identity</span><span class="o">=</span><span class="s">unix-user:xbmc</span>
<span class="na">Action</span><span class="o">=</span><span class="s">org.freedesktop.upower.*;org.freedesktop.consolekit.system.*</span>
<span class="na">ResultAny</span><span class="o">=</span><span class="s">yes</span>
<span class="na">ResultInactive</span><span class="o">=</span><span class="s">yes</span>
<span class="na">ResultActive</span><span class="o">=</span><span class="s">yes</span>
</pre></div>


</li>
</ol>
<div class="footnote">
<hr>
<ol>
<li id="fn:lcd">
<p>The readibility of the <span class="caps">LCD</span> screen is very bad. You should look
    at the <span class="caps">VFD</span> version. The <abbr title="Infrared"><abbr title="Infrared"><abbr title="Infrared"><span class="caps">IR</span></abbr></abbr></abbr> receiver reception is poor. The
    provided remote control is a joke.&#160;<a href="#fnref:lcd" rev="footnote" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
<li id="fn:wheezy">
<p>Debian Wheezy is not yet released. If you are unfamiliar
       with Debian, it may be cumbersome to maintain it until the
       freeze happens in a few months.&#160;<a href="#fnref:wheezy" rev="footnote" title="Jump back to footnote 2 in the text">&#8617;</a></p>
</li>
<li id="fn:missing">
<p>Some keys are missing from the provided table. For
        example, there is no exclamation mark. While there is a
        scan code for such a key in <span class="caps">RC</span>-6 protocol, there is no
        appropriate key code to translate to: on a <span class="caps">QWERTY</span>
        keyboard, the exclamation mark is on the same key as the
        number 1. It is possible to map it to some other key code,
        but the mapping would have been difficult to use.&#160;<a href="#fnref:missing" rev="footnote" title="Jump back to footnote 3 in the text">&#8617;</a></p>
</li>
<li id="fn:keymap">
<p>For example, in <code>~/.xbmc/userdata/keymaps/harmony.xml</code>.&#160;<a href="#fnref:keymap" rev="footnote" title="Jump back to footnote 4 in the text">&#8617;</a></p>
</li>
</ol>
</div>
]]>
            </content>
        </entry>
                <entry>
            <title type="html">Asynchronicity &amp; Net-SNMP AgentX protocol</title>
            <author><name>Vincent Bernat</name></author>
            <link href="http://vincent.bernat.im/en/blog/2012-fixing-async-agentx.html"/>
            <updated>2012-03-05T18:02:31+01:00</updated>
            <id>http://www.luffy.cx/en/blog/2012-fixing-async-agentx.html</id>

            <content type="html">
<![CDATA[
<p>One of the best way to
<a href="/en/blog/2012-extending-netsnmp.html" title="Recipes for extending Net-SNMP">add <abbr title="Simple Network Management Protocol"><abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr></abbr> support to an application is the use of AgentX protocol</a>:
an application can act as a <em>subagent</em> and handle requests from a
<em>master agent</em> using AgentX protocol. The most widespread
implementation for such a task is the one from Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr>.</p>
<p><strong><span class="caps">TL</span>;<span class="caps">DR</span></strong>: An application asynchronously leveraging Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> AgentX
implementation has many opportunities to get stuck when the master
agent becomes temporarily unavailable. A mostly efficient workaround
is to dedicate a master agent for AgentX and delegate <span class="caps">MIB</span> handling to
a&nbsp;subagent.</p>
<h1 id="pinging-the-master-agent">Pinging the master&nbsp;agent</h1>
<p>Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> uses an event-based model. It also provides some synchronous
functions but they are built on top of the asynchronous ones. It is
shipped with its own event loop. Therefore, Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> AgentX protocol
implementation seems a fine choice to add <abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> support to an
event-based program, for example in <a href="/en/blog/2011-keepalived-snmp-ipv6.html" title="SNMP support for keepalived">Keepalived</a>, a <abbr title="Virtual Router Redundancy Protocol"><span class="caps">VRRP</span></abbr>
daemon and a monitoring daemon for <abbr title="Linux Virtual Server"><span class="caps">LVS</span></abbr>&nbsp;clusters.</p>
<p>Unfortunately, an AgentX subagent is expected to check, at a regular
interval, if the master agent is alive . This is handled automatically
with Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> implementation as long as you call <code>run_alarms()</code>
function which will call <code>agentx_check_session()</code>:</p>
<div class="codehilite"><pre><span class="cm">/*</span>
<span class="cm"> * check a session validity for connectivity to the master agent.  If</span>
<span class="cm"> * not functioning, close and start attempts to reopen the session </span>
<span class="cm"> */</span>
<span class="kt">void</span>
<span class="nf">agentx_check_session</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">clientreg</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">clientarg</span><span class="p">)</span>
<span class="p">{</span>
    <span class="cm">/* [...] */</span>
    <span class="n"><span class="caps">DEBUGMSGTL</span></span><span class="p">((</span><span class="s">&quot;agentx/subagent&quot;</span><span class="p">,</span> <span class="s">&quot;checking status of session %p</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">ss</span><span class="p">));</span>

    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">agentx_send_ping</span><span class="p">(</span><span class="n">ss</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">snmp_log</span><span class="p">(</span><span class="n">LOG_WARNING</span><span class="p">,</span>
                 <span class="s">&quot;AgentX master agent failed to respond to ping.  Attempting to re-register.</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span>
        <span class="cm">/*</span>
<span class="cm">         * master agent disappeared?  Try and re-register.</span>
<span class="cm">         * close first, just to be sure .</span>
<span class="cm">         */</span>
        <span class="n">agentx_unregister_callbacks</span><span class="p">(</span><span class="n">ss</span><span class="p">);</span>
        <span class="n">agentx_close_session</span><span class="p">(</span><span class="n">ss</span><span class="p">,</span> <span class="n">AGENTX_CLOSE_TIMEOUT</span><span class="p">);</span>
        <span class="cm">/* [...] */</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">main_session</span> <span class="o">!=</span> <span class="nb"><span class="caps">NULL</span></span><span class="p">)</span> <span class="p">{</span>
            <span class="cm">/* [...] */</span>
            <span class="n">main_session</span> <span class="o">=</span> <span class="nb"><span class="caps">NULL</span></span><span class="p">;</span>
            <span class="n">agentx_reopen_session</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb"><span class="caps">NULL</span></span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">else</span> <span class="p">{</span>
            <span class="n">snmp_close</span><span class="p">(</span><span class="n">main_session</span><span class="p">);</span>
            <span class="n">main_session</span> <span class="o">=</span> <span class="nb"><span class="caps">NULL</span></span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n"><span class="caps">DEBUGMSGTL</span></span><span class="p">((</span><span class="s">&quot;agentx/subagent&quot;</span><span class="p">,</span> <span class="s">&quot;session %p responded to ping</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span>
                    <span class="n">ss</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></div>


<p>This piece of code will end up calling (directly or indirectly) the
following functions<sup id="fnref:synchfunctions"><a href="#fn:synchfunctions" rel="footnote">1</a></sup> which are using
<code>agentx_synch_response()</code>:</p>
<ul>
<li><code>agentx_send_ping()</code></li>
<li><code>agentx_open_session()</code></li>
<li><code>agentx_reopen_session()</code></li>
<li><code>agentx_close_session()</code></li>
<li><code>agentx_register()</code></li>
<li><code>agentx_unregister()</code></li>
<li><code>agentx_register_index()</code></li>
<li><code>agentx_unregister_index()</code></li>
<li><code>agentx_add_agentcaps()</code></li>
<li><code>agentx_remove_agentcaps()</code></li>
</ul>
<p><code>agentx_synch_response()</code> will <strong>synchronously</strong> wait for an answer
from the master agent. Your event-based program will just sit here
doing nothing while this happens. For example, <em>keepalived</em> may be
unable to send <abbr title="Virtual Router Redundancy Protocol"><span class="caps">VRRP</span></abbr> probes resulting in some serious havoc in your&nbsp;cluster.</p>
<p>Functions prefixed by <code>agentx_</code> are not part of NetSNMP <span class="caps">API</span> and could
therefore be rewritten to do their work asynchronously. Unfortunately,
<a href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=3479744&amp;group_id=12694&amp;atid=112694" title="run_alarms() can block a program, in Net-SNMP bug tracker">talk is</a> <a href="http://groups.google.com/group/mailing.unix.net-snmp-users/browse_thread/thread/391697fb5391989d" title="run_alarms() can block a program, in Net-SNMP mailing list">cheap</a>. Moreover, there exists
other deep paths that will block a subagent. For example, the
low-level connection to the master agent (using <span class="caps">TCP</span> or a Unix socket,
but not with <span class="caps">UDP</span>) will use a blocking <code>connect()</code> call. It seems quite
difficult to fix&nbsp;this.</p>
<p>Here are some (partial)&nbsp;workarounds:</p>
<ul>
<li>
<p>Call <code>agentx_check_session()</code> less often. The default interval is
   15 seconds. Disabling it completely or using a very high value is
   not advised because this function is the only way to reestablish a
   connection to the master agent when it is, for example,
   restarted. Here is how to change the delay to 120&nbsp;seconds:</p>
<div class="codehilite"><pre><span class="n">netsnmp_ds_set_int</span><span class="p">(</span><span class="n">NETSNMP_DS_APPLICATION_ID</span><span class="p">,</span>
                   <span class="n">NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL</span><span class="p">,</span> <span class="mi">120</span><span class="p">);</span>
</pre></div>


</li>
<li>
<p>Don&#8217;t call <code>agentx_check_session()</code> if we know the master agent is
   alive. For example, if it just sent us a new request, no need to
   ping it. I have written a
   <a href="http://sourceforge.net/tracker/?func=detail&amp;aid=3481686&amp;group_id=12694&amp;atid=312694" title="Patch avoiding use of AgentX ping">patch implementing such a workaround</a>. The <span class="caps">ABI</span> is left
   untouched, therefore, you only need to recompile Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr>&nbsp;libraries.</p>
</li>
<li>
<p>Use a lower timeout and no retry. By default, the timeout for
   synchronous requests is 1 second and a failed request will be
   retried 5 times. Because several synchronous functions are used in
   a row, you may be trapped for as long as 30 seconds with those
   settings. Here is how<sup id="fnref:how"><a href="#fn:how" rel="footnote">2</a></sup> to disable the retry mechanism and to
   set the timeout to a very low&nbsp;value:</p>
<div class="codehilite"><pre><span class="k">static</span> <span class="kt">int</span>
<span class="nf">snmp_setup_session_cb</span><span class="p">(</span><span class="kt">int</span> <span class="n">majorID</span><span class="p">,</span> <span class="kt">int</span> <span class="n">minorID</span><span class="p">,</span>
              <span class="kt">void</span> <span class="o">*</span><span class="n">serverarg</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">clientarg</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">netsnmp_session</span> <span class="o">*</span><span class="n">sess</span> <span class="o">=</span> <span class="n">serverarg</span><span class="p">;</span>
    <span class="n">sess</span><span class="o">-&gt;</span><span class="n">timeout</span> <span class="o">=</span> <span class="n">ONE_SEC</span> <span class="o">/</span> <span class="mi">3</span><span class="p">;</span>
    <span class="n">sess</span><span class="o">-&gt;</span><span class="n">retries</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">some_init_function</span><span class="p">()</span>
<span class="p">{</span>
    <span class="cm">/* [...] */</span>
    <span class="n">snmp_register_callback</span><span class="p">(</span><span class="n">SNMP_CALLBACK_LIBRARY</span><span class="p">,</span>
       <span class="n">SNMP_CALLBACK_SESSION_INIT</span><span class="p">,</span>
       <span class="n">snmp_setup_session_cb</span><span class="p">,</span> <span class="nb"><span class="caps">NULL</span></span><span class="p">);</span>
    <span class="cm">/* [...] */</span>
<span class="p">}</span>
</pre></div>


</li>
</ul>
<h1 id="unresponsive-master-agent">Unresponsive master&nbsp;agent</h1>
<p>Why is the master agent unresponsive? <code>snmpd</code> is also an event-based
program and, trust me, there are a lot of places where it will become
unresponsive. Here are two&nbsp;examples:</p>
<ul>
<li>
<p>When using the <code>pass</code> or the <code>pass_persist</code> directive, Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr>
   will block until the delegated command outputs a complete&nbsp;line.</p>
<div class="codehilite"><pre><span class="cm">/* var_extensible_pass() in agent/mibgroup/ucd-snmp/pass.c */</span>
<span class="cm">/*</span>
<span class="cm"> * valid call.  Exec and get output </span>
<span class="cm"> */</span>
<span class="k">if</span> <span class="p">((</span><span class="n">fd</span> <span class="o">=</span> <span class="n">get_exec_output</span><span class="p">(</span><span class="n">passthru</span><span class="p">))</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">file</span> <span class="o">=</span> <span class="n">fdopen</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="s">&quot;r&quot;</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">fgets</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">buf</span><span class="p">),</span> <span class="n">file</span><span class="p">)</span> <span class="o">==</span> <span class="nb"><span class="caps">NULL</span></span><span class="p">)</span> <span class="p">{</span>
        <span class="n">fclose</span><span class="p">(</span><span class="n">file</span><span class="p">);</span>
        <span class="n">wait_on_exec</span><span class="p">(</span><span class="n">passthru</span><span class="p">);</span>
        <span class="cm">/* [...] */</span>
        <span class="k">continue</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="cm">/* [...] */</span>
    <span class="n">fclose</span><span class="p">(</span><span class="n">file</span><span class="p">);</span>
    <span class="n">wait_on_exec</span><span class="p">(</span><span class="n">passthru</span><span class="p">);</span>
    <span class="cm">/* [...] */</span>
<span class="p">}</span>
</pre></div>


</li>
<li>
<p><code>DISMAN-PING-MIB</code> implementation will just hang while pinging the
   remote host. If the host is down and you have requested 5 probes
   with a timeout of 1 second, <code>snmpd</code> will be unresponsive for 5
   seconds. A similar problem exists with <code>DISMAN-TRACEROUTE-MIB</code>.</p>
</li>
</ul>
<h1 id="minimal-master-agent">Minimal master&nbsp;agent</h1>
<p>More and more code is running in the main agent. You cannot expect it
to not block. But we could add a <em>minimal master agent</em> to the mix: it
will handle only a few <span class="caps">MIB</span> modules by itself while most <span class="caps">MIB</span> modules
will be delagated to a complete agent running as a subagent. Your own
subagent will connect to the minimal master&nbsp;agent.</p>
<p><img alt="Schema showing the use of a minimal master agent" src="//d1g3mdmxf8zbo9.cloudfront.net/images/minimal-snmpd.png" title="Adding a minimal master agent and turning snmpd into a subagent"></p>
<p>It is quite easy to turn <code>snmpd</code> into a subagent: just use <code>-X</code>
flag. We should also disable unwanted <span class="caps">MIB</span> modules for each agent with
<code>-I</code> flag. For the minimal master agent, we only enable some
modules. All other modules<sup id="fnref:modules"><a href="#fn:modules" rel="footnote">3</a></sup> will be served by <code>snmpd</code> acting
as a&nbsp;subagent.</p>
<div class="codehilite"><pre><span class="gp">$</span> <span class="nv"><span class="caps">MODS</span></span><span class="o">=</span><span class="s2">&quot;snmp_mib,sysORTable,usmConf,usmStats,usmUser,vacm_conf,vacm_context,vacm_vars&quot;</span>
<span class="gp">$</span> snmpd -Lsd -Lf /dev/null -u snmp -g snmp <span class="se">\</span>
<span class="gp">&gt;</span>   -C -c /etc/snmp/snmpd.master.conf <span class="se">\</span>
<span class="gp">&gt;</span>   -p /var/run/snmpd.master.pid <span class="se">\</span>
<span class="gp">&gt;</span>   -I <span class="nv">$<span class="caps">MODS</span></span>
<span class="gp">$</span> snmpd -Lsd -Lf /dev/null -u snmp -g snmp <span class="se">\</span>
<span class="gp">&gt;</span>   -p /var/run/snmpd.pid -X <span class="se">\</span>
<span class="gp">&gt;</span>   -I -<span class="nv">$<span class="caps">MODS</span></span>
</pre></div>


<p>Access control configuration should be placed in
<code>/etc/snmp/snmpd.master.conf</code>, as well as <code>master agentx</code>
directive. Other directives (like <code>pass</code>, <code>pass_persist</code>, <code>load</code>,
<code>sysname</code>, &#8230;) in <code>/etc/snmp/snmpd.conf</code>.</p>
<p>The minimal master agent is very unlikely to block and while the
ground cause is still here, it is now very much mitigated. You may
extend this solution by splicing <code>snmpd</code> into several subagents: one
handling safe modules, one handling <code>pass</code> and <code>pass_persist</code> stuff
and a last one for unsafe modules (like <code>DISMAN-PING-MIB</code>).</p>
<div class="footnote">
<hr>
<ol>
<li id="fn:synchfunctions">
<p><code>agentx_reopen_session()</code> will call <code>agentx_close_session()</code>
               and <code>agentx_open_session()</code>. <code>agentx_register()</code> and
               the following functions will be called by those
               two functions.&#160;<a href="#fnref:synchfunctions" rev="footnote" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
<li id="fn:how">
<p><code>NETSNMP_DS_AGENT_AGENTX_TIMEOUT</code> and <code>NETSNMP_DS_AGENT_AGENTX_RETRIES</code>
    variables are only used by the master agent, not by a subagent.&#160;<a href="#fnref:how" rev="footnote" title="Jump back to footnote 2 in the text">&#8617;</a></p>
</li>
<li id="fn:modules">
<p>Use <code>snmpd -Dmib_init -H</code> to get the list of modules. You
        may want to add <code>smux</code> module to the master agent.&#160;<a href="#fnref:modules" rev="footnote" title="Jump back to footnote 3 in the text">&#8617;</a></p>
</li>
</ol>
</div>
]]>
            </content>
        </entry>
                <entry>
            <title type="html">Recipes for extending Net-SNMP</title>
            <author><name>Vincent Bernat</name></author>
            <link href="http://vincent.bernat.im/en/blog/2012-extending-netsnmp.html"/>
            <updated>2012-02-09T19:30:35+01:00</updated>
            <id>http://www.luffy.cx/en/blog/2012-extending-netsnmp.html</id>

            <content type="html">
<![CDATA[
<p><abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> stands for <a href="http://en.wikipedia.org/wiki/Simple_Network_Management_Protocol" title="SNMP on Wikipedia">Simple Network Management Protocol</a>. It allows
a <em>manager</em> to query information from an <em>agent</em>. A popular use of
<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> is to retrieve network interface counters to plot a bandwidth
graph. While the &#8220;S&#8221; in <abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> stands for <em>simple</em>, <abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> can be quite
difficult to deal with. However, it is still the <em>de facto</em> standard
for retrieving metrics in an heterogeneous
environment. <a href="http://www.net-snmp.org/" title="Net-SNMP, a suite of applications for SNMP">Net-<abbr title="Simple Network Management Protocol"><abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr></abbr></a> is a suite of <abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> applications
including an agent. Out of the box, this agent exports a lot of
information but if something is missing, there are several ways to
extend it. Which&nbsp;ones?</p>
<p><strong>tl;dr</strong>: in my opinion, extending Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> should be done with
either of those&nbsp;methods:</p>
<ul>
<li>using <code>extend</code> directive;</li>
<li>using <code>pass_persist</code> directive;</li>
<li>using AgentX&nbsp;protocol.</li>
</ul>
<div class="toc">
<ul>
<li><a href="#snmp-in-a-nutshell"><span class="caps">SNMP</span> in a&nbsp;nutshell</a></li>
<li><a href="#extending-net-snmp">Extending Net-<span class="caps">SNMP</span></a><ul>
<li><a href="#with-arbitrary-commands">With arbitrary&nbsp;commands</a></li>
<li><a href="#with-pass-through-scripts">With pass-through&nbsp;scripts</a></li>
<li><a href="#with-agentx-protocol">With AgentX protocol</a><ul>
<li><a href="#perl-and-python">Perl and&nbsp;Python</a></li>
<li><a href="#c-with-new-api">C with &#8220;new&#8221;&nbsp;<span class="caps">API</span></a></li>
<li><a href="#c-with-traditional-api">C with &#8220;traditional&#8221;&nbsp;<span class="caps">API</span></a></li>
</ul>
</li>
<li><a href="#other-solutions">Other&nbsp;solutions</a></li>
</ul>
</li>
</ul>
</div>
<h1 id="snmp-in-a-nutshell"><abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> in a&nbsp;nutshell</h1>
<p>The <em>variables</em> accessible with <abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> through the agent are organized
in a tree. Each variable is typed and associated to an <em>object
identifier</em> (or <abbr title="Object IDentifier"><span class="caps">OID</span></abbr>). For example, <code>.1.3.6.1.2.1.31.1.1.1.1.2</code> is the
<abbr title="Object IDentifier"><span class="caps">OID</span></abbr> of the name of the second network&nbsp;card.</p>
<p>Usually, <abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> is operated over <span class="caps">UDP</span>, port 161. For the purpose of this
article, we consider a manager can issue three kinds of&nbsp;requests:</p>
<dl>
<dt><span class="caps">GET</span></dt>
<dd>retrieve a&nbsp;variable.</dd>
<dt><span class="caps">GETNEXT</span></dt>
<dd>retrieve the next variable, in lexical order of their <abbr title="Object IDentifier"><span class="caps">OID</span></abbr>. This
  operation enables an <abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> manager to <em>walk</em> through all available
  variables, for example to discover the list of interfaces of an
  agent. This operation is what makes an <abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> agent difficult to
  implement but this is also a critical&nbsp;feature.</dd>
<dt><span class="caps">SET</span></dt>
<dd>request the modification of a&nbsp;variable.</dd>
</dl>
<p>Since such an <abbr title="Object IDentifier"><span class="caps">OID</span></abbr> may be difficult to handle by humans, available
variables are described by a <a href="http://en.wikipedia.org/wiki/Management_information_base" title="MIB on Wikipedia"><abbr title="Management Information Base"><abbr title="Management Information Base"><span class="caps">MIB</span></abbr></abbr></a> module which is a file that
should be parsed to get a mapping between <abbr title="Object IDentifier"><span class="caps">OID</span></abbr> and variable names and
types. For example, the above <abbr title="Object IDentifier"><span class="caps">OID</span></abbr> can also be referred as
<code>IF-MIB::ifName.2</code>. Those <abbr title="Management Information Base"><span class="caps">MIB</span></abbr> modules are described using a subset of
<a href="http://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One" title="ASN.1 syntax on Wikipedia"><span class="caps">ASN</span>.1</a> defined in <a href="http://tools.ietf.org/html/rfc2578" title="RFC 2578: SMIv2"><span class="caps">RFC</span> 2578</a>.</p>
<p>A <abbr title="Management Information Base"><span class="caps">MIB</span></abbr> module allows to group several variables into a conceptual
table. For example, <code>IF-MIB::ifDescr</code>, <code>IF-MIB::ifType</code>,
<code>IF-MIB::ifSpeed</code> are columns of <code>IF-MIB::ifTable</code>. Each row is
associated to an index. In the case of <code>IF-MIB::ifTable</code>, it is the
interface index. Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> includes <code>snmptable</code> allowing one to display
such a table in a natural manner<sup id="fnref:snmpconf"><a href="#fn:snmpconf" rel="footnote">1</a></sup>:</p>
<div class="codehilite"><pre><span class="gp">$</span> snmptable localhost <span class="caps">IF</span>-<span class="caps">MIB</span>::ifTable
<span class="go"><span class="caps">SNMP</span> table: <span class="caps">IF</span>-<span class="caps">MIB</span>::ifTable</span>

<span class="go"> ifIndex ifDescr           ifType ifMtu   ifSpeed</span>
<span class="go">       1      lo softwareLoopback 16436  10000000</span>
<span class="go">       2    eth0   ethernetCsmacd  1500 100000000</span>
<span class="go">       3    eth1   ethernetCsmacd  1500  10000000</span>
<span class="go">       4     br0   ethernetCsmacd  1500         0</span>
</pre></div>


<p>Variables inside a table are called <em>columnar objects</em> while those
outside are <em>scalar objects</em>. <abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr>, as a protocol, does not care of
this distinction since it does not know the concept of <abbr title="Management Information Base"><span class="caps">MIB</span></abbr>&nbsp;modules.</p>
<p>Other useful tools from Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> includes <code>snmpget</code> to get a specific
variable, <code>snmpwalk</code> to discover available variables (with <em><span class="caps">GETNEXT</span></em>
operation) from an <abbr title="Object IDentifier"><span class="caps">OID</span></abbr> and <code>snmptranslate</code> to translate between object
names and <abbr title="Object IDentifier"><span class="caps">OID</span></abbr>.</p>
<div class="codehilite"><pre><span class="gp">$</span> snmpget localhost <span class="caps">IF</span>-<span class="caps">MIB</span>::ifDescr.2
<span class="go"><span class="caps">IF</span>-<span class="caps">MIB</span>::ifDescr.2 = <span class="caps">STRING</span>: eth0</span>
<span class="gp">$</span> snmpwalk localhost <span class="caps">IF</span>-<span class="caps">MIB</span>::ifDescr
<span class="go"><span class="caps">IF</span>-<span class="caps">MIB</span>::ifDescr.1 = <span class="caps">STRING</span>: lo</span>
<span class="go"><span class="caps">IF</span>-<span class="caps">MIB</span>::ifDescr.2 = <span class="caps">STRING</span>: eth0</span>
<span class="go"><span class="caps">IF</span>-<span class="caps">MIB</span>::ifDescr.3 = <span class="caps">STRING</span>: eth1</span>
<span class="go"><span class="caps">IF</span>-<span class="caps">MIB</span>::ifDescr.4 = <span class="caps">STRING</span>: br0</span>
<span class="gp">$</span> snmpwalk -On public localhost .1.3.6.1.2.1.2.2.1.2
<span class="go">.1.3.6.1.2.1.2.2.1.2.1 = <span class="caps">STRING</span>: lo</span>
<span class="go">.1.3.6.1.2.1.2.2.1.2.2 = <span class="caps">STRING</span>: eth0</span>
<span class="go">.1.3.6.1.2.1.2.2.1.2.3 = <span class="caps">STRING</span>: eth1</span>
<span class="go">.1.3.6.1.2.1.2.2.1.2.4 = <span class="caps">STRING</span>: br0</span>
<span class="gp">$</span> snmptranslate -On <span class="caps">IF</span>-<span class="caps">MIB</span>::ifDescr.3
<span class="go">.1.3.6.1.2.1.2.2.1.2.3</span>
</pre></div>


<h1 id="extending-net-snmp">Extending Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr></h1>
<p><code>ethtool -S</code> allows us to access various statistics from a network
card, like the number of octets received and transmitted or the number
of collisions. While some of those statistics are defined in
<a href="http://tools.ietf.org/html/rfc2233" title="RFC 2233: The Interfaces Group MIB using SMIv2"><span class="caps">IF</span>-<abbr title="Management Information Base"><abbr title="Management Information Base"><span class="caps">MIB</span></abbr></abbr></a>, in <a href="http://tools.ietf.org/html/rfc1757" title="RFC 1757: RMON"><span class="caps">RMON</span>-<abbr title="Management Information Base"><abbr title="Management Information Base"><span class="caps">MIB</span></abbr></abbr></a> and in
<a href="http://tools.ietf.org/html/rfc3635" title="RFC 3635: Ethernet-like Interface Types">EtherLike-<abbr title="Management Information Base"><abbr title="Management Information Base"><span class="caps">MIB</span></abbr></abbr></a>, some of them are not available and very
specific. Therefore, we would like to export those statistics,
unmodified, through <abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr>.</p>
<p>To the best of my knowledge, no <abbr title="Management Information Base"><span class="caps">MIB</span></abbr> module exists for such an
usage. The first task is to write one. It can be called
<a href="https://github.com/vincentbernat/extend-netsnmp/blob/master/ETHTOOL-MIB" title="ETHTOOL-MIB"><span class="caps">ETHTOOL</span>-<abbr title="Management Information Base"><abbr title="Management Information Base"><span class="caps">MIB</span></abbr></abbr></a>. It only contains one table indexed by the
interface index and the name of the statistic. Here is the expected&nbsp;output:</p>
<div class="codehilite"><pre><span class="gp">$</span> snmpwalk localhost <span class="caps">ETHTOOL</span>-<span class="caps">MIB</span>::ethtoolStat.2
<span class="go">ethtoolStat.2.&#39;align_errors&#39; = Counter64: 0</span>
<span class="go">ethtoolStat.2.&#39;broadcast&#39; = Counter64: 25</span>
<span class="go">ethtoolStat.2.&#39;multicast&#39; = Counter64: 345</span>
<span class="go">ethtoolStat.2.&#39;rx_errors&#39; = Counter64: 0</span>
<span class="go">ethtoolStat.2.&#39;rx_missed&#39; = Counter64: 0</span>
<span class="go">ethtoolStat.2.&#39;rx_packets&#39; = Counter64: 262011</span>
<span class="go">ethtoolStat.2.&#39;tx_aborted&#39; = Counter64: 0</span>
<span class="go">ethtoolStat.2.&#39;tx_errors&#39; = Counter64: 0</span>
<span class="go">ethtoolStat.2.&#39;tx_multi_collisions&#39; = Counter64: 0</span>
<span class="go">ethtoolStat.2.&#39;tx_packets&#39; = Counter64: 296170</span>
<span class="go">ethtoolStat.2.&#39;tx_single_collisions&#39; = Counter64: 0</span>
<span class="go">ethtoolStat.2.&#39;tx_underrun&#39; = Counter64: 0</span>
<span class="go">ethtoolStat.2.&#39;unicast&#39; = Counter64: 261641</span>
</pre></div>


<p>I have coded various implementations of this <abbr title="Management Information Base"><span class="caps">MIB</span></abbr> module and made them
available in a <a href="https://github.com/vincentbernat/extend-netsnmp/" title="Various examples on how to extend Net-SNMP">GitHub repository</a>.</p>
<h2 id="with-arbitrary-commands">With arbitrary&nbsp;commands</h2>
<p>The <code>extend</code> directive allows the agent to execute an arbitrary
command and to provide its output and status through
<code>NET-SNMP-EXTEND-MIB</code> module. If we want to export the statistics for
<code>eth0</code>, we could add something like this in <code>snmpd.conf</code>, using a
<a href="https://github.com/vincentbernat/extend-netsnmp/blob/master/net-snmp-extend/ethtool-stats" title="Simple script to format the output of ethtool">custom script</a> to format the output of <code>ethtool -S</code> in
a way that is more suitable for our&nbsp;use:</p>
<div class="codehilite"><pre><span class="c"># Export eth0 statistics</span>
<span class="n">extend</span> <span class="n">eth0</span><span class="o">-</span><span class="n">names</span>  <span class="o">/</span><span class="nb">full</span><span class="o">/</span><span class="nb">path</span><span class="o">/</span><span class="n">to</span><span class="o">/</span><span class="n">ethtool</span><span class="o">-</span><span class="n">stats</span> <span class="n">eth0</span> <span class="n">names</span>
<span class="n">extend</span> <span class="n">eth0</span><span class="o">-</span><span class="n">values</span> <span class="o">/</span><span class="nb">full</span><span class="o">/</span><span class="nb">path</span><span class="o">/</span><span class="n">to</span><span class="o">/</span><span class="n">ethtool</span><span class="o">-</span><span class="n">stats</span> <span class="n">eth0</span> <span class="n">values</span>
</pre></div>


<p>The result can be retrieved through
<code>NET-SNMP-EXTEND-MIB::‌nsExtendOutput2Table</code>:</p>
<div class="codehilite"><pre><span class="gp">$</span> snmpwalk localhost <span class="caps">NET</span>-<span class="caps">SNMP</span>-<span class="caps">EXTEND</span>-<span class="caps">MIB</span>::nsExtendOutput2Table
<span class="go">nsExtendOutLine.&quot;eth0-names&quot;.1 = <span class="caps">STRING</span>: tx_packets</span>
<span class="go">nsExtendOutLine.&quot;eth0-names&quot;.2 = <span class="caps">STRING</span>: rx_packets</span>
<span class="go">nsExtendOutLine.&quot;eth0-names&quot;.3 = <span class="caps">STRING</span>: tx_errors</span>
<span class="go">nsExtendOutLine.&quot;eth0-names&quot;.4 = <span class="caps">STRING</span>: rx_errors</span>
<span class="go">nsExtendOutLine.&quot;eth0-names&quot;.5 = <span class="caps">STRING</span>: rx_missed</span>
<span class="go">nsExtendOutLine.&quot;eth0-names&quot;.6 = <span class="caps">STRING</span>: align_errors</span>
<span class="go">nsExtendOutLine.&quot;eth0-names&quot;.7 = <span class="caps">STRING</span>: tx_single_collisions</span>
<span class="go">nsExtendOutLine.&quot;eth0-names&quot;.8 = <span class="caps">STRING</span>: tx_multi_collisions</span>
<span class="go">nsExtendOutLine.&quot;eth0-values&quot;.1 = <span class="caps">STRING</span>: 246309</span>
<span class="go">nsExtendOutLine.&quot;eth0-values&quot;.2 = <span class="caps">STRING</span>: 223941</span>
<span class="go">nsExtendOutLine.&quot;eth0-values&quot;.3 = <span class="caps">STRING</span>: 0</span>
<span class="go">nsExtendOutLine.&quot;eth0-values&quot;.4 = <span class="caps">STRING</span>: 0</span>
<span class="go">nsExtendOutLine.&quot;eth0-values&quot;.5 = <span class="caps">STRING</span>: 0</span>
<span class="go">nsExtendOutLine.&quot;eth0-values&quot;.6 = <span class="caps">STRING</span>: 0</span>
<span class="go">nsExtendOutLine.&quot;eth0-values&quot;.7 = <span class="caps">STRING</span>: 0</span>
<span class="go">nsExtendOutLine.&quot;eth0-values&quot;.8 = <span class="caps">STRING</span>: 0</span>
</pre></div>


<p>It is also possible to configure such a command using <em><span class="caps">SET</span></em>
requests. For example, if we want to add statistics for <code>eth2</code>, we
could issue the following&nbsp;command:</p>
<div class="codehilite"><pre><span class="gp">$</span> snmpset -m +<span class="caps">NET</span>-<span class="caps">SNMP</span>-<span class="caps">EXTEND</span>-<span class="caps">MIB</span> localhost <span class="se">\</span>
<span class="gp">&gt;</span>    <span class="s1">&#39;nsExtendStatus.&quot;eth2-names&quot;&#39;</span>  <span class="o">=</span> createAndGo <span class="se">\</span>
<span class="gp">&gt;</span>    <span class="s1">&#39;nsExtendCommand.&quot;eth2-names&quot;&#39;</span> <span class="o">=</span> /full/path/to/ethtool-stats <span class="se">\</span>
<span class="gp">&gt;</span>    <span class="s1">&#39;nsExtendArgs.&quot;eth2-names&quot;&#39;</span>    <span class="o">=</span> <span class="s1">&#39;eth2 names&#39;</span> <span class="se">\</span>
<span class="gp">&gt;</span>    <span class="s1">&#39;nsExtendStatus.&quot;eth2-values&quot;&#39;</span>  <span class="o">=</span> createAndGo <span class="se">\</span>
<span class="gp">&gt;</span>    <span class="s1">&#39;nsExtendCommand.&quot;eth2-values&quot;&#39;</span> <span class="o">=</span> /full/path/to/ethtool-stats <span class="se">\</span>
<span class="gp">&gt;</span>    <span class="s1">&#39;nsExtendArgs.&quot;eth2-values&quot;&#39;</span>    <span class="o">=</span> <span class="s1">&#39;eth2 values&#39;</span>
<span class="go">nsExtendStatus.&quot;eth2-names&quot; = <span class="caps">INTEGER</span>: createAndGo(4)</span>
<span class="go">nsExtendCommand.&quot;eth2-names&quot; = <span class="caps">STRING</span>: /full/path/to/ethtool-stats</span>
<span class="go">nsExtendArgs.&quot;eth2-names&quot; = <span class="caps">STRING</span>: eth2 names</span>
<span class="go">nsExtendStatus.&quot;eth2-values&quot; = <span class="caps">INTEGER</span>: createAndGo(4)</span>
<span class="go">nsExtendCommand.&quot;eth2-values&quot; = <span class="caps">STRING</span>: /full/path/to/ethtool-stats</span>
<span class="go">nsExtendArgs.&quot;eth2-values&quot; = <span class="caps">STRING</span>: eth2 values</span>
<span class="gp">$</span> snmpgetnext -m +<span class="caps">NET</span>-<span class="caps">SNMP</span>-<span class="caps">EXTEND</span>-<span class="caps">MIB</span> localhost <span class="se">\</span>
<span class="gp">&gt;</span>    <span class="s1">&#39;nsExtendOutLine.&quot;eth2-names&quot;&#39;</span>
<span class="go">nsExtendOutLine.&quot;eth2-names&quot;.1 = <span class="caps">STRING</span>: tx_packets</span>
</pre></div>


<p>This can be very convenient but also a huge security risk. You should
disable this functionality or
<a href="https://github.com/vincentbernat/extend-netsnmp/blob/master/net-snmp-extend/snmpd.conf" title="snmpd.conf disabling the ability to configure NET-SNMP-EXTEND-MIB except for a super admin">enable it only for some SNMPv3 user</a>.</p>
<p>Using <code>extend</code> does not allow to implement an arbitrary <abbr title="Management Information Base"><span class="caps">MIB</span></abbr> module. If
the cache is not disabled, <code>extend</code> is a good solution for various
simple needs, like providing the content of a one-line file or the
output of some Nagios plugin. However, exporting anything tabular,
like interface statistics, is not a good&nbsp;fit.</p>
<h2 id="with-pass-through-scripts">With pass-through&nbsp;scripts</h2>
<p>Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> allows one to extend the agent by delegating some sub-tree to
a script defined by the <code>pass_persist</code> directive. Such a script will
receive requests on its standard input with a very simple
line-oriented protocol described in the
<a href="http://linux.die.net/man/5/snmpd.conf" title="Manual page of snmpd.conf">manual page of snmpd.conf</a>. Here is an example of&nbsp;interaction:</p>
<div class="codehilite"><pre>→  PING
←  PONG
→  get
→  .1.3.6.1.4.1.39178.100.1.1.1.2.2.109.117.108.116.105.99.97.115.116
←  .1.3.6.1.4.1.39178.100.1.1.1.2.2.109.117.108.116.105.99.97.115.116
←  counter64
←  223941
→  getnext
→  .1.3.6.1.4.1.39178.100.1.1.1.2.2
←  .1.3.6.1.4.1.39178.100.1.1.1.2.2.97.108.105.103.110.95.101.114
←  counter64
←  0
</pre></div>


<p>The protocol is simple enough to implement it from scratch in any
scripting language. However, in Perl, you may prefer to use
<a href="http://search.cpan.org/~saper/SNMP-Extension-PassPersist-0.06/lib/SNMP/Extension/PassPersist.pm" title="SNMP::Extension::PassPersist extension for Perl"><abbr title="Simple Network Management Protocol"><abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr></abbr>::‌ExtensionSNMP::‌PassPersist</a> extension from Sébastien
Aperghis-Tramoni. You can find the
<a href="https://github.com/vincentbernat/extend-netsnmp/blob/master/passpersist-perl/ethtool-stats.pl" title="Export ethtool statistics using pass_persist in Perl">complete example on Github</a>.</p>
<div class="codehilite"><pre><span class="k">use</span> <span class="nn"><span class="caps">SNMP</span>::Extension::</span><span class="n">PassPersist</span><span class="p">;</span>
<span class="k">my</span> <span class="nv">$extsnmp</span> <span class="o">=</span> <span class="nn"><span class="caps">SNMP</span>::Extension::</span><span class="n">PassPersist</span><span class="o">-&gt;</span><span class="k">new</span><span class="p">(</span>
    <span class="n">backend_collect</span> <span class="o">=&gt;</span> <span class="o">\&amp;</span><span class="n">update_tree</span>
    <span class="p">);</span>
<span class="nv">$extsnmp</span><span class="o">-&gt;</span><span class="n">run</span><span class="p">;</span>

<span class="k">sub </span><span class="nf">update_tree</span> <span class="p">{</span>
    <span class="k">my</span> <span class="nv">@interfaces</span> <span class="o">=</span> <span class="sr">&lt;/sys/class/net/*&gt;</span><span class="p">;</span>
    <span class="k">foreach</span> <span class="k">my</span> <span class="nv">$interface</span> <span class="p">(</span><span class="nv">@interfaces</span><span class="p">)</span> <span class="p">{</span>
        <span class="nv">$interface</span> <span class="o">=~</span> <span class="sr">s/^.*\///</span><span class="p">;</span>
        <span class="nb">open</span><span class="p">(</span><span class="n"><span class="caps">ETHTOOL</span></span><span class="p">,</span> <span class="s">&quot;ethtool -S $interface 2&gt;/dev/null |&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="k">next</span><span class="p">;</span>
        <span class="k">while</span> <span class="p">(</span><span class="sr">&lt;<span class="caps">ETHTOOL</span>&gt;</span><span class="p">)</span> <span class="p">{</span>
            <span class="sr">/^\s+(\w+): (\d+)$/</span> <span class="ow">or</span> <span class="k">next</span><span class="p">;</span>
            <span class="k">my</span> <span class="nv">$name</span>  <span class="o">=</span> <span class="nv">$1</span><span class="p">;</span>
            <span class="k">my</span> <span class="nv">$value</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nv">$2</span><span class="p">);</span>
            <span class="k">my</span> <span class="nv">$oid</span>   <span class="o">=</span> <span class="n">oid_compute</span><span class="p">(</span><span class="nv">$interface</span><span class="p">,</span> <span class="nv">$name</span><span class="p">);</span>
            <span class="nv">$extsnmp</span><span class="o">-&gt;</span><span class="n">add_oid_entry</span><span class="p">(</span><span class="nv">$oid</span><span class="p">,</span> <span class="s">&quot;counter&quot;</span><span class="p">,</span> <span class="nv">$value</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="nb">close</span><span class="p">(</span><span class="n"><span class="caps">ETHTOOL</span></span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></div>


<p>With Python, <a href="http://pypi.python.org/pypi/snmp-passpersist" title="snmp-passpersist module for Python">snmp-passpersist</a> module, from Nicolas
Agius, provides a similar interface. Look at the
<a href="https://github.com/vincentbernat/extend-netsnmp/blob/master/passpersist-python/ethtool-stats.py" title="Export ethtool statistics using pass_persist in Python">complete example on GitHub</a>.</p>
<p><code>pass_persist</code> allows you to implement an arbitrary <abbr title="Management Information Base"><span class="caps">MIB</span></abbr> module with
honest performances. Here are some important things to know about this&nbsp;directive:</p>
<ul>
<li>Unless you have a recent version of Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr>, 64bit types are
   converted to 32bit equivalents. The counters may overflow&nbsp;quickly.</li>
<li>While handling a request, you are not allowed to pause (for
   example, to fetch a remote information): the agent would become
   unresponsive. If you need slow-to-get data or data from the agent,
   grab them in a separate thread and ensure you have them&nbsp;beforehand.</li>
</ul>
<h2 id="with-agentx-protocol">With AgentX&nbsp;protocol</h2>
<p>AgentX is a protocol defined in <a href="http://tools.ietf.org/html/rfc2741" title="RFC 2741: Ethernet-like Interface Types"><span class="caps">RFC</span> 2741</a> allowing a <em>master
agent</em> to be extended by independent <em>sub-agents</em>. For <code>snmpd</code> to
become a master agent, you just need to add <code>master agentx</code> in
<code>snmpd.conf</code>. Here are some of the benefits of an AgentX sub-agent over
<code>pass_persist</code>:</p>
<ol>
<li>No configuration is needed for the master agent to accept an
    additional sub-agent. A sub-agent registers to the master agent
    the <abbr title="Management Information Base"><span class="caps">MIB</span></abbr> modules (or part of them) it wants to take care&nbsp;of.</li>
<li>A sub-agent is decoupled from the master agent. It can run with a
    different identity or be integrated into another daemon to export
    its internal metrics, send traps or allow remote configuration
    through <abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr>.</li>
<li>AgentX protocol can be carried over <span class="caps">TCP</span>. Sub-agents can therefore
    run on a foreign host or in a jailed&nbsp;environment.</li>
<li>64bit types are fully supported. Traps are also&nbsp;supported.</li>
</ol>
<h3 id="perl-and-python">Perl and&nbsp;Python</h3>
<p>Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> provides a Perl module, <code>NetSNMP::agent</code>, to write a sub-agent
using AgentX protocol. This module is not as convenient as the module
for <code>pass_persist</code> described above since it does not provide a
convenient layer to put required information into some
datastore. Basically, it mimics the available C <span class="caps">API</span>. Here are a few
examples of its&nbsp;use:</p>
<ul>
<li>An <a href="https://github.com/vincentbernat/extend-netsnmp/blob/master/agentx-perl/ethtool-stats.pl" title="Export ethtool statistics using AgentX in Perl">implementation of <span class="caps">ETHTOOL</span>-<abbr title="Management Information Base"><abbr title="Management Information Base"><span class="caps">MIB</span></abbr></abbr></a> I have
   done in the same way as the <code>pass_persist</code> version. My Perl skills
   are a bit rusty and the code has many rough&nbsp;edges.</li>
<li>An <a href="https://github.com/masterzen/redis-snmp/blob/master/redis-snmp" title="SNMP subagent for Redis servers">implementation of a sub-agent for Redis servers</a>.</li>
<li>An <a href="http://net-snmp.git.sourceforge.net/git/gitweb.cgi?p=net-snmp/net-snmp;a=blob;f=local/snmp-bridge-mib;hb=171e8d48d4af04013cff8fd28f5341a2aef21d88" title="An implementation of BRIDGE-MIB as a Perl AgentX subagent">implementation of <span class="caps">BRIDGE</span>-<abbr title="Management Information Base"><abbr title="Management Information Base"><span class="caps">MIB</span></abbr></abbr></a> shipped with Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr>.</li>
</ul>
<p>There is no similar binding for Python but there is an
<a href="https://sourceforge.net/projects/python-agentx/" title="AgentX module for Python">agentx extension</a> using <code>ctypes</code>. It provides a more
high-level view. I did not write an example for this one but you can
look at the <a href="http://python-agentx.svn.sourceforge.net/viewvc/python-agentx/example.py?revision=8&amp;view=markup" title="Example of Python agentx module">example provided by the author</a>.</p>
<h3 id="c-with-new-api">C with &#8220;new&#8221;&nbsp;<span class="caps">API</span></h3>
<p>To write a sub-agent in C, you have to choose between two&nbsp;<span class="caps">API</span>:</p>
<ol>
<li>the <span class="caps">API</span> inherited from <span class="caps">UCD</span>-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> also known as the &#8220;traditional&#8221;&nbsp;<span class="caps">API</span>;</li>
<li>the new <span class="caps">API</span> developed for Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr>&nbsp;5.x.</li>
</ol>
<p>With both <span class="caps">API</span>, an handler is registered to take care of one or several
sub-trees. With the traditional <span class="caps">API</span>, the handler is invoked with very
little information. It is then up to you to locate the appropriate
variable by mapping the index part of the <abbr title="Object IDentifier"><span class="caps">OID</span></abbr> to the objects you want
to export. It is quite simple for scalar objects but columnar objects
with complex indexes are a pain with such an&nbsp;<span class="caps">API</span>.</p>
<p>The new <span class="caps">API</span> provides various helpers. Some of them allow you to copy
objects into an array or a list and let Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> library do the hard
work of serving them. Another helper will provide methods to serve
objects without putting them in a special structure but by providing
an iterator. Some of those helpers can also help you to cache some&nbsp;variables.</p>
<p>On top of this new <span class="caps">API</span>, Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> comes with <code>mib2c</code>, a tool that will
help you convert a <abbr title="Management Information Base"><span class="caps">MIB</span></abbr> module into C code: after a few questions, you
will get a skeleton C code you will have to complete with the logic to
retrieve real objects. A generated file also provides directions on
what to do (with some magic command to have a step-by-step&nbsp;cookbook).</p>
<p>I was able to implement <code>ETHTOOL-MIB</code> by just running it through
<code>mib2c</code>, choosing the table container helper with cache and adding
some code in <code>ethtoolStatTable_data_access.c</code>. You can look at the
<a href="https://github.com/vincentbernat/extend-netsnmp/blob/master/agentx-c-mib2c/" title="Implementation of ETHTOOL-MIB with mib2c">result on Github</a>. Here is a stripped-down
version<sup id="fnref:strip"><a href="#fn:strip" rel="footnote">2</a></sup> of what has been&nbsp;modified:</p>
<div class="codehilite"><pre><span class="cm">/* Socket for ioctl */</span>
<span class="n">skfd</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_DGRAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>

<span class="cm">/* Iterate through all interfaces */</span>
<span class="n">getifaddrs</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ifap</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="n">ifa</span> <span class="o">=</span> <span class="n">ifap</span><span class="p">;</span> <span class="n">ifa</span> <span class="o">!=</span> <span class="nb"><span class="caps">NULL</span></span><span class="p">;</span> <span class="n">ifa</span> <span class="o">=</span> <span class="n">ifa</span><span class="o">-&gt;</span><span class="n">ifa_next</span><span class="p">)</span> <span class="p">{</span>
    <span class="cm">/* Grab statistics name and values */</span>
    <span class="n">strcpy</span><span class="p">(</span><span class="n">ifr</span><span class="p">.</span><span class="n">ifr_name</span><span class="p">,</span> <span class="n">ifa</span><span class="o">-&gt;</span><span class="n">ifa_name</span><span class="p">);</span>
    <span class="n">drvinfo</span><span class="p">.</span><span class="n">cmd</span>         <span class="o">=</span> <span class="n">ETHTOOL_GDRVINFO</span><span class="p">;</span>
    <span class="n">ifr</span><span class="p">.</span><span class="n">ifr_data</span>        <span class="o">=</span> <span class="p">(</span><span class="n">caddr_t</span><span class="p">)</span> <span class="o">&amp;</span><span class="n">drvinfo</span><span class="p">;</span>
    <span class="n">ioctl</span><span class="p">(</span><span class="n">skfd</span><span class="p">,</span> <span class="n"><span class="caps">SIOCETHTOOL</span></span><span class="p">,</span> <span class="o">&amp;</span><span class="n">ifr</span><span class="p">);</span>
    <span class="n">n_stats</span>             <span class="o">=</span> <span class="n">drvinfo</span><span class="p">.</span><span class="n">n_stats</span><span class="p">;</span>
    <span class="n">strings</span><span class="o">-&gt;</span><span class="n">cmd</span>        <span class="o">=</span> <span class="n">ETHTOOL_GSTRINGS</span><span class="p">;</span>
    <span class="n">strings</span><span class="o">-&gt;</span><span class="n">string_set</span> <span class="o">=</span> <span class="n">ETH_SS_STATS</span><span class="p">;</span>
    <span class="n">strings</span><span class="o">-&gt;</span><span class="n">len</span>        <span class="o">=</span> <span class="n">n_stats</span><span class="p">;</span>
    <span class="n">ifr</span><span class="p">.</span><span class="n">ifr_data</span>        <span class="o">=</span> <span class="p">(</span><span class="n">caddr_t</span><span class="p">)</span> <span class="n">strings</span><span class="p">;</span>
    <span class="n">ioctl</span><span class="p">(</span><span class="n">skfd</span><span class="p">,</span> <span class="n"><span class="caps">SIOCETHTOOL</span></span><span class="p">,</span> <span class="o">&amp;</span><span class="n">ifr</span><span class="p">);</span>
    <span class="n">stats</span><span class="o">-&gt;</span><span class="n">cmd</span>          <span class="o">=</span> <span class="n">ETHTOOL_GSTATS</span><span class="p">;</span>
    <span class="n">stats</span><span class="o">-&gt;</span><span class="n">n_stats</span>      <span class="o">=</span> <span class="n">n_stats</span><span class="p">;</span>
    <span class="n">ifr</span><span class="p">.</span><span class="n">ifr_data</span>        <span class="o">=</span> <span class="p">(</span><span class="n">caddr_t</span><span class="p">)</span> <span class="n">stats</span><span class="p">;</span>
    <span class="n">ioctl</span><span class="p">(</span><span class="n">skfd</span><span class="p">,</span> <span class="n"><span class="caps">SIOCETHTOOL</span></span><span class="p">,</span> <span class="o">&amp;</span><span class="n">ifr</span><span class="p">);</span>

    <span class="n">ifIndex</span> <span class="o">=</span> <span class="n">if_nametoindex</span><span class="p">(</span><span class="n">ifa</span><span class="o">-&gt;</span><span class="n">ifa_name</span><span class="p">);</span>

    <span class="cm">/* Iterate through statistics */</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n_stats</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>

        <span class="cm">/* Declare the appropriate index */</span>
        <span class="n">strncpy</span><span class="p">(</span><span class="n">ethtoolStatName</span><span class="p">,</span>
                <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">strings</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">[</span><span class="n">i</span> <span class="o">*</span> <span class="n">ETH_GSTRING_LEN</span><span class="p">],</span>
                <span class="n">ETH_GSTRING_LEN</span><span class="p">);</span>
        <span class="n">ethtoolStatName</span><span class="p">[</span><span class="k">sizeof</span><span class="p">(</span><span class="n">ethtoolStatName</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="sc">&#39;\0&#39;</span><span class="p">;</span>
        <span class="n">ethtoolStatName_len</span> <span class="o">=</span> <span class="n">strlen</span><span class="p">(</span><span class="n">ethtoolStatName</span><span class="p">);</span>

        <span class="cm">/* Append this new variable to the container. */</span>
        <span class="n">rowreq_ctx</span> <span class="o">=</span> <span class="n">ethtoolStatTable_allocate_rowreq_ctx</span><span class="p">();</span>
        <span class="n">ethtoolStatTable_indexes_set</span><span class="p">(</span><span class="n">rowreq_ctx</span><span class="p">,</span>
                    <span class="n">ifIndex</span><span class="p">,</span>
                    <span class="n">ethtoolStatName</span><span class="p">,</span> <span class="n">ethtoolStatName_len</span><span class="p">);</span>
        <span class="n">rowreq_ctx</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">.</span><span class="n">ethtoolStat</span><span class="p">.</span><span class="n">high</span> <span class="o">=</span> <span class="n">stats</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="mi">32</span><span class="p">;</span>
        <span class="n">rowreq_ctx</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">.</span><span class="n">ethtoolStat</span><span class="p">.</span><span class="n">low</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="n">stats</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>

        <span class="n">CONTAINER_INSERT</span><span class="p">(</span><span class="n">container</span><span class="p">,</span> <span class="n">rowreq_ctx</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></div>


<p>See? It is pretty easy. I have only enumerated all the objects I
wanted to expose. I didn&#8217;t even have to convert statistics names to an
<abbr title="Object IDentifier"><span class="caps">OID</span></abbr>, <code>mib2c</code> built a <code>ethtoolStatTable_indexes_set()</code> for this
purpose. OpenHPI project provides an
<a href="http://openhpi.sourceforge.net/subagent-manual/" title="Net-SNMP subagent development manual">extensive documentation to write a sub-agent</a> this&nbsp;way.</p>
<p>Now, on the downside, to implement a <strong>single table</strong>, I have <strong>14
generated files</strong> whose code style is usually unfit to integrate
into an existing project : some people, me included, do not like
automatically generated code, all the more when it is so verbose. The
solution would be to use the new <span class="caps">API</span> without <code>mib2c</code>; unfortunately,
while the <a href="http://www.net-snmp.org/dev/agent/group__handler.html" title="Documentation of Net-SNMP 5.x API">documentation exists</a>, all provided examples
rely exclusively on <code>mib2c</code> tool. Unless you are able to grasp the new
<span class="caps">API</span> without it, I would restrict its use to two&nbsp;cases:</p>
<ul>
<li>Writing a new module for inclusion into Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr>. Since most
   modules are now written with the help of <code>mib2c</code>, there is no
   coding style&nbsp;problem.</li>
<li>Writing a standalone sub-agent for some <abbr title="Management Information Base"><span class="caps">MIB</span></abbr>. As a standalone
   project, you won&#8217;t run into coding style problems&nbsp;either.</li>
</ul>
<p>For other uses, let&#8217;s have a look at the traditional&nbsp;<span class="caps">API</span>.</p>
<h3 id="c-with-traditional-api">C with &#8220;traditional&#8221;&nbsp;<span class="caps">API</span></h3>
<p>The traditional <span class="caps">API</span> is way simpler and even if it is quite old, it is
easier to find associated examples. Here is how to initialize the
agent, again, in a stripped-down version (the
<a href="https://github.com/vincentbernat/ethtool-snmpd" title="Implementation of ETHTOOL-MIB with UCD-SNMP API">complete version is on GitHub</a>):</p>
<div class="codehilite"><pre><span class="k">static</span> <span class="n">oid</span> <span class="n">ethtool_oid</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">39178</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">1</span><span class="p">};</span>
<span class="k">static</span> <span class="k">struct</span> <span class="n">variable3</span> <span class="n">ethtool_vars</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span>
  <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="n">ASN_COUNTER64</span><span class="p">,</span> <span class="n"><span class="caps">RONLY</span></span><span class="p">,</span> <span class="n">ethtool_stat</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">}}</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
  <span class="n">netsnmp_enable_subagent</span><span class="p">();</span>
  <span class="n">snmp_disable_log</span><span class="p">();</span>
  <span class="n">snmp_enable_stderrlog</span><span class="p">();</span>
  <span class="n">init_agent</span><span class="p">(</span><span class="s">&quot;ethtoolAgent&quot;</span><span class="p">);</span>
  <span class="n">REGISTER_MIB</span><span class="p">(</span><span class="s">&quot;ethtoolStatTable&quot;</span><span class="p">,</span> <span class="n">ethtool_vars</span><span class="p">,</span>
               <span class="n">variable3</span><span class="p">,</span> <span class="n">ethtool_oid</span><span class="p">);</span>
  <span class="n">init_snmp</span><span class="p">(</span><span class="s">&quot;ethtoolAgent&quot;</span><span class="p">);</span>
  <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
    <span class="n">agent_check_and_process</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>


<p>The <code>REGISTER_MIB()</code> macro is used to register the provided root <abbr title="Object IDentifier"><span class="caps">OID</span></abbr>
(<code>ethtool_oid</code>) to the master agent. It also registers handlers
associated to various sub-<abbr title="Object IDentifier"><span class="caps">OID</span></abbr> through the <code>ethtool_vars[]</code> array. Each
member of this array features the following&nbsp;fields:</p>
<ul>
<li><code>magic</code> is an integer allowing one to discriminate <abbr title="Object IDentifier"><span class="caps">OID</span></abbr> handled by
   the same handler. For a table, this allows to handle several
   columns with the same handler since they share a common&nbsp;index.</li>
<li><code>type</code> is the type of the variable that will be&nbsp;returned.</li>
<li><code>acl</code> tells if the object is read-only (<code>RONLY</code>) or read-write
   (<code>RWRITE</code>).</li>
<li><code>findVar</code> is the handler associated to the object. Its task will be
   to find the appropriate object and return its&nbsp;value.</li>
<li>The two last fields are the relative <abbr title="Object IDentifier"><span class="caps">OID</span></abbr> this entry is responsible
   for along with its&nbsp;length.</li>
</ul>
<p>The prototype of <code>ethtool_stat()</code> handler function is the&nbsp;following:</p>
<div class="codehilite"><pre><span class="k">static</span> <span class="n">u_char</span><span class="o">*</span>
<span class="n">ethtool_stat</span><span class="p">(</span><span class="k">struct</span> <span class="n">variable</span> <span class="o">*</span><span class="n">vp</span><span class="p">,</span> <span class="n">oid</span> <span class="o">*</span><span class="n">name</span><span class="p">,</span> <span class="kt">size_t</span> <span class="o">*</span><span class="n">length</span><span class="p">,</span>
             <span class="kt">int</span> <span class="n">exact</span><span class="p">,</span> <span class="kt">size_t</span> <span class="o">*</span><span class="n">var_len</span><span class="p">,</span> <span class="n">WriteMethod</span> <span class="o">**</span><span class="n">write_method</span><span class="p">);</span>
</pre></div>


<p>This function should return the value of the requested variable or
<code>NULL</code> if no appropriate object was found. The value can be statically
stored since it will be copied. Here is the description of the&nbsp;arguments:</p>
<ul>
<li><code>struct variable *vp</code> is the structure the handle was associated
   with, except that <code>vp-&gt;name</code> is now a full <abbr title="Object IDentifier"><span class="caps">OID</span></abbr>, not a relative
   one. You can access <code>vp-&gt;magic</code> to determine which column or which
   scalar to handle if this handler is common to several&nbsp;objects.</li>
<li><code>oid *name</code> and <code>size_t *length</code> describe the <abbr title="Object IDentifier"><span class="caps">OID</span></abbr> requested. If you
   want to return another <abbr title="Object IDentifier"><span class="caps">OID</span></abbr> (for a <em><span class="caps">GETNEXT</span></em> request for example), you
   can modify them. <code>name</code> points to an <abbr title="Object IDentifier"><span class="caps">OID</span></abbr> array large enough to fit
   any <abbr title="Object IDentifier"><span class="caps">OID</span></abbr> you want to&nbsp;return.</li>
<li><code>int exact</code> tells if the requested <abbr title="Object IDentifier"><span class="caps">OID</span></abbr> should be exactly matched
   (case of <em><span class="caps">GET</span></em> or <em><span class="caps">SET</span></em>) or not (<em><span class="caps">GETNEXT</span></em>).</li>
<li><code>size_t *var_len</code> is used to tell the size of the returned&nbsp;object.</li>
<li><code>WriteMethod **write_method</code> is only used if the variable is
   modifiable. When a <em><span class="caps">SET</span></em> request is received, the <span class="caps">API</span> will call the
   handler with <code>exact</code> set to 1 and expects to get a pointer to the
   function that will handle the write operation<sup id="fnref:write"><a href="#fn:write" rel="footnote">3</a></sup>.</li>
</ul>
<p>To implement this function, you are on your own. When relying on
externally fetched data, you need to handle a cache yourself. I have
used a red-black tree for this purpose (with code stolen from
OpenBSD). This also enables an easy implementation of the <em><span class="caps">GETNEXT</span></em>&nbsp;operation.</p>
<p>Here are three projects using this <span class="caps">API</span> to provide <abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr>&nbsp;support:</p>
<ul>
<li><a href="http://www.keepalived.org/" title="Keepalived: healthchecking for LVS and high-availability">Keepalived</a> is a <span class="caps">VRRP</span> daemon and a monitoring daemon
   for <span class="caps">LVS</span> clusters. I have
   <a href="/en/blog/2011-keepalived-snmp-ipv6.html" title="SNMP support for Keepalived">added a complete <abbr title="Simple Network Management Protocol"><abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr></abbr> support</a>. The most
   interesting files are <a href="https://github.com/vincentbernat/keepalived/blob/snmp-1.2.0/keepalived/core/snmp.c" title="SNMP support for Keepalived: core/snmp.c">core/snmp.c</a>,
   <a href="https://github.com/vincentbernat/keepalived/blob/snmp-1.2.0/keepalived/check/check_snmp.c" title="SNMP support for Keepalived: check/check_snmp.c">check/check_snmp.c</a> and
   <a href="https://github.com/vincentbernat/keepalived/blob/snmp-1.2.0/keepalived/vrrp/vrrp_snmp.c" title="SNMP support for Keepalived: vrrp/vrrp_snmp.c">vrrp/vrrp_snmp.c</a>. It features a tight
   integration into Keepalived event loop that should be reusable by
   other projects. It includes read-only support of all data
   structures (configuration, state and statistics), ability to send
   traps on events and a write support for some&nbsp;values.</li>
<li><a href="https://github.com/vincentbernat/lldpd/wiki" title="lldpd, implementation of IEEE 802.1ab (LLDP)">lldpd</a> is an implementation of 802.<span class="caps">1AB</span> (<span class="caps">LLDP</span>) which is a
   protocol allowing an equipment to advertise itself to its neighbors
   on Ethernet level. 802.<span class="caps">1AB</span> comes with a huge <abbr title="Management Information Base"><span class="caps">MIB</span></abbr> module and many
   extensions. <em>lldpd</em> provides a fairly complete read-only
   implementation of this <abbr title="Management Information Base"><span class="caps">MIB</span></abbr> module. Some tables have complex
   indexes. Have a look at <a href="https://github.com/vincentbernat/lldpd/blob/master/src/agent.c" title="lldpd, SNMP support: agent.c">agent.c</a>. There is currently
   no write support and no traps but <em>lldpd</em> features privilege
   separation and some code allows it to still use an Unix socket to
   speak with the master&nbsp;agent.</li>
<li><a href="http://www.asterisk.org/" title="Asterisk, Open Source Private Branch Exchange">Asterisk</a>, an open source <abbr title="Private Branch Exchange"><span class="caps">PBX</span></abbr>, includes an AgentX
   sub-agent allowing one to grab some metrics. Look at
   <a href="http://svnview.digium.com/svn/asterisk/trunk/res/snmp/agent.c?revision=352957&amp;view=markup" title="SNMP support for Asterisk, agent.c">res/snmp/agent.c</a>.</li>
</ul>
<p><strong><span class="caps">UPDATED</span>:</strong> If it is critical for your project to <em>not</em> block, you
should be aware that using NetSNMP implementation of AgentX has some
issues. Have a look at my <a href="/en/blog/2012-fixing-async-agentx.html" title="Asynchronicity &amp; Net-SNMP AgentX protocol">other post on this topic</a>.</p>
<h2 id="other-solutions">Other&nbsp;solutions</h2>
<p>The manual page for <a href="http://linux.die.net/man/5/snmpd.conf" title="Manual page of snmpd.conf">snmpd.conf</a> explores other ways to
extend Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> agent under the section &#8220;<em>Extending agent
functionality</em>&#8220;:</p>
<ul>
<li><code>exec</code> and <code>sh</code> are deprecated. Use <code>extend</code> instead.</li>
<li><code>pass</code> is a bit simpler than <code>pass_persist</code>. The command is run
   once for each request. Such a command can easily be turned into a
   <code>pass_persist</code> script. Moreover, Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> will not answer any
   request while a <code>pass</code> command is&nbsp;running.</li>
<li><code>proxy</code> redirects requests to another <abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> agent. Unless you have
   some code that can only act as a complete <abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> agent, it is better
   to use AgentX instead. For programs using Net-<abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr> <span class="caps">API</span>, turning an
   agent into an AgentX sub-agent is just one line of code. Since a
   sub-agent involves less code than a complete agent, it is more
   efficient and more&nbsp;reliable.</li>
<li><code>smux</code> has been superseeded by&nbsp;AgentX.</li>
<li><code>perl</code> and <code>dlmod</code> allow one to load and execute external code
   inside the running agent. Unless you have important performance
   requirements, it is better to use a sub-agent instead: if some bug
   happens, only the sub-agent will be affected, not the master
   agent. A sub-agent sticks more closely to the Unix philosophy:
   &#8220;write programs that do one thing and do it well&#8221;. However,
   <a href="http://www.net-snmp.org/docs/FAQ.html#What_is_the_purpose_of__dlmod__" title="Net-SNMP FAQ about dlmod">Net-<abbr title="Simple Network Management Protocol"><abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr></abbr> <span class="caps">FAQ</span></a>&nbsp;says:</li>
</ul>
<blockquote>
<p>Implementing the module in C within the main agent (directly or via
<code>dlmod</code>) is probably the most efficient and reliable, closely followed
by embedded perl (or python) extensions.  These have the advantage
of minimal overheads between the code implementing the <abbr title="Management Information Base"><span class="caps">MIB</span></abbr> module,
and the agent framework, and no inter-process communication&nbsp;issues.</p>
</blockquote>
<div class="footnote">
<hr>
<ol>
<li id="fn:snmpconf">
<p>Additional arguments for <code>snmp*</code> are usually required to
         specify a version and a community (for SNMPv1 and
         SNMPv2c) or a user (for SNMPv3). In all examples, I do
         not specify anything. I assume that <code>~/.snmp/snmp.conf</code>
         contains the appropriate bits. Moreover, some outputs are
         truncated.&#160;<a href="#fnref:snmpconf" rev="footnote" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
<li id="fn:strip">
<p>No allocations, no variable declarations and no error
      checkings. Do not do this at home!&#160;<a href="#fnref:strip" rev="footnote" title="Jump back to footnote 2 in the text">&#8617;</a></p>
</li>
<li id="fn:write">
<p>If you want to look at an example of how to handle a <em><span class="caps">SET</span></em>
      request, look at the
    <br>
<a href="https://github.com/vincentbernat/keepalived/blob/snmp-1.2.0/keepalived/vrrp/vrrp_snmp.c" title="SNMP support for Keepalived: vrrp/vrrp_snmp.c"><abbr title="Simple Network Management Protocol"><abbr title="Simple Network Management Protocol"><abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr></abbr></abbr> support for Keepalived</a>. A <em><span class="caps">SET</span></em>
      operation is more complex because <abbr title="Simple Network Management Protocol"><abbr title="Simple Network Management Protocol"><abbr title="Simple Network Management Protocol"><span class="caps">SNMP</span></abbr></abbr></abbr> ensures that the
    <br>
<em><span class="caps">SET</span></em> operation is atomic across all provided variables. It
      uses a three-staged commit. The traditional <span class="caps">API</span> is very
      inefficient for this kind of operation because the object
      has to be located again for each step.&#160;<a href="#fnref:write" rev="footnote" title="Jump back to footnote 3 in the text">&#8617;</a></p>
</li>
</ol>
</div>
]]>
            </content>
        </entry>
                <entry>
            <title type="html">Tuning Linux IPv4 route cache</title>
            <author><name>Vincent Bernat</name></author>
            <link href="http://vincent.bernat.im/en/blog/2011-ipv4-route-cache-linux.html"/>
            <updated>2011-12-13T19:12:45+01:00</updated>
            <id>http://www.luffy.cx/en/blog/2011-ipv4-route-cache-linux.html</id>

            <content type="html">
<![CDATA[
<p>The route cache is a Linux kernel component enabling route lookups to
be faster by caching the results in some table and checking it before
issuing a regular lookup in the route tables. When using Linux as a
router, the inefficiency of the route cache can hinder the
performances of your&nbsp;box.</p>
<p>The documentation on this component is scarce and it is difficult to
find up-to-date bits on how the route cache works and how to tune
it. The book <em><a href="http://shop.oreilly.com/product/9780596002558.do" title="Understanding Linux Network Internals">Understanding Linux Network Internals</a></em>
from O&#8217;Reilly is an exception and contains valuable information on how
the route cache works. Even if the book is targeted at 2.6.12, the
part on the route cache is still quite accurate. Unfortunately, it
fails to provide appropriate tips on how to monitor and tune the route&nbsp;cache.</p>
<p>I hope to provide here a concise view of the route cache, as it is
implemented in <strong>Linux 3.1</strong><sup id="fnref:valid"><a href="#fn:valid" rel="footnote">1</a></sup>. It is protocol-dependent<sup id="fnref:dst"><a href="#fn:dst" rel="footnote">2</a></sup>
and I will cover only the <strong>IPv4</strong> version&nbsp;here.</p>
<div class="toc">
<ul>
<li><a href="#overview-of-the-route-cache-subsystem">Overview of the route cache subsystem</a><ul>
<li><a href="#available-knobs">Available&nbsp;knobs</a></li>
<li><a href="#statistics-monitoring">Statistics <span class="amp">&amp;</span>&nbsp;monitoring</a></li>
<li><a href="#tuning">Tuning</a></li>
</ul>
</li>
<li><a href="#in-depth-look-into-the-garbage-collector">In-depth look into the garbage collector</a><ul>
<li><a href="#setting-a-goal">Setting a&nbsp;goal</a></li>
<li><a href="#meeting-the-goal">Meeting the&nbsp;goal</a></li>
</ul>
</li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
</div>
<h1 id="overview-of-the-route-cache-subsystem">Overview of the route cache&nbsp;subsystem</h1>
<p>To handle an incoming or outgoing <span class="caps">IP</span> datagram, the kernel needs to
issue a lookup in the route tables. While it seems to be quite
trivial, several questions need to be&nbsp;answered:</p>
<ul>
<li>Does the source address and the destination address appear to be&nbsp;valid?</li>
<li>Is the source address a martian address<sup id="fnref:martian"><a href="#fn:martian" rel="footnote">3</a></sup>?</li>
<li>Is the destination address mine or should I forward the&nbsp;packet?</li>
<li>Which route table should I&nbsp;use?</li>
<li>Does the destination address match this route? And this&nbsp;one?</li>
<li>Can I currently contact the gateway that I should&nbsp;use?</li>
</ul>
<p>Those checks can be a bit time consuming, even for small route
tables. To avoid them for each packets, Linux maintains a <em>route
cache</em> which is queried before doing a regular lookup and updated
after each one. You can dump it with <code>ip -s route show cache</code>:</p>
<div class="codehilite"><pre><span class="gp">$</span> ip -s route show cache
<span class="go">198.51.100.7 from 203.0.113.2 via 192.0.2.1 dev eth1</span>
<span class="go">  cache used 7 age 2sec ipid 0x1fce rtt 131ms rttvar 45ms cwnd 10</span>
<span class="go">198.51.100.17 from 203.0.113.15 via 192.0.2.1 dev eth1</span>
<span class="go">  cache used 3 age 0sec ipid 0xc3bd</span>
<span class="go">local 192.0.2.18 from 203.0.113.15 dev lo src 192.0.2.18</span>
<span class="go">  cache &lt;local&gt; used 154 age 1sec iif eth0</span>
</pre></div>


<p>Here are two&nbsp;examples:</p>
<ul>
<li>If Linux receives a packet from <strong>198.51.100.17</strong> to
   <strong>203.0.113.15</strong>, it will find this flow in the route
   cache. Therefore, it already knows that it should forward the packet
   to 192.0.2.1. No checks&nbsp;needed.</li>
<li>If it receives a packet from <strong>198.51.100.16</strong> to <strong>203.0.113.15</strong>,
   there is no appropriate entry in the route cache and therefore,
   the system will have to look at the route tables. It is likely to
   use the exact same entry than if the source was 198.51.100.17 but
   maybe there is some policy routing requesting the use of a special
   route table or 198.51.100.16 is a local address and the packet
   will therefore be classified as <em>martian</em>.</li>
</ul>
<p>The schema below shows how this cache is implemented<sup id="fnref:src"><a href="#fn:src" rel="footnote">4</a></sup>. It uses a
separate <a href="http://en.wikipedia.org/wiki/Hash_table" title="Hash table on Wikipedia">hash table</a> (<span class="caps">BSD</span> systems keep the cache in the routing
table). Each bucket is a chained list of route cache&nbsp;entries.</p>
<p><img alt="Schema of the route cache hash table" src="//d1g3mdmxf8zbo9.cloudfront.net/images/linux/routing-cache.png" title="Partial view of the route cache hash table with three cached entries"></p>
<p>Once an entry has been added to the route cache, there are several
ways to remove it. Most entries are removed by the
<a href="http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)" title="Garbage collector on Wikipedia">garbage collector</a> which will scan the route cache and remove
invalid and older entries. It will be triggered when the route cache
is full or at regular interval, once a certain threshold has been&nbsp;met.</p>
<h2 id="available-knobs">Available&nbsp;knobs</h2>
<p>There are several values you can tune. Most of them are available in
<code>sysctl</code>.</p>
<ul>
<li><code>rhash_entries</code> is the <strong>size of the hash table</strong><sup id="fnref:size"><a href="#fn:size" rel="footnote">5</a></sup>. If you
   don&#8217;t specify it on the kernel command line, it is computed
   dynamically based on the memory available on your system. You can
   view its value by looking at something like <code>IP route cache hash
   table entries: 262144 (order: 9, 2097152 bytes)</code> in the kernel&nbsp;logs.</li>
<li><code>net.ipv4.route.max_size</code> is the <strong>maximum number of entries</strong> in
   the route cache. Except under exceptional circumstances, this value
   is never&nbsp;exceeded.</li>
<li><code>net.ipv4.route.gc_elasticity</code> is the target <strong>average length of a
   chain</strong> in the route cache. The garbage collector will work harder
   if this value is exceeded. This means that if you multiply this
   value by the value of <code>rhash_entries</code>, you will get the target
   average number of entries in the route&nbsp;cache.</li>
<li><code>net.ipv4.route.gc_min_interval_ms</code> is the <strong>minimum delay between
   two runs of the garbage collector</strong>, except when the cache is
   full. The default value should be&nbsp;fine.</li>
<li><code>net.ipv4.route.gc_thresh</code> is a <strong>threshold triggering the garbage
   collector</strong> every <code>net.ipv4.route.gc_min_interval_ms</code> milliseconds.</li>
<li><code>net.ipv4.route.gc_timeout</code> is the base value to determine if an
   <strong>entry is old enough to be removed</strong> or not. Whatever its value,
   the garbage collector will attempt to remove the same number of
   entries. However, this value could potentially influence its
   efficiency. See below for more details on&nbsp;this.</li>
</ul>
<p>You may find documentation about those obsolete <em>sysctl</em>&nbsp;values:</p>
<ul>
<li><code>net.ipv4.route.secret_interval</code> has been
   <a href="https://github.com/torvalds/linux/commit/3ee943728fff536edaf8f59faa58aaa1aa7366e3" title="Linux commit removing secret_interval timer">removed in Linux 2.6.35</a>; it was used to trigger an
   asynchronous flush at fixed interval to avoid to fill the&nbsp;cache.</li>
<li><code>net.ipv4.route.gc_interval</code> has been
   <a href="https://github.com/torvalds/linux/commit/349d2895cc8b7db1f5be677cd685209a3805d2ed" title="Linux commit removing gc_interval sysctl">removed in Linux 2.6.38</a>. It is still present until
   Linux 3.2 but has no effect. It was used to trigger an asynchronous
   cleanup of the route cache. The garbage collector is now considered
   efficient enough for the&nbsp;job.</li>
</ul>
<p><strong><span class="caps">UPDATED</span>:</strong> <code>net.ipv4.route.gc_interval</code>
<a href="https://github.com/torvalds/linux/commit/9f28a2fc0bd77511f649c0a788c7bf9a5fd04edb" title="Linux commit adding back gc_interval sysctl">is back for Linux 3.2</a>. It is still needed to avoid
exhausting the neighbour cache because it allows to cleanup the cache
periodically and not only above a given threshold. Keep it to its
default value of&nbsp;60.</p>
<h2 id="statistics-monitoring">Statistics <span class="amp">&amp;</span>&nbsp;monitoring</h2>
<p>Linux maintains some statistics about the use of the route
cache. You can find them in <code>/proc/net/stat/rt_cache</code>. The command
<code>lnstat</code> can print them nicely for&nbsp;you:</p>
<div class="codehilite"><pre><span class="gp">$</span> lnstat -s1 -i1 -c-1 -f rt_cache
<span class="go">rt_cache|rt_cache|rt_cache|rt_cache|rt_cache|rt_cache|rt_cache|rt_cache|rt_cache|rt_cache|rt_cache|rt_cache|rt_cache|rt_cache|rt_cache|rt_cache|rt_cache|</span>
<span class="go"> entries|  in_hit|in_slow_|in_slow_|in_no_ro|  in_brd|in_marti|in_marti| out_hit|out_slow|out_slow|gc_total|gc_ignor|gc_goal_|gc_dst_o|in_hlist|out_hlis|</span>
<span class="go">        |        |     tot|      mc|     ute|        |  an_dst|  an_src|        |    _tot|     _mc|        |      ed|    miss| verflow| _search|t_search|</span>
<span class="go"> 3096848|   42309|     686|       0|       0|       0|       0|       0|       3|       0|       0|     674|     672|       0|       0|   27644|       8|</span>
<span class="go"> 3096984|   41405|     636|       0|       0|       0|       0|       0|       3|       0|       0|     623|     621|       0|       0|   28189|       8|</span>
<span class="go"> 3097160|   42483|     700|       0|       0|       0|       0|       0|       5|       0|       0|     694|     692|       0|       0|   29506|      12|</span>
</pre></div>


<p>Except for the first column, <code>lnstat</code> outputs values in units per
second. Let&#8217;s review some of those&nbsp;values:</p>
<ul>
<li><code>rt_cache_entries</code> is the number of entries in the route cache. You
   should compare it with <code>net.ipv4.route.max_size</code> and ensure that
   the <strong>cache is never full</strong> to avoid triggering the garbage
   collector too&nbsp;often.</li>
<li><code>rt_cache_in_hit</code> and <code>rt_cache_out_hit</code> are the number of regular
   lookups avoided because the result was found in the cache for
   incoming and outgoing packets, respectively. When the system is a
   router, most lookups only happen on the incoming side. You should
   compare this value with <code>rt_cache_in_slow_tot</code> and
   <code>rt_cache_in_out_slow_tot</code> which are the number of lookups in the
   route tables. On this system, the <strong>efficiency</strong> of the route cache
   is more than 98% which is quite&nbsp;good.</li>
<li><code>rt_cache_gc_total</code> is how often the garbage collector was
   requested to be triggered while <code>rt_cache_gc_ignored</code> corresponds
   to how often it was finally not run because it has already been
   triggered shortly beforehand (less than
   <code>net.ipv4.route.gc_min_interval_ms</code> milliseconds). The difference
   between those two values should be very small to ensure that the
   garbage collector does not run more a handful of times per&nbsp;second.</li>
<li><code>rt_cache_gc_goal_miss</code> is how often the garbage collector was not
   able to fulfill its goal. This value should rarely be different of&nbsp;0.</li>
<li><code>rt_cache_gc_dst_overflow</code> is how often the route cache is bigger
   than the allowed maximum size. This should never happen except
   when you try to shrink the&nbsp;cache.</li>
<li><code>rt_cache_in_hlist_search</code> and <code>rt_cache_out_hlist_search</code> is how
   often a lookup in the cache had to look at the next entry in the
   chain for the computed bucket: each time Linux has to follow the
   <code>next</code> pointer in a cache entry, it increments one of those
   counters. It is a clue on the average length of chains in the route
   cache hash table. Compare those values with the number of cache
   lookups (hit and&nbsp;miss).</li>
</ul>
<p>As an illustration, here is a plot of the various statistics exposed
above for a router whose route cache receives about 1000 routes par&nbsp;second:</p>
<p><img alt="Plot of various statistics for the route cache" src="//d1g3mdmxf8zbo9.cloudfront.net/images/linux/routing-cache-stats.png" title="Various statistics about the route cache"></p>
<p><code>rhash_entries</code> is 1,048,576, as is
<code>net.ipv4.route.gc_thresh</code>. Therefore, the garbage collector was
requested to be run when the number of entries goes above this
level. Because the cache is not full, it is only really run twice per
seconds (the value of <code>net.ipv4.route.gc_interval_ms</code> is
500). <code>net.ipv4.route.gc_elasticity</code> is set to 3. This explains why
the garbage collector is aggressive when the number of entries reached&nbsp;3,145,728.</p>
<p>As you can see, the efficiency is near 100% all the time. The
percentage of collisions is <code>rt_cache_in_hlist_search</code> ratio to the
sum of <code>rt_cache_in_hit</code> and <code>rt_cache_in_slow_tot</code>.</p>
<p><strong><span class="caps">UPDATED</span>:</strong> The plot above was with a 2.6.39 kernel. For a kernel
between 2.6.35 and 2.6.37 (included) or a 3.2 kernel or more recent,
the cleanup triggered every <code>net.ipv4.route.gc_interval</code> seconds will
expire up to <code>rhash_entries</code> entries. If the pace at which routes are
added to the cache is less than this rate, the number of entries may
stop climbing, even when <code>net.ipv4.route.gc_threshold</code> is not met. For
example, here are the same statistics with a 2.6.35 kernel for a
router with about 2,500 new entries per second but with
<code>net.ipv4.route.gc_interval</code> enabled; the threshold of 1,048,576 is
never&nbsp;met:</p>
<p><img alt="Plot of various statistics for the route cache with gc_interval" src="//d1g3mdmxf8zbo9.cloudfront.net/images/linux/routing-cache-gc-interval.png" title="Various statistics about the route cache with gc_interval set to 60"></p>
<h2 id="tuning">Tuning</h2>
<p>Do you need to modify any of those values? You have two questions to
ask&nbsp;yourself:</p>
<ol>
<li>How much efficiency do you want to get from the route&nbsp;cache?</li>
<li>How much memory do you want to dedicate to the route&nbsp;cache?</li>
</ol>
<p>As a rule of thumb, two millions entries eat about 500 <span class="caps">MB</span> of memory on
a 64bit system. You should be able to compute the average memory usage
and the maximum memory usage from the values of
<code>net.ipv4.route.max_size</code>, <code>rhash_entries</code> and
<code>net.ipv4.route.gc_elasticity</code>. For example, if the route cache hash
table has 262,144 buckets, the maximum allowed number of entries in
the cache is 4,194,304 and <code>net.ipv4.route.gc_elasticity</code> is set to 8,
the memory usage will be 500 <span class="caps">MB</span> on average and 1 <span class="caps">GB</span> max. If this is
too much, you will need to lower some&nbsp;values.</p>
<p>Look at the previous section to compute the current efficiency of your
route cache. It should be above 90%. If you are dissatisfied with
that, you could increase the cache&nbsp;size.</p>
<p>If you want to double the number of entries, double
<code>net.ipv4.route.max_size</code>, <code>net.ipv4.route.gc_thresh</code> and
<code>rhash_entries</code> but keep <code>net.ipv4.route.gc_elasticity</code> to&nbsp;8.</p>
<p>For the garbage collector to be efficient, the route cache should not
be filled too fast. The garbage collector should be able to cope with
this situation but this may impact performance because it needs to
walk several times the route cache to find entries to expire. Watching
<code>gc_goal_miss</code> may give you a hint about this: if this value starts to
be different of 0, lower <code>net.ipv4.route.gc_timeout</code>.</p>
<p><strong><span class="caps">UPDATED</span>:</strong> For a kernel where <code>net.ipv4.route.gc_interval</code> matters,
things become more complicated. Because the cleanup algorithm will
expire entries at a regular interval, the average number of entries
may stay low unless the number of new entries per second is high
enough. Therefore, the average number of entries may be lower than the
theoretical value computed above. Monitoring the appropriate metrics
is the key to a good tuning. If you feel that entries are expired too
fast, you may want to double <code>net.ipv4.route.gc_timeout</code>.</p>
<h1 id="in-depth-look-into-the-garbage-collector">In-depth look into the garbage&nbsp;collector</h1>
<p>Those different pieces of advice may have puzzled you. We need to
understand how the garbage collector works to better cope with
them. The garbage collector is triggered when a new entry needs to be
added to the cache and the number of entries is superior to
<code>net.ipv4.route.gc_thresh</code>. It is implemented in
<a href="https://github.com/torvalds/linux/blob/v3.1/net/ipv4/route.c#L880-L998" title="rt_garbage_collect() in Linux 3.1"><code>rt_garbage_collect()</code> function</a>. It will do
nothing if it has been called less than
<code>net.ipv4.route.gc_interval_ms</code> milliseconds and the cache is not full
(more than <code>net.ipv4.route.max_size</code> entries).</p>
<h2 id="setting-a-goal">Setting a&nbsp;goal</h2>
<p>The garbage collector will first assess the situation. It will look how
the number of entries currently in the cache compares to the product
of <code>rhash_entries</code> and <code>net.ipv4.route.gc_elasticity</code>:</p>
<ol>
<li>Above this limit, it will try to remove at least
    <code>rhash_entries</code> entries.</li>
<li>Otherwise, it will try to remove no more than half the&nbsp;difference.</li>
</ol>
<p>If you look at the previous plot, you can easily see the difference
when the garbage collector is not aggressive (above 1,048,576 entries
but below 3,145,728) and when it is (above 3,145,728 entries). If we
assume the garbage collector is able to meet its goal, we can easily
<a href="https://gist.github.com/1460108" title="Simulation of rt_garbage_collect()">simulate its algorithm</a>:</p>
<p><img alt="Plot showing influence of various kernel parameters" src="//d1g3mdmxf8zbo9.cloudfront.net/images/linux/routing-cache-exp.png" title="Variations of various cache parameters and their effects"></p>
<p>The first plot shows what would happen if about 2000 routes are added
per second with <code>rhash_entries</code> equal to 262,144 and
<code>net.ipv4.route.gc_elasticity</code> set to 8. When
<code>net.ipv4.route.gc_threshold</code> is met, the garbage collector has almost
no effect. However, when the number of entries reaches 2,097,152, the
garbage collector sets its goal to 262,144. From this point, the number
of entries oscillates around 2 millions&nbsp;entries.</p>
<p>On the second plot, <code>rhash_entries</code> is now equal to 1,048,576 but
<code>net.ipv4.route.gc_elasticity</code> has been set to 2. Therefore, the
aggressive part of the garbage collectors kicks at the same threshold
than for the previous plot. However, its goal is now four times larger
and the oscillations have a larger amplitude. The fact that the
aggressive part of the garbage collector kicks less often is nullified
by the fact that it needs to remove more entries each time. Because of
the slight impact on cache efficiency, it seems better to keep
<code>net.ipv4.route.gc_elasticity</code> around 8, or 4 if we want to keep
shorter chains (but there seems to be no improvement to do&nbsp;so).</p>
<p>The other plots show what happens when there is a sudden surge in the
number of routes added or when there is a&nbsp;pause.</p>
<h2 id="meeting-the-goal">Meeting the&nbsp;goal</h2>
<p>Now that we understand how <code>rhash_entries</code>,
<code>net.ipv4.route.gc_elasticity</code> and <code>net.ipv4.route.gc_threshold</code>
interact, let&#8217;s look at <code>net.ipv4.route.gc_timeout</code>. Once the garbage
collector has set its goal and if it is positive, it needs to choose
which entries to remove from the&nbsp;cache.</p>
<p>It walks the hash table from the position of its last run and remove
entries until its goal is met. If the entry is not current anymore
(for example, the network interface associated to it has changed its
<span class="caps">IP</span> configuration), it is removed. Otherwise, the system looks at the
age of the entry and its position in the chain. If the entry is the
first in the chain, it is kept only if its age is below
<code>net.ipv4.route.gc_timeout</code>. If it is second, it is kept only if its
age is below half of <code>net.ipv4.route.gc_timeout</code>. If it is third, the
threshold is a quarter of <code>net.ipv4.route.gc_timeout</code>, and so on. The
garbage collector will favor short&nbsp;chains.</p>
<p>If after a full run of the hash table, the garbage collector was not
able to meet its goal, it will start again but will behave more
aggressively, as if <code>net.ipv4.route.gc_timeout</code> is set to half of its
value. It will do as many passes as necessary until its goal is met or
until there is no way to remove any entry (or until it has spent too
much time). Once the garbage collector has switched to this more
aggressive behavior, it will keep being aggressive for a few cycles
(a bit less for each&nbsp;cycle).</p>
<p>With a very large value of <code>net.ipv4.route.gc_timeout</code>, the garbage
collector will have a hard time to find entries to expire. It will
need to do several passes until it is able to expire some entries. On
the other hand, if you choose a very small value, the garbage
collector may remove entries that were just added, even if there are
older entries further in the hash&nbsp;table.</p>
<p>For a more in-depth coverage of how the route cache works, look at
chapter 33 of
<em><a href="http://shop.oreilly.com/product/9780596002558.do" title="Understanding Linux Network Internals">Understanding Linux Network Internals</a></em>. Just be
aware that multipath route caching has been removed (and was never
really used) and asynchronous cleanup (<code>rt_periodic_timer</code>) does not
exist&nbsp;anymore.</p>
<p><strong><span class="caps">UPDATED</span>:</strong> As stated earlier, <code>net.ipv4.route.gc_interval</code> has been
<a href="https://github.com/torvalds/linux/commit/9f28a2fc0bd77511f649c0a788c7bf9a5fd04edb" title="Linux commit adding back gc_interval sysctl">reinstantiated in Linux 3.2</a>. The cleanup is a bit
different of what is done by the garbage collector but have some
similarities. It is run every <code>net.ipv4.route.gc_interval</code> seconds
(even when there is less than <code>net.ipv4.route.gc_threshold</code>
entries). It will set a goal proportional to
<code>net.ipv4.route.gc_interval</code> and inversely proportional to
<code>net.ipv4.route.gc_timeout</code>. It cannot be greater than
<code>rhash_entries</code>. If <code>net.ipv4.route.gc_interval</code> and
<code>net.ipv4.route.gc_timeout</code> are equal, the goal is exactly
<code>rhash_entries</code>. It represents the number of entries the cleanup
procedure will look at (and <em>not</em> the number of entries it will try to
expire). If an entry is not valid anymore or is old enough to be
removed (with the same criteria as for the garbage collector), it will
be removed. Another important thing about this cleanup algorithm is
that it will modify the maximum allowed length of a chain to the
average length it has observed plus four times the standard deviation
with a maximum equal to <code>net.ipv4.route.gc_elasticity</code>. Without this
algorithm, the maximum allowed length is 20. When inserting a new
entry, if a chain with more than <code>net.ipv4.route.gc_elasticity</code>
entries is selected, the kernel will try to remove an element before
inserting a new one. Then, if the chain is still longer than the
maximum allowed length (longer than what is allowed by
<code>net.ipv4.route.gc_elasticity</code> or too long compared to other
chains<sup id="fnref:attack"><a href="#fn:attack" rel="footnote">6</a></sup>), all cache entries for the current interface are&nbsp;invalidated.</p>
<h1 id="conclusion">Conclusion</h1>
<p>When tuning the route cache, <code>rhash_entries</code>,
<code>net.ipv4.route.gc_elasticity</code>, <code>net.ipv4.route.max_size</code> and
<code>net.ipv4.route.gc_threshold</code> are related and should not be modified
independently. <code>net.ipv4.route.gc_thresh</code> should be below the product
of <code>net.ipv4.route.gc_elasticity</code> and <code>rhash_entries</code> while
<code>net.ipv4.route.max_size</code> should be above this&nbsp;value.</p>
<p>Linux exposes several interesting metrics related to the route
cache. Monitoring them allows one to watch the efficiency of the
route cache and may uncover some anomalies (garbage collector
running too often, difficulty to remove routes from the cache,&nbsp;&#8230;).</p>
<p>The route cache subsystem still evolves and some old behaviors have
been dismissed. The best documentation is, unfortunately, still the
code and other documentations tend to become obsolete. The IPv6
route cache is quite different of the one presented here. Don&#8217;t
blindly apply the same tuning for&nbsp;IPv6.</p>
<div class="footnote">
<hr>
<ol>
<li id="fn:valid">
<p>The content of this article should be valid for Linux
      2.6.38, 2.6.39, 3.0 and 3.1. There are some clues for Linux
      2.6.35, 2.6.36 and 2.6.37 as well as for Linux 3.2. For
      other versions, you are on your own.&#160;<a href="#fnref:valid" rev="footnote" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
<li id="fn:dst">
<p>Linux provides a protocol-independent destination cache
    subsystem (<span class="caps">DST</span>). This component is not a generic cache layer
    and only enables loose coupling with external subsystems.&#160;<a href="#fnref:dst" rev="footnote" title="Jump back to footnote 2 in the text">&#8617;</a></p>
</li>
<li id="fn:martian">
<p>Martian addresses are addresses that cannot be used as a
        source address, either because they are reserved for
        special-use (like a multicast address) or because of the
        use of <em>reverse path filtering</em> which checks if a packet
        received on one interface would be answered on the same
        interface, as defined in <a href="http://tools.ietf.org/html/rfc3704" title="RFC 3704: Ingress Filtering for Multihomed Networks"><span class="caps">RFC</span> 3704</a>. This feature
        is enabled by setting <code>rp_filter</code> in Linux.&#160;<a href="#fnref:martian" rev="footnote" title="Jump back to footnote 3 in the text">&#8617;</a></p>
</li>
<li id="fn:src">
<p>For more details, you may want to look at <code>include/net/dst.h</code>,
  <br>
<code>include/net/route.h</code> and <code>net/ipv4/route.c</code>.&#160;<a href="#fnref:src" rev="footnote" title="Jump back to footnote 4 in the text">&#8617;</a></p>
</li>
<li id="fn:size">
<p>In fact, the size of the hash table is always a power of
     two. If specified, <code>rhash_entries</code> is rounded to the next
     power of two and, internally, is stored as <code>rt_hash_mask +
     1</code>.&#160;<a href="#fnref:size" rev="footnote" title="Jump back to footnote 5 in the text">&#8617;</a></p>
</li>
<li id="fn:attack">
<p>This allows the kernel to guard against collision attacks.&#160;<a href="#fnref:attack" rev="footnote" title="Jump back to footnote 6 in the text">&#8617;</a></p>
</li>
</ol>
</div>
]]>
            </content>
        </entry>
                <entry>
            <title type="html">SSL/TLS &amp; Perfect Forward Secrecy</title>
            <author><name>Vincent Bernat</name></author>
            <link href="http://vincent.bernat.im/en/blog/2011-ssl-perfect-forward-secrecy.html"/>
            <updated>2011-11-28T22:49:49+01:00</updated>
            <id>http://www.luffy.cx/en/blog/2011-ssl-perfect-forward-secrecy.html</id>

            <content type="html">
<![CDATA[
<p>Once the private key of some <span class="caps">HTTPS</span> web site is compromised, an
attacker is able to build a <a href="http://en.wikipedia.org/wiki/Man-in-the-middle_attack" title="Man-in-the-middle attack on Wikipedia">man-in-the-middle attack</a> to
intercept and decrypt any communication with the web site. The first
step against such an attack is the revocation of the associated
certificate through a <abbr title="Certificate Revocation List"><span class="caps">CRL</span></abbr> or a protocol like <abbr title="Online Certificate Status Protocol"><span class="caps">OCSP</span></abbr>. Unfortunately, the
attacker could also have recorded past communications protected by
this private key and therefore decrypt&nbsp;them.</p>
<p><em>Forward secrecy</em> allows today information to be kept secret even if
the private key is compromised in the future. Achieving this property
is usually costly and therefore, most web servers do not enable it on
purpose. Google recently
<a href="http://googleonlinesecurity.blogspot.com/2011/11/protecting-data-for-long-term-with.html" title="Protecting data for the long term with forward secrecy">announced support of forward secrecy</a> on their <span class="caps">HTTPS</span>
sites. Adam Langley
<a href="http://www.imperialviolet.org/2011/11/22/forwardsecret.html" title="Forward secrecy for Google HTTPS">wrote a post with more details on what was achieved</a> to increase
efficiency of such a mechanism: with a few fellow people, he wrote an
efficient implementation of some elliptic curve cryptography for&nbsp;OpenSSL.</p>
<div class="toc">
<ul>
<li><a href="#without-forward-secrecy">Without forward&nbsp;secrecy</a></li>
<li><a href="#diffie-hellman-with-discrete-logarithm">Diffie-Hellman with discrete&nbsp;logarithm</a></li>
<li><a href="#diffie-hellman-with-elliptic-curves">Diffie-Hellman with elliptic curves</a><ul>
<li><a href="#some-theory">Some&nbsp;theory</a></li>
<li><a href="#in-practice">In&nbsp;practice</a></li>
<li><a href="#some-benchmarks">Some&nbsp;benchmarks</a></li>
</ul>
</li>
</ul>
</div>
<h1 id="without-forward-secrecy">Without forward&nbsp;secrecy</h1>
<p>To understand the problem when forward secrecy is absent, let&#8217;s look
at the classic <abbr title="Transport Layer Security"><span class="caps">TLS</span></abbr> handshake when using a cipher suite like
<code>AES128-SHA</code>. During this handshake, the server will present its
certificate and both the client and the server will agree on a <em>master
secret</em>.</p>
<p><img alt="TLS full handshake" src="//d1g3mdmxf8zbo9.cloudfront.net/images/benchs-ssl/ssl-handshake.png" title="Full TLS handshake"></p>
<p>This secret is built from a 48byte <em>premaster secret</em> generated and
encrypted by the client with the public key of the server. It is then
sent in a <em>Client Key Exchange</em> message to the server during the third
step of the <abbr title="Transport Layer Security"><span class="caps">TLS</span></abbr> handshake. The <em>master secret</em> is derived from this
<em>premaster secret</em> and random values sent in clear-text with <em>Client
Hello</em> and <em>Server Hello</em>&nbsp;messages.</p>
<p>This scheme is secure as long as only the server is able to decrypt
the <em>premaster secret</em> (with its private key) sent by the
client. Let&#8217;s suppose that an attacker records all exchanges between
the server and clients during a year. Two years later, the server is
decommissioned and sent for recycling. The attacker is able to recover
the hard drive with the private key. She can now decrypt any session
she recorded: the encrypted premaster secret sent by a client is
decrypted with the private key and the master secret is derived from
it. The attacker can now recover passwords and other sensitive
information that can still be valuable&nbsp;today.</p>
<p>The main problem lies in the fact that the private key is used for two
purposes: <strong>authentication</strong> of the server and <strong>encryption</strong> of a
shared secret. Authentication only matters while the communication is
established, but encryption is expected to last for&nbsp;years.</p>
<h1 id="diffie-hellman-with-discrete-logarithm">Diffie-Hellman with discrete&nbsp;logarithm</h1>
<p>One way to solve the problem is to keep using the private key for
authentication but uses an independent mechanism to agree on a shared
secret. Hopefully, there exists a well-known protocol for this: the
<a href="http://en.wikipedia.org/wiki/Diffie-Hellman" title="Diffie-Hellman key exchange on Wikipedia">Diffie-Hellman key exchange</a>. It is a method of exchanging keys
without any prior knowledge. Here is how it works in <abbr title="Transport Layer Security"><span class="caps">TLS</span></abbr>:</p>
<ol>
<li>The server needs to generate once (for example, with <code>openssl
    dhparam</code> command):<ul>
<li>·p·, a large <a href="http://en.wikipedia.org/wiki/Prime_number" title="Prime numbers on Wikipedia">prime number</a>,</li>
<li>·g·, a <a href="http://en.wikipedia.org/wiki/Primitive_root_modulo_n" title="Primitive root modulo n on Wikipedia">primitive root modulo ·p·</a> (for every integer
   ·a· <a href="http://en.wikipedia.org/wiki/Coprime" title="Coprime numbers on Wikipedia">coprime</a> to ·p·, there exists an integer ·k· such
   that ·g^k=a\mod&nbsp;p·).</li>
</ul>
</li>
<li>The server picks a random integer ·a· and compute ·g^a \mod
    p·. After sending its regular <em>Certificate</em> message, it will also
    send a <em>Server Key Exchange</em> message (not included in the
    handshake depicted above) containing, unencrypted but signed with
    its private key for authentication purpose:<ul>
<li>random value from the <em>Client Hello</em>&nbsp;message,</li>
<li>random value from the <em>Server Hello</em>&nbsp;message,</li>
<li>·p·,&nbsp;·g·,</li>
<li>·g^a\mod&nbsp;p=A·.</li>
</ul>
</li>
<li>The client checks that the signature is correct. It also picks a
    random integer ·b· and sends ·g^b \mod p=B· in a <em>Client Key
    Exchange</em> message. It will also compute ·A^b\mod p=g^{ab}\mod p·
    which is the <em>premaster secret</em> from which the <em>master secret</em> is&nbsp;derived.</li>
<li>The server will receive ·B· and compute ·B^a\mod p=g^{ab}\mod p·
    which is the same <em>premaster secret</em> known by the&nbsp;client.</li>
</ol>
<p>Again, the private key is only used for authentication purpose. An
eavesdropper will only know ·p·, ·g·, ·g^a\mod p· and ·g^b\mod
p·. Computing ·g^{ab}\mod p· from those values is the
<a href="http://en.wikipedia.org/wiki/Discrete_logarithm" title="Discrete Logarithm on Wikipedia">discrete logarithm</a> problem for which there is no known
efficient&nbsp;solution.</p>
<p>Because the Diffie-Hellman exchange described above always uses new
random values ·a· and ·b·, it is called <em>Ephemeral Diffie-Hellman</em>
(<span class="caps">EDH</span> or <span class="caps">DHE</span>). Cipher suites like <code>DHE-RSA-AES128-SHA</code> use this
protocol to achieve <em>perfect forward secrecy</em><sup id="fnref:pfs"><a href="#fn:pfs" rel="footnote">1</a></sup>.</p>
<p>To achieve a good level of security, parameters of the same size as
the key are usually used (the security provided by the discrete
logarithm problem is about the same as the security provided by
factorisation of two large prime numbers) and therefore, the
exponentiation operations are pretty slow as we can see in the
benchmark&nbsp;below:</p>
<p><img alt="Graphical comparison of speed with and without DHE" src="//d1g3mdmxf8zbo9.cloudfront.net/images/benchs-ssl/dhe-impact.png" title="Performances of stud on 6 cores, with and without DHE with a 1024bit key"></p>
<h1 id="diffie-hellman-with-elliptic-curves">Diffie-Hellman with elliptic&nbsp;curves</h1>
<p>Fortunately, there exists another way to achieve a Diffie-Hellman key
exchange with the help of <a href="http://en.wikipedia.org/wiki/Elliptic_curve_cryptography" title="Elliptic curve cryptography on Wikipedia">elliptic curve cryptography</a> which is
based on the algebraic structure of elliptic curves over finite
fields. To get some background on this, be sure to check first
<a href="http://en.wikipedia.org/wiki/Elliptic_curve" title="Elliptic curves on Wikipedia">Wikipedia article on elliptic curves</a>. Elliptic curve
cryptography allows one to achieve the same level of security than <span class="caps">RSA</span>
with smaller keys. For example, a 224bit elliptic curve is believed to
be <a href="http://www.keylength.com/en/compare/" title="Cryptographic key length recommendation">as secure as a 2048bit <span class="caps">RSA</span> key</a>.</p>
<h2 id="some-theory">Some&nbsp;theory</h2>
<p>Diffie-Hellman key exchange described above can easily be translated
to elliptic curves. Instead of defining ·p· and ·g·, you get some
elliptic curve, ·y^2=x^3+\alpha x+\beta·, a prime ·p· and a base
point ·G·. All those parameters are public. In fact, while they can be
generated by the server, this is a difficult operation and they are
usually chosen among a set of published&nbsp;ones.</p>
<p>The use of elliptic curves is an extension of <abbr title="Transport Layer Security"><span class="caps">TLS</span></abbr> described in
<a href="http://tools.ietf.org/html/rfc4492" title="RFC 4492: ECC Cipher Suites for TLS"><span class="caps">RFC</span> 4492</a>. Unlike with the classic Diffie-Hellman key
exchange, the client and the server need to agree on the various
paremeters. Most of this agreement is done inside <em>Client Hello</em> and
<em>Server Hello</em> messages. While it is possible to define some arbitrary
parameters, web browsers will only support a handful of predefined
curves, usually <span class="caps">NIST</span> P-256, P-384 and P-521. From here, the key
exchange with elliptic curves is pretty similar to the classic
Diffie-Hellman&nbsp;one:</p>
<ol>
<li>The server picks a random integer ·a· and compute ·aG· which will
    be sent, unencrypted but signed with its private key for
    authentication purpose, in a <em>Server Key Exchange</em>&nbsp;message.</li>
<li>The client checks that the signature is correct. It also picks a
    random integer ·b· and sends ·bG· in a <em>Client Key Exchange</em>
    message. It will also compute ·b\cdot aG=abG· which is the
    <em>premaster secret</em> from which the <em>master secret</em> is&nbsp;derived.</li>
<li>The server will receive ·bG· and compute ·a\cdot bG=abG·
    which is the same <em>premaster secret</em> known by the&nbsp;client.</li>
</ol>
<p>An eavesdropper will only see ·aG· and ·bG· and won&#8217;t be able to
compute efficiently&nbsp;·abG·.</p>
<p>Using <code>ECDHE-RSA-AES128-SHA</code> cipher suite (with P-256 for example) is
already a huge speed improvement over <code>DHE-RSA-AES128-SHA</code> thanks to
the reduced size of the various parameters&nbsp;involved.</p>
<p>Web browsers only support a handful of well-defined elliptic curves,
chosen to ease an efficient implementation. Bodo Möller, Emilia Käsper
and Adam Langley have provided 64bit optimized versions of <span class="caps">NIST</span> P-224,
P-256 and P-521 for OpenSSL. To get even more details on the matter,
you can read the end of the
<a href="http://www.imperialviolet.org/2010/12/04/ecc.html" title="Elliptic curves and their implementation">introduction on elliptic curves</a> from Adam Langley, then a
<a href="http://research.google.com/pubs/archive/37376.pdf" title="Fast Elliptic Curve Cryptography in OpenSSL">short paper from Emilia Käsper</a> which presents a 64bit
optimized implementation of the <span class="caps">NIST</span> elliptic curve <span class="caps">NIST</span>&nbsp;P-224.</p>
<h2 id="in-practice">In&nbsp;practice</h2>
<p>First, keep in mind that elliptic curve cryptography is not supported
by all browsers. Recent versions of Firefox and Chrome should handle
<span class="caps">NIST</span> P-256, P-384 and P-521 but for most versions Internet Explorer,
you are currently out of luck. Therefore, you need to keep accepting
other cipher&nbsp;suites.</p>
<p>You need a recent version of OpenSSL. Support for <span class="caps">ECDHE</span> cipher suites
has been added in <strong>OpenSSL 1.0.0</strong>. Check with <code>openssl ciphers ECDH</code>
that your version supports them. If you want to use the 64bit
optimized version, you need to run a snapshot of OpenSSL 1.0.1,
configured with <code>enable-ec_nistp_64_gcc_128</code> option. A recent <span class="caps">GCC</span> is
also required in this&nbsp;case.</p>
<p>Next, you need to choose the appropriate <strong>cipher suites</strong>. If
forward secrecy is an option for you, you can opt for
<code>ECDHE-RSA-AES128-SHA:AES128-SHA:RC4-SHA</code> cipher suites which should be
compatible with most browsers. If you really need forward secrecy, you
may opt for
<code>ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:EDH-DSS-DES-CBC3-SHA</code>
instead.</p>
<p>Then, you need to ensure the <strong>order of cipher suites is
respected</strong>. On <em>nginx</em>, this is done with <code>ssl_prefer_server_ciphers
on</code>. On <em>Apache</em>, this is <code>SSLHonorCipherOrder on</code>.</p>
<p><strong><span class="caps">UPDATED</span>:</strong> You need to check <strong><span class="caps">ECDHE</span> support for your web
server</strong>. For <em>nginx</em>, the support has been added in 1.0.6 and
1.1.0. The curve selected defaults to <span class="caps">NIST</span> P-256. You can specify
another one with <code>ssl_ecdh_curve</code> directive. For <em>Apache</em>, it has been
added in 2.3.3 and does not exist in the current stable branch. Adding
support for <span class="caps">ECDHE</span> is quite easy. You can check
<a href="https://github.com/bumptech/stud/pull/61" title="Adding support for ECDHE in stud">how I added it in <em>stud</em></a>. This issue also exists for <span class="caps">DHE</span>
cipher suites, in which case you also might have to specify <span class="caps">DH</span>
parameters to use (generated with <code>openssl dhparam</code>) using some
special directive or by appending the parameters to the
certificate. Check <a href="https://tech.immerda.ch/?p=84" title="The state of Forward Secrecy in OpenSSL">Immerda Techblog article</a> for more
background about this&nbsp;point.</p>
<p>The implementation of <a href="/en/blog/2011-ssl-session-reuse-rfc5077.html" title="Speeding up SSL: enabling session reuse"><abbr title="Transport Layer Security"><abbr title="Transport Layer Security"><span class="caps">TLS</span></abbr></abbr> session tickets</a> may be
incompatible with forward secrecy, depending on how they are
implemented. When they are protected by a random key generated at the
start of the server, the same key could be used for months. Some
implementations<sup id="fnref:stud"><a href="#fn:stud" rel="footnote">2</a></sup> may derive the key from the private key. In
this case, forward secrecy is broken. If forward secrecy is a
requirement for you, you need to either disable tickets or ensure that
key rotation happens&nbsp;often.</p>
<p>Check with <code>openssl s_client -tls1 -cipher ECDH -connect
127.0.0.1:443</code> that everything works as&nbsp;expected.</p>
<h2 id="some-benchmarks">Some&nbsp;benchmarks</h2>
<p>With the help of the <a href="https://github.com/vincentbernat/ssl-dos/blob/master/server-vs-client.c" title="Tool compare processing power needed by client and server">micro-benchmark tool</a> that I
developed for my <a href="/en/blog/2011-ssl-dos-mitigation.html" title="SSL computational DoS mitigation">previous article</a>, we can compare the
efficiency of cipher suites providing forward&nbsp;secrecy:</p>
<p><img alt="Speed comparison with/without DHE/ECDHE" src="//d1g3mdmxf8zbo9.cloudfront.net/images/benchs-ssl/ecdhe.png" title="Compared performance for 1000 handshakes of various cipher suites (RSA 2048, DHE, ECDHE, optimized ECDHE)"></p>
<p>I have used a <a href="ftp://ftp.openssl.org/snapshot/openssl-1.0.1-stable-SNAP-20111125.tar.gz">snapshot of OpenSSL 1.0.1 (2011/11/25)</a>. The
optimized version of <span class="caps">ECDHE</span> is the one you get by using
<code>enable-ec_nistp_64_gcc_128</code> option when configuring&nbsp;OpenSSL.</p>
<p>Let&#8217;s focus on the server part. Enabling <code>DHE-RSA-AES128-SHA</code> cipher
suite hinders the performance of <abbr title="Transport Layer Security"><span class="caps">TLS</span></abbr> handshakes by a factor of
3. Using <code>ECDHE-RSA-AES128-SHA</code> instead only adds an overhead of
27%. However, if we use the 64bit optimized version, the <strong>cost is
only 15%</strong>. The overhead is only per full <abbr title="Transport Layer Security"><span class="caps">TLS</span></abbr> handshake. If 3 out of 4
of your handshakes are resumed, you need to adjust the&nbsp;numbers.</p>
<p>Your mileage may vary but the computational cost for enabling perfect
forward secrecy with an <span class="caps">ECDHE</span> cipher suite seems a small sacrifice for
better&nbsp;security.</p>
<div class="footnote">
<hr>
<ol>
<li id="fn:pfs">
<p><em>Perfect forward secrecy</em> is an enhanced version of <em>forward
    secrecy</em>. It assumes each exchanged key are independent and
    therefore a compromised key cannot be used to compromise
    another one.&#160;<a href="#fnref:pfs" rev="footnote" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
<li id="fn:stud">
<p>For example, this is the case of the implementation I have
     proposed for <a href="https://github.com/bumptech/stud" title="stud, the scalable TLS unwrapping daemon">stud</a> to enable <a href="https://github.com/bumptech/stud/pull/30" title="Sharing tickets with multiple instances of stud">sharing of tickets
     between multiple hosts</a>.&#160;<a href="#fnref:stud" rev="footnote" title="Jump back to footnote 2 in the text">&#8617;</a></p>
</li>
</ol>
</div>
]]>
            </content>
        </entry>
                <entry>
            <title type="html">A quick look at Typekit</title>
            <author><name>Vincent Bernat</name></author>
            <link href="http://vincent.bernat.im/en/blog/2011-typekit-overview.html"/>
            <updated>2011-11-14T08:50:49+01:00</updated>
            <id>http://www.luffy.cx/en/blog/2011-typekit-overview.html</id>

            <content type="html">
<![CDATA[
<p>Back in the dark ages of the web, before the introduction of <abbr title="Cascading Style Sheets"><span class="caps">CSS</span></abbr> 3,
browsers could only display fonts available on the client
system. Thanks to the introduction of <code>@font-face</code> and its now
widespread support, this is over. Now, Web designers have access to a
large selection of fonts and most users will be able to appreciate&nbsp;them.</p>
<p><a href="http://www.typekit.com" title="Typekit">Typekit</a> provides a subscription-based library of hosted,
high-quality fonts to use on websites. I expose here my own, mostly
uneducated<sup id="fnref:educated"><a href="#fn:educated" rel="footnote">1</a></sup> on the typographic side, look on this&nbsp;service.</p>
<div class="toc">
<ul>
<li><a href="#fonts-embedding-101">Fonts embedding 101</a><ul>
<li><a href="#self-hosting-and-font-face">Self-hosting and&nbsp;@font-face</a></li>
<li><a href="#google-web-fonts">Google Web&nbsp;Fonts</a></li>
<li><a href="#paid-services">Paid&nbsp;services</a></li>
</ul>
</li>
<li><a href="#typekit-the-good-parts">Typekit: the good&nbsp;parts&#8230;</a></li>
<li><a href="#and-the-bad-ones">&#8230;and the bad ones</a><ul>
<li><a href="#not-free-nor-free">Not free, nor&nbsp;free</a></li>
<li><a href="#difficulty-to-choose-and-test-fonts">Difficulty to choose and test&nbsp;fonts</a></li>
<li><a href="#poor-subset-support">Poor subset&nbsp;support</a></li>
<li><a href="#defective-caching">Defective&nbsp;caching</a></li>
</ul>
</li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
</div>
<h1 id="fonts-embedding-101">Fonts embedding&nbsp;101</h1>
<p>There are several ways to embed fonts for the Web. Let&#8217;s have a look
at the most common&nbsp;ones.</p>
<h2 id="self-hosting-and-font-face">Self-hosting and <code>@font-face</code></h2>
<p>A first possibility is to host fonts yourself and provide a <abbr title="Cascading Style Sheets"><span class="caps">CSS</span></abbr> file
with the appropriate <code>@font-face</code> declarations. There are five
important things to&nbsp;know:</p>
<ol>
<li>There is <strong>no common format</strong>. You will need to host different
    versions of the same font to support most&nbsp;browsers.</li>
<li>Of course, Internet Explorer comes with its own <strong>quirks</strong> that
    you need to work&nbsp;around.</li>
<li>Most browsers enforce a <strong><a href="http://en.wikipedia.org/wiki/Same_origin_policy" title="Wikipedia article on same origin policy">same origin policy</a></strong>. You need to
    serve your fonts from the same domain as the requesting page. You
    can circumvent such a limitation by enabling
    <a href="http://enable-cors.org/" title="Enable cross-origin resource sharing">cross-origin resource sharing</a>: add an
    <code>Access-Control-Allow-Origin</code> header when serving&nbsp;fonts.</li>
<li>Fonts are unlikely to change. To <strong>leverage caching</strong>, configure
    an explicit expiration date far in the future. Something like 30&nbsp;days.</li>
<li>There is no <a href="https://developer.mozilla.org/en/css/@font-face" title="@font-face reference at MDN"><span class="caps">MIME</span> types registered for fonts</a>. Don&#8217;t bother
    setting one, even if Google Chrome likes to complain about them in
    the&nbsp;console.</li>
</ol>
<p>One great resource is <a href="http://www.fontsquirrel.com/" title="Font Squirrel">Font Squirrel</a> which provides kits
with fonts and the appropriate <abbr title="Cascading Style Sheets"><span class="caps">CSS</span></abbr> declarations. You choose your font
family (or upload one of your own), the formats that you want to use
(check them all) and you will get a <span class="caps">ZIP</span> archive with all fonts and a
<abbr title="Cascading Style Sheets"><span class="caps">CSS</span></abbr> file. You may want to tweak it a bit to enable automatic use of
the bold variant when needed and to use a local copy if available. For
example, if you choose <em>Crimson</em>, an oldstyle typeface, you may want
to declare the bold version with <code>font-weight: bold</code> and add local&nbsp;names:</p>
<div class="codehilite"><pre><span class="k">@font-face</span> <span class="p">{</span>
    <span class="nt">font-family</span><span class="o">:</span> <span class="s1">&#39;Crimson&#39;</span><span class="o">;</span>
    <span class="nt">src</span><span class="o">:</span> <span class="nt">url</span><span class="o">(</span><span class="s1">&#39;Crimson-Bold-webfont.eot&#39;</span><span class="o">);</span>
    <span class="nt">src</span><span class="o">:</span> <span class="nt">local</span><span class="o">(</span><span class="s1">&#39;Crimson Bold&#39;</span><span class="o">),</span> <span class="nt">local</span><span class="o">(</span><span class="s1">&#39;Crimson Text Bold&#39;</span><span class="o">),</span>
         <span class="nt">url</span><span class="o">(</span><span class="s1">&#39;Crimson-Bold-webfont.eot?#iefix&#39;</span><span class="o">)</span> <span class="nt">format</span><span class="o">(</span><span class="s1">&#39;embedded-opentype&#39;</span><span class="o">),</span>
         <span class="nt">url</span><span class="o">(</span><span class="s1">&#39;Crimson-Bold-webfont.woff&#39;</span><span class="o">)</span> <span class="nt">format</span><span class="o">(</span><span class="s1">&#39;woff&#39;</span><span class="o">),</span>
         <span class="nt">url</span><span class="o">(</span><span class="s1">&#39;Crimson-Bold-webfont.ttf&#39;</span><span class="o">)</span> <span class="nt">format</span><span class="o">(</span><span class="s1">&#39;truetype&#39;</span><span class="o">),</span>
         <span class="nt">url</span><span class="o">(</span><span class="s1">&#39;Crimson-Bold-webfont.svg#CrimsonBold&#39;</span><span class="o">)</span> <span class="nt">format</span><span class="o">(</span><span class="s1">&#39;svg&#39;</span><span class="o">);</span>
    <span class="nt">font-weight</span><span class="o">:</span> <span class="nt">bold</span><span class="o">;</span>
    <span class="nt">font-style</span><span class="o">:</span> <span class="nt">normal</span><span class="o">;</span>
<span class="p">}</span>
</pre></div>


<h2 id="google-web-fonts">Google Web&nbsp;Fonts</h2>
<p>For open-source fonts, you can also use
<a href="http://www.google.com/webfonts" title="Google Web Fonts">Google Web Fonts</a> instead of hosting the files
yourself. Build a collection of fonts and choose the variants that you
want to use for each of them. You will then be provided with a code
snippet to paste in the <code>&lt;head&gt;</code> element of your page. For example,
for <em>Crimson</em>:</p>
<div class="codehilite"><pre><span class="nt">&lt;link</span> <span class="na">href=</span><span class="s">&#39;http://fonts.googleapis.com/css?family=Crimson+Text:400,700,400italic&#39;</span>
      <span class="na">rel=</span><span class="s">&#39;stylesheet&#39;</span> <span class="na">type=</span><span class="s">&#39;text/css&#39;</span><span class="nt">&gt;</span>
</pre></div>


<p>Why choose this solution over&nbsp;self-hosting?</p>
<ol>
<li>You don&#8217;t use your own <strong>bandwith</strong> to serve fonts. This may be
    important if you pay for&nbsp;it.</li>
<li>Google uses its own <strong><abbr title="Content Delivery Network"><abbr title="Content Delivery Network"><span class="caps">CDN</span></abbr></abbr></strong> to serve fonts. If you don&#8217;t use a <abbr title="Content Delivery Network"><span class="caps">CDN</span></abbr>
    yourself, this can be a major performance&nbsp;improvement.</li>
<li><strong>Caching</strong> is more efficient since many sites will use the same&nbsp;font.</li>
<li>It&#8217;s <strong>easier</strong> to do it&nbsp;right.</li>
</ol>
<p>Unless you are concerned about Google tracking your users<sup id="fnref:track"><a href="#fn:track" rel="footnote">2</a></sup>, I
think this is a better solution than self-hosting. Quick delivery of
fonts is pretty important since content rendering can be delayed by&nbsp;them.</p>
<h2 id="paid-services">Paid&nbsp;services</h2>
<p>If you would like to use commercial fonts, like <em>Adobe Minion Pro</em> or
<em>Paratype Futura <span class="caps">PT</span></em>, a convenient option is to rent
them. <a href="http://www.typekit.com" title="Typekit">Typekit</a> is service providing such an option. Pricing
depends on volume and the number of fonts you want to have access
to. There is a free plan and the first paid plan is <span class="caps">US</span>$24.99 per
year. Other <a href="http://www.smashingmagazine.com/2010/10/20/review-of-popular-web-font-embedding-services/" title="Smashing Magazine: Review of Popular Web Font Embedding Services">similar services</a> exist. Feel free to&nbsp;compare.</p>
<p>Once registered, the workflow is similar to <em>Google Web Fonts</em>. You
choose your fonts, assemble them in a &#8220;kit&#8221; and publish it. Instead
of directly providing a <abbr title="Cascading Style Sheets"><span class="caps">CSS</span></abbr> file, <em>Typekit</em> provides some Javascript
which will in turn download a <abbr title="Cascading Style Sheets"><span class="caps">CSS</span></abbr> file containing all fonts in the
appropriate format for the browser (on most browsers, fonts are
<em>inlined</em>).</p>
<div class="codehilite"><pre><span class="nt">&lt;script </span><span class="na">type=</span><span class="s">&quot;text/javascript&quot;</span>
        <span class="na">src=</span><span class="s">&quot;//use.typekit.com/tyt0atd.js&quot;</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">&quot;text/javascript&quot;</span><span class="nt">&gt;</span>
  <span class="k">try</span><span class="p">{</span><span class="nx">Typekit</span><span class="p">.</span><span class="nx">load</span><span class="p">();}</span><span class="k">catch</span><span class="p">(</span><span class="nx">e</span><span class="p">){}</span>
<span class="nt">&lt;/script&gt;</span>
</pre></div>


<h1 id="typekit-the-good-parts">Typekit: the good&nbsp;parts&#8230;</h1>
<p>So, why choose <em>Typekit</em>? First, there is the <strong>very large choice of
fonts</strong>. The first paid plan comes with more than 500 fonts from about
80 foundries. There are about a hundred serif fonts and a couple
hundred sans serif&nbsp;ones.</p>
<p><em>Typekit</em> provides a <strong>convenient interface to browse fonts</strong>. You can
either search fonts by name or by characteristics. In the last case,
you can filter on properties like the classification (serif, sans
serif, decorative, etc.), weight, width, contrast, x-height,
recommended use or language support. Once a font is selected and added
to your kit, you can easily choose what variants you want. The kit
total size is&nbsp;displayed.</p>
<p>If you happen to meet any problem or have some questions, <em>Typekit</em>
<strong>support is very responsive</strong>. I got clear and crisp answers in less
than a few hours in the&nbsp;week-end.</p>
<h1 id="and-the-bad-ones">&#8230;and the bad&nbsp;ones</h1>
<p>Unfortunately, <em>Typekit</em> has also some shortcomings. One of the most
commonly cited is that Javascript is mandatory. No Javascript, no
fonts. If you want to display the appropriate fonts for users without
Javascript, you should just not use <em>Typekit</em>.</p>
<h2 id="not-free-nor-free">Not free, nor&nbsp;free</h2>
<p>While <em>Typekit</em> offers some open-source fonts, most of them are
not. Moreover, only a few of them are available in the free
plan. While I would prefer to use open-source fonts, I don&#8217;t consider
this a strong requirement: if you are dissatisfied for some reason,
switching back to open-source fonts (or another service) is fast and&nbsp;easy.</p>
<p>I like serif fonts a lot and they get less attention from the <abbr title="Free and Open Source Software"><span class="caps">FLOSS</span></abbr>
world: it is difficult to find one whose readability on screen is
excellent. <em>Droid Serif</em> is a nice font but is a bit too black for
me. Maybe <em>Cardo</em> would be a good&nbsp;match.</p>
<p>You may disagree and in this case, <a href="http://www.google.com/webfonts" title="Google Web Fonts">Google Web Fonts</a> or
self-hosting seem the perfect&nbsp;match.</p>
<h2 id="difficulty-to-choose-and-test-fonts">Difficulty to choose and test&nbsp;fonts</h2>
<p>While browsing fonts is easy and smooth, choosing and testing them is
another matter. For example, <em>Typekit</em> is missing some interface to
compare font rendering for whole paragraphs at a given size. It also
misses a way to check how two fonts render together, one for headings
and one for paragraphs. Here, <em>Google Web Fonts</em> is more&nbsp;versatile.</p>
<p>Things become really difficult when you want to test your selected
fonts for real. Except if you have invested into one of the expensive
plans, you can only include a limited number of fonts in your
kit. Each time you want to try another set of fonts, you need to
modify your kit and wait for it to be distributed across <em>Typekit</em>
network. You may have to <strong>wait five or ten minutes between each
change</strong>!</p>
<p>Another inconvenient thing is that once you publish your site, any
change to the kit will affect the published version. Therefore,
you need to use a second kit for development and play back and
forth with those two&nbsp;kits.</p>
<p>What would be convenient here is a special kit with all fonts from the
library with restricted access to some <span class="caps">IP</span> to avoid abuse. This is
something done by <a href="http://www.fontdeck.com/" title="Fontdeck">Fontdeck</a>, a&nbsp;competitor.</p>
<h2 id="poor-subset-support">Poor subset&nbsp;support</h2>
<p>Because you want to keep the font size small (about 30 kB for each
variant), <em>Typekit</em> usually proposes two subsets: the default one
contains <strong>only latin characters</strong> and the complete one with <strong>all
glyphs</strong>. If some glyph is absent from the default subset, you need to
use the complete one which is roughly two to four times the size of
the default one. This is a bit huge for only one&nbsp;character.</p>
<p>What would be nice is to have subsets for each language. In my case, I
would take a French subset because I need the &#8220;œ&#8221; glyph which appears
in French in words like &#8220;<em>cœur</em>&#8221; (<em>heart</em> or <em>core</em>) or &#8220;<em>œil</em>&#8221;
(<em>eye</em>). I don&#8217;t want to select the complete subset just for this&nbsp;character.</p>
<p>When a glyph is absent, the next font in the <abbr title="Cascading Style Sheets"><span class="caps">CSS</span></abbr> stack is used. For
example, if the selected font is <em><span class="caps">FF</span> Tisa Web Pro</em> and the next font
in the stack is <em>Droid Serif</em>, here is how the word &#8220;<em>cœur</em>&#8221; may be
rendered. On the first line, <em><span class="caps">FF</span> Tisa Web Pro</em> contains the
appropriate glyph. On the second line, the glyph is absent and taken
from <em>Droid Serif</em>. Since x-height and contrast are a bit different,
the replaced glyph seems out of tone. At small sizes, the difference
accounts for more than&nbsp;10%.</p>
<p><img alt="Various rendering of word &quot;cœur&quot;" src="//d1g3mdmxf8zbo9.cloudfront.net/images/typekit/ligatures.png" title="Rendering when glyph is present, substituted by a glyph from another font or emulated. Rendering at 72px and 16px (zoomed)."></p>
<p>I have also added a third line where the ligature is built from &#8220;o&#8221;
and &#8220;e&#8221; and the following style is applied to&nbsp;&#8220;e&#8221;:</p>
<div class="codehilite"><pre><span class="nc">.lf-ligature</span> <span class="p">{</span>
    <span class="k">margin-left</span><span class="o">:</span> <span class="m">-0.172em</span><span class="p">;</span>
    <span class="n">zoom</span><span class="o">:</span> <span class="m">1</span><span class="p">;</span> <span class="c">/* Here to trigger hasLayout on <span class="caps">IE7</span> */</span>
<span class="p">}</span>
</pre></div>


<p>As you can see, the result seems good. I have a
<a href="https://github.com/vincentbernat/www.luffy.cx/commit/dab984d044c1dd7440a2db9b95e3b67c2ae07924#diff-3" title="Javascript code to render ligatures correctly">piece of Javascript</a> turning a ligature into the
appropriate markup. It can be extended to handle more ligatures and
could be adapted to handle other composed characters (like the ones in
&#8220;Antonín&nbsp;Dvořák&#8221;).</p>
<h2 id="defective-caching">Defective&nbsp;caching</h2>
<p>Because a document can only be rendered after the fonts have been
loaded<sup id="fnref:fout"><a href="#fn:fout" rel="footnote">3</a></sup>, it is pretty important to deliver fonts as fast as
possible. <em>Typekit</em> uses <a href="http://www.edgecast.com/" title="EdgeCast Networks">Edgecast</a> as a <abbr title="Content Delivery Network"><span class="caps">CDN</span></abbr> and
<a href="http://dyn.com/dns/dynect-managed-dns/" title="DynECT Managed DNS">DynECT</a> for <abbr title="Domain Name Service"><span class="caps">DNS</span></abbr>&nbsp;hosting.</p>
<p>Two files are downloaded. Both of them are hosted on
<code>use.typekit.com</code>. The first one is a script that will act as a
loader. Based on the characteristics of your browser, it will choose
how to download the requested fonts for best rendering. The second
file is generally a big <abbr title="Cascading Style Sheets"><span class="caps">CSS</span></abbr> file containing the&nbsp;fonts.</p>
<p>Here are the headers returned for the first&nbsp;file:</p>
<div class="codehilite"><pre><span class="kr"><span class="caps">HTTP</span></span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne"><span class="caps">OK</span></span>
<span class="na">Accept-Ranges</span><span class="o">:</span> <span class="l">bytes</span>
<span class="na">Cache-Control</span><span class="o">:</span> <span class="l">max-age=300</span>
<span class="na">Content-Encoding</span><span class="o">:</span> <span class="l">gzip</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">text/javascript</span>
<span class="na">Date</span><span class="o">:</span> <span class="l">Tue, 08 Nov 2011 18:34:16 <span class="caps">GMT</span></span>
<span class="na">ETag</span><span class="o">:</span> <span class="l">&quot;388467610+gzip&quot;</span>
<span class="na">Expires</span><span class="o">:</span> <span class="l">Tue, 08 Nov 2011 18:39:16 <span class="caps">GMT</span></span>
<span class="na">Last-Modified</span><span class="o">:</span> <span class="l">Sat, 05 Nov 2011 09:31:57 <span class="caps">GMT</span></span>
<span class="na">Server</span><span class="o">:</span> <span class="l"><span class="caps">ECS</span> (cdg/D624)</span>
<span class="na">Vary</span><span class="o">:</span> <span class="l">Accept-Encoding</span>
<span class="na">X-Cache</span><span class="o">:</span> <span class="l"><span class="caps">HIT</span></span>
<span class="na">Content-Length</span><span class="o">:</span> <span class="l">7440</span>
</pre></div>


<p>First, notice that the content is served compressed. Good point. The
next headers to look at are <code>Cache-Control</code>, <code>Date</code>, <code>ETag</code> and
<code>Expires</code>: the server requests the content to be <strong>cached for 5
minutes</strong>. When the browser notices that its copy is out-of-date, it
will issue a new request including a <code>If-None-Match: 388467610+gzip</code>
header. Unless the kit has been modified, the server will answer
with <code>304 Not Modified</code> and no content. The copy of the browser
will be valid for another 5 minutes. This means that after 5 minutes,
at least <strong>3 round-trips</strong> are needed to check if our fonts are&nbsp;up-to-date.</p>
<p>Worse, sometimes, <em>Typekit</em> servers may be just slow. They can wait
one second before answering, just to send a <code>304</code>. Since the first file
is a script embedded in <code>&lt;head&gt;</code>, the whole page is blocked until you
get the answer. Here is an illustrative example with Chromium 14 where
a page using <em>Typekit</em> is loaded while all static assets are in the
navigator cache and things have gone wrong (which is pretty&nbsp;rare):</p>
<p><img alt="Screenshot of Chromium Inspector" src="//d1g3mdmxf8zbo9.cloudfront.net/images/typekit/slow.png" title="Timeline view when loading a page with Typekit embedded"></p>
<p>Since fonts are needed, the rendering has been paused for 3.5 seconds
until <em>Typekit</em> was fully loaded. If we look more closely, we may also
notice we got a status <code>200</code> from the server instead of <code>304</code>. Here is
an excerpt of the browser&nbsp;request:</p>
<div class="codehilite"><pre><span class="nf"><span class="caps">GET</span></span> <span class="nn">/tyt0atd.js</span> <span class="kr"><span class="caps">HTTP</span></span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Host</span><span class="o">:</span> <span class="l">use.typekit.com</span>
<span class="na">Connection</span><span class="o">:</span> <span class="l">keep-alive</span>
<span class="na">Accept-Encoding</span><span class="o">:</span> <span class="l">gzip,deflate,sdch</span>
<span class="na">If-None-Match</span><span class="o">:</span> <span class="l">&quot;2200251225+gzip&quot;</span>
<span class="na">If-Modified-Since</span><span class="o">:</span> <span class="l">Thu, 10 Nov 2011 11:38:11 <span class="caps">GMT</span></span>
</pre></div>


<p>And here is an excerpt of the answer&nbsp;headers:</p>
<div class="codehilite"><pre><span class="kr"><span class="caps">HTTP</span></span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne"><span class="caps">OK</span></span>
<span class="na">Accept-Ranges</span><span class="o">:</span> <span class="l">bytes</span>
<span class="na">Cache-Control</span><span class="o">:</span> <span class="l">max-age=300</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">text/javascript</span>
<span class="na">Date</span><span class="o">:</span> <span class="l">Fri, 11 Nov 2011 17:10:03 <span class="caps">GMT</span></span>
<span class="na">ETag</span><span class="o">:</span> <span class="l">&quot;2200251225&quot;</span>
<span class="na">Expires</span><span class="o">:</span> <span class="l">Fri, 11 Nov 2011 17:15:03 <span class="caps">GMT</span></span>
<span class="na">Last-Modified</span><span class="o">:</span> <span class="l">Thu, 10 Nov 2011 11:38:11 <span class="caps">GMT</span></span>
<span class="na">Server</span><span class="o">:</span> <span class="l"><span class="caps">EOS</span> (lax001/54E5)</span>
<span class="na">Content-Length</span><span class="o">:</span> <span class="l">25755</span>
</pre></div>


<p>What happened? For some unknown reason, the server denied the access
to the compressed version of the resource: there is no
<code>Content-Encoding: gzip</code> while the browser <em>did</em> send
<code>Accept-Encoding: gzip</code>. The tag provided by the browser
(<code>2200251225+gzip</code>) came obviously from the compressed resource and
therefore does not match. <a href="http://rfc2616.com/" title="RFC 2616: HTTP/1.1"><span class="caps">RFC</span> 2616</a> requests
<code>If-Modified-Since</code> header to be ignored if the tag does not
match. Consequently, the server answers with <code>200 OK</code> and resend the
whole file. The same problem happened with the <abbr title="Cascading Style Sheets"><span class="caps">CSS</span></abbr> file. Let me stress
again how important the problem is: we had to download again the two
files but we also downloaded the non-compressed&nbsp;version.</p>
<p>Now, let&#8217;s suppose that we did not run into this problem and the
server answered with <code>304 Not Modified</code>. The result is still not
satisfactory: we would have waited 1.3 seconds to get both answers
from the server. Keep in mind that most of the time, <em>Typekit</em> is
pretty&nbsp;fast.</p>
<p>Here is how I think this should have been done: each time you modify
your font kit, you get a new <span class="caps">URL</span> to use (containing the version of
the font kit for example). This resource and the associated fonts
(whose <span class="caps">URL</span> is also versioned) are requested to be cached for several
days. As a sidenote, this also enables to modify a kit for your
development environment without modifying the kit for your
production&nbsp;site.</p>
<p>I suspect that <em>Typekit</em> did not go this way to track kit usage more
accurately and enforce the appropriate pricing. Having multiple
versions of the same kit would also allow us to use more fonts that we
are paying&nbsp;for.</p>
<p><strong><span class="caps">UPDATED</span>:</strong> <em>Typekit</em> support knows the problem and is working on&nbsp;it:</p>
<blockquote>
<p>You&#8217;ve identified a small bug in our <abbr title="Content Delivery Network"><span class="caps">CDN</span></abbr> provider that we&#8217;re working
with them to fix. Hopefully I can give an explanation of what&#8217;s&nbsp;happening.</p>
<p>The <abbr title="Content Delivery Network"><span class="caps">CDN</span></abbr> edge servers have a cache of recently served kits on them.
Any request that is served from that cache will be correctly Gzipped
and handle ETags. Unfortunately, if the content isn&#8217;t already in
cache and needs to be fetched from the master origin server then the
request won&#8217;t be gzipped correctly which has the side effect of
breaking&nbsp;ETags.</p>
<p>[&#8230;]</p>
<p>We are working to on getting this bug fixed, but any change to a
globally distributed <abbr title="Content Delivery Network"><span class="caps">CDN</span></abbr> will take some time. We&#8217;re also working on
having our content cached longer than 5 minutes whilst still
allowing people to quickly update their&nbsp;site.</p>
</blockquote>
<p><strong><span class="caps">UPDATED</span>:</strong> To avoid to block page loading if <em>Typekit</em> is slow, you
can load it <a href="http://icelab.com.au/articles/loading-typekit-asynchronously-with-yepnopejs/" title="Loading Typekit asynchronously with yepnope.js">asynchronously with <em>yepnope.js</em></a>. You&#8217;ll get
some <abbr title="Flash of unstyled text"><span class="caps">FOUT</span></abbr>&nbsp;instead.</p>
<h1 id="conclusion">Conclusion</h1>
<p>I have mixed feelings about <em>Typekit</em>. While the difficulty to test
fonts and the lack of language-related subsets are annoying, I have
been able to work around them. However, the caching problem is more
annoying. I am still considering going back to <em>Google Web Fonts</em>
just because of&nbsp;this.</p>
<div class="footnote">
<hr>
<ol>
<li id="fn:educated">
<p>While I have a high interest in typography, have my own
         copy of “<a href="http://www.amazon.com/Elements-Typographic-Style-Robert-Bringhurst/dp/0881792063" title="The Elements of Typographic Style on Amazon">The Elements of Typographic Style</a>” by
         Robert Bringhurst and have throughly read
         “<a href="http://webtypography.net/" title="The Elements of Typographic Style Applied to the Web">The Elements of Typographic Style Applied to the Web</a>”,
         I am still fairly novice on this matter.&#160;<a href="#fnref:educated" rev="footnote" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
<li id="fn:track">
<p>Google serves fonts from a cookie-less domain. Technically,
      they could still do some kind of tracking but I believe they
      don&#8217;t.&#160;<a href="#fnref:track" rev="footnote" title="Jump back to footnote 2 in the text">&#8617;</a></p>
</li>
<li id="fn:fout">
<p>In fact, browsers have different strategies on how to
     render before fonts availability. Paul Irish wrote a
     <a href="http://paulirish.com/2009/fighting-the-font-face-fout/" title="Fighting the @font-face FOUT">comprehensive article on <abbr title="Flash of unstyled text"><abbr title="Flash of unstyled text"><abbr title="Flash of unstyled text"><span class="caps">FOUT</span></abbr></abbr></abbr></a>. One common strategy is
     to render a blank space until downloaded fonts are
     available. If this takes too much time, fallback fonts may be
     used.&#160;<a href="#fnref:fout" rev="footnote" title="Jump back to footnote 3 in the text">&#8617;</a></p>
</li>
</ol>
</div>
]]>
            </content>
        </entry>
    </feed>
