Subject: RFC [patch]: unify route cache
To: None <tech-net@netbsd.org>
From: David Young <dyoung@pobox.com>
List: tech-net
Date: 04/24/2007 22:52:26
I have made a bunch of changes to our networking stacks in order to
eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is necessary
for correct routing.  Route-cache invalidation fixes an ancient PR,
kern/3508, at long last; it fixes various other PRs, also.

Patches at <ftp://cuw.ojctech.com/cuw/netbsd-1da8c563/ro_sa.patch>.
Please help me by testing!

Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously.  Of course, all design oversights and bugs are mine.

DETAILS

1 I added to each address family a pool of sockaddrs.  I have introduced
  routines for allocating, copying, and duplicating, and freeing
  sockaddrs:

	struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
	struct sockaddr *sockaddr_copy(struct sockaddr *dst,
	                               const struct sockaddr *src);
	struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
	struct sockaddr *sockaddr_free(struct sockaddr *sa);

  sockaddr_alloc() returns either a sockaddr from the pool belonging to
  the specified family, or NULL if the pool is exhausted.  The returned
  sockaddr has the right size for that family; sa_family and sa_len fields
  are initialized to the family and sockaddr length---e.g., sa_family
  = AF_INET and sa_len = sizeof(struct sockaddr_in).  sockaddr_free()
  puts the given sockaddr back into its family's pool.

  sockaddr_dup() and sockaddr_copy() work analogously to strdup() and
  strcpy(), respectively.  sockaddr_copy() KASSERTs that the family of
  the destination and source sockaddrs are alike.

  The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is passed
  directly to pool_get(9).

2 I added routines for initializing sockaddrs in each address family,
  sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(), etc.
  They are fairly self-explanatory.

3 structs route_in6 and route_iso are no more.  All protocol families use
  struct route.  I have changed the route cache, 'struct route', so
  that it does not contain storage space for a sockaddr.  Instead,
  struct route points to a sockaddr coming from the pool the sockaddr
  belongs to.  I added a new method to struct route, rtcache_setdst(),
  for setting the cache destination:

	int rtcache_setdst(struct route *, const struct sockaddr *);

  rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
  available to create the sockaddr storage.

  It is now possible for rtcache_getdst() to return NULL if, say,
  rtcache_setdst() failed.  I check the return value for NULL everywhere
  in the kernel.

4 Each routing domain (struct domain) has a list of live route caches,
  dom_rtcache.  rtflushall(sa_family_t af) looks up the domain indicated
  by 'af', walks the domain's list of route caches and invalidates
  each one.

TESTING

So far, IPv4 and IPv6 networking work fine in my rigorous wireless router
application.  I will test gre, stf, and pf, soon.  I need your help to
test IP Filter, AppleTalk, ISO, or Bluetooth networking for regressions.

TODO

Manual pages.

Dave

-- 
David Young             OJC Technologies
dyoung@ojctech.com      Urbana, IL * (217) 278-3933