Subject: Re: kern/10500: eon driver
To: None <lha@stacken.kth.se>
From: Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us>
List: tech-net
Date: 07/04/2000 23:10:37
executive summary: eon is horribly broken when given an address of
0.0.0.0, requires some work, and, unless someone wants to spend a
bunch of time rewriting it, we should just comment it out of the
GENERIC configs on all ports.

some analysis:

eon implements RFC986, which appears to be a rough ISO equivalent of
the IPv6 6to4 transition mechanism: using ipv4 as a link-layer
protocol underlying ISO, with ipv4 addresses embedded in the addresses
used by the upper layer protocol.

It's doing something slightly screwy with routing, by attempting to
keep a cached route around in the pseudo-device's softc.

This is running afoul of some fairly squirrelly conventions within the
main protocol-independant routing table code.

background:

a "struct route" is a parameterized reference to a route; a "struct
rtentry" is the actual route.

route entries are refcounted, with a twist: the reference from the
routing table itself doesn't count as a reference!  (this is not
documented anywhere I found).

eon attempts to keep a cached copy of the route to the ipv4 default
(all-zeros) address around which is used in certain cases (i haven't
spent the time needed to understand exactly when).

now, when you ifconfig eon0 to 0.0.0.0:
	- the higher-level interface management code allocates an
interface route to 0.0.0.0 for the ifaddr, set to refcount 1.
	- rtrequest then calls into the interface-specific
	  eonrtrequest routine to do interface-specific setup.
	- eonrtrequest then looks up the route to 0.0.0.0, and finds
	  the interface route to itself (!)  (which can't possibly
	  work in practice..); this gets its refcount bumped up to 2
	- on return from rtrequest(), rtinit() decrements the refcount
	  of the route (back down to 1), since the reference from the
	  routing table doesn't count.

the second time around, the interface management code notices that the
interface route already exists, and so it starts cleaning it up;
rtrequest() is invoked, which then calls through to eonrtrequest,
which releases the reference on that route (which drops it from 1 back
down to 0), freeing the route.

rtinit then frees it again:

		if (rt->rt_refcnt <= 0) {
			rt->rt_refcnt++;
			rtfree(rt);
		}

Conclusions:

 - The pragmatic answer here is probably to declare EON as "broken, in
need of work, but nobody really cares" and take it out of all the
stock GENERIC configs on all supported architectures.

 - Handling of route reference counting is horribly underdocumented
and confusing and just plain fragile.  If I were going to redesign
things, one thing I would change would be to have ifaddrs explicitly
hold references to route entries for both the ifa's address (pointing
to loopback) and for the subnet/destination route associated with the
ifa (pointing to the interface).

						- Bill