Subject: Re: User-level ARP handling
To: Charles M. Hannum <mycroft@mit.edu>
From: Dennis Ferguson <dennis@jnx.com>
List: tech-net
Date: 09/02/1996 21:20:49
> Contrast this with IP routing.
>
> We handle RIP requests through a user-level program.  When the kernel
> needs to send a packet to a random IP address, and it doesn't already
> have an IP route for it, it sends a RTM_LOSS message to the routing
> socket.  The routing daemon does its magic (RIP, router discovery,
> whatever) to come up with a route and then delivers it to the kernel.

Note that 99.99% of Unix boxes running this kernel never generate an RTM_MISS
message, and routing protocol implementations for UNIX don't actually work
this way.  The kernel will only generate an RTM_MISS message if the
route lookup fails to match anything.  Since almost all Unix boxes (pretty
much all hosts, and most Unix machines used as routers) have a default
route in the kernel, a route lookup is guaranteed to match something.
And, similarly, gated and routed operate by installing a full set of
known routes in the kernel since (i) route caching is hard in general,
certainly in the presence of overlapping routes, and (ii) route caching
can actually make the state-in-the-kernel problem worse in some important
situations (for example, you are prevented from ever installing a default
route if you are caching, even though the vast majority of packets you
are sending may match the default).  And, of course, even without a
default route packets to a host on an ethernet will still not generate
an RTM_MISS, since even if the ARP-installed host route is absent you'll
still match the interface subnet route, and if you match anything you don't
get an RTM_MISS.

I think the message you are looking for is actually RTM_RESOLVE, which
the kernel will generate if you match a route with the RTF_XRESOLVE
flag set and which was sort of intended for things like this.
The trouble with using this to implement ARP (in fact RTF_XRESOLVE is
used by nothing I know of, either) is that the host routes generated by,
or for, ARP are installed not only when packets are forwarded, but also
when routes which reference the host address as a next hop are installed,
which end up pointing rt->rt_gwroute at the ARP host route.  Since there
is no mechanism for going around finding and updating all previously
installed routes which reference a particular address as a next hop once
the user-land daemon gets around to finally adding the host route it
discovered by running ARP, there needs to be a way to immediately generate
the host route on demand, in the kernel.  And, once generated, you can't
really remove such a route either, until you are sure that no references
to the route as a next hop remain in the table.  Having a user space
daemon responsible for adding and deleting this route is hence unlikely
to work well.

So an implementation of ARP in user space can't really install host
routes, since they'll need to be generated immediately by a cloning
operation.  What a user space ARP implementation could do is fill in
the device-dependent link-level address that is needed to actually
forward packets with the already-installed route, i.e. to fill in
rt->rt_llinfo.  Unfortunately, the thing pointed to by rt->rt_llinfo
is opague to the routing table code; it is really the responsibility
of the link-level device specific driver code to deal with this.  So,
while you may use the routing socket to implement this, the user space
daemon really needs to talk to the device driver (for more than just this;
it also needs to send and receive media-framed packets), not the routing
table code, since the latter needs to internalize the route-cloning
operations regardless.

In any case, I think what you're proposing looks more like a back channel
to the link-level code associated with a device than it looks like
a generic routing function.  The operations performed in route.c
won't change, only the source of link-level information that eventually
gets attached to the routes being generated will.

Dennis Ferguson