The number of neighbors on a network segment can range from a few to many thousands. On large networks, the memory required by neighbour data structures can therefore grow quite big and affect system performances. Increasing the values of the gc_threshn configuration parameters in the neigh_table structure simply changes the maximum number of entries that can be created, but it does not solve the performance problem of over-consumption of limited kernel memory.
arpd is a user-space daemon that can offload work from the kernel by keeping its own (bigger) cache. A user-space implementation of ARP cannot be as fast as a kernel implementation, but the difference is acceptable in most cases.
To use arpd, a kernel has to be compiled with support for the ARPD feature. The kernel documentation calls ARPD an experimental feature, but it has actually been around for a long time.
Two arpd daemons are currently available for download. One is old and does not work properly, and the other is part of the IPROUTE2 package and does work. I will refer to the second one in this section.
The arpd daemon is responsible for intercepting ARP requests from other systems and maintaining its own database in lieu of a kernel cache. We won't say much about the internals of the daemon in this chapter, but we will focus on the interaction between the daemon and the kernel. While arpd maintains its own relationship with the network, the kernel can also continue to handle ARP requests, and is responsible for notifying arpd about events the kernel knows about. They communicate via a Netlink socket, which is supported by default in the 2.6 kernel.
Figure 28-22 gives the big picture of the interaction between the neighboring subsystem, ARP, and arpd. Essentially, the neighboring subsystem sends notifications to the daemon and the daemon listens for them. The next two sections go into more detail on this interaction.
Figure 28-22. Interaction between ARP and arpd daemon
28.13.1. Kernel Side
When ARPD is enabled, the neighboring subsystem sends messages to the user-space daemon. Here we review the routines used to send those messages and the conditions under which the routines are invoked:
28.13.2. User-Space Side
In the previous section we saw when the kernel sends notifications to arpd. Now we'll see how arpd handles them. Here's the skeleton of the daemon (the main function):
1. Parse command-line options 2. Open database 3. Load database from file if option present (3.1) Open socket for reception and transmission of ARP packets (3.2) Open socket with kernel for ARPD notifications 4. Infinite loop (4.1) Poll the two sockets (4.2) If events appear on socket (1), process input ARP packet (4.3) If events appear on socket (2), process input kernel message
A simplified model of this behavior is shown in Figure 28-23. (Figure 28-23(a) represents 4.2, and Figure 28-23(b) represents 4.3.) It should clearly show a correspondence to the kernel behavior described in the previous section.
The daemon accepts a few command-line options to tune its behavior. For instance, the administrator can specify:
The current arpd daemon implements its ARP cache using a generic Berkeley DB Database, which is the reason why, when an administrator installs the IPROUTE2 package, it includes a dependency on the Berkeley DB package.
One difference between arpd and the kernel's ARP subsystem is worth mentioning: unlike the kernel ARP cache, the arpd cache stores negative results. When an attempt to resolve an address fails, the daemon stores that information in its cache and does not retry the resolution for a certain amount of time.