socket. If we don't make an exact match, we may use a cached rule which
has lower priority than a rule that would otherwise have matched the
packet.
Code submitted by Karl Knutsson in PR/36051
is equal to one of the host's IPv6 addresses, do not stop at setting
the route's interface to lo0, but also clear the route's RTF_CLONED
flag, if it is present, so that ip6_input() will accept packets
sent to that destination. This is necessary because ip6_input()
will not accept a packet if it looks up the packet's destination
and finds a route with RTF_CLONED set.
I believe this will help IPv6 networking survive '/etc/rc.d/network
restart'. See the problem report, kern/33279.
If ip6_forward successfully forwards a packet, a cache, in this case a
ip6flow struct entry, will be created. ether_input and friends will
then be able to call ip6flow_fastforward with the packet which will then
be passed to if_output (unless an issue is found - in that case the packet
is passed back to ip6_input).
ok matt@ christos@ dyoung@ and joerg@
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
explicitly return `EINVAL'. Before, it was done but later in
ip6_setpktopt() when checking for 'len < ...')
CID-3316: check for 'm != NULL' before using it
ok christos@
rtcache_init and rtcache_init_noclone lookup ro_dst and store
the result in ro_rt, taking care of the reference counting and
calling the domain specific route cache.
rtcache_free checks if a route was cashed and frees the reference.
rtcache_copy copies ro_dst of the given struct route, checking that
enough space is available and incrementing the reference count of the
cached rtentry if necessary.
rtcache_check validates that the cached route is still up. If it isn't,
it tries to look it up again. Afterwards ro_rt is either a valid again
or NULL.
rtcache_copy is used internally.
Adjust to callers of rtalloc/rtflush in the tree to check the sanity of
ro_dst first (if necessary). If it doesn't fit the expectations, free
the cache, otherwise check if the cached route is still valid. After
that combination, a single check for ro_rt == NULL is enough to decide
whether a new lookup needs to be done with a different ro_dst.
Make the route checking in gre stricter by repeating the loop check
after revalidation.
Remove some unused RADIX_MPATH code in in6_src.c. The logic is slightly
changed here to first validate the route and check RTF_GATEWAY
afterwards. This is sementically equivalent though.
etherip doesn't need sc_route_expire similiar to the gif changes from
dyoung@ earlier.
Based on the earlier patch from dyoung@, reviewed and discussed with
him.
routing caused by stale route caches (struct route). Route caches
are sprinkled throughout PCBs, the IP fast-forwarding table, and
IP tunnel interfaces (gre, gif, stf).
Stale IPv6 and ISO route caches will be treated by separate patches.
Thank you to Christoph Badura for suggesting the general approach
to invalidating route caches that I take here.
Here are the details:
Add hooks to struct domain for tracking and for invalidating each
domain's route caches: dom_rtcache, dom_rtflush, and dom_rtflushall.
Introduce helper subroutines, rtflush(ro) for invalidating a route
cache, rtflushall(family) for invalidating all route caches in a
routing domain, and rtcache(ro) for notifying the domain of a new
cached route.
Chain together all IPv4 route caches where ro_rt != NULL. Provide
in_rtcache() for adding a route to the chain. Provide in_rtflush()
and in_rtflushall() for invalidating IPv4 route caches. In
in_rtflush(), set ro_rt to NULL, and remove the route from the
chain. In in_rtflushall(), walk the chain and remove every route
cache.
In rtrequest1(), call rtflushall() to invalidate route caches when
a route is added.
In gif(4), discard the workaround for stale caches that involves
expiring them every so often.
Replace the pattern 'RTFREE(ro->ro_rt); ro->ro_rt = NULL;' with a
call to rtflush(ro).
Update ipflow_fastforward() and all other users of route caches so
that they expect a cached route, ro->ro_rt, to turn to NULL.
Take care when moving a 'struct route' to rtflush() the source and
to rtcache() the destination.
In domain initializers, use .dom_xxx tags.
KNF here and there.
in6_control() with splnet()/splx(). I was being a bit paranoid
here. Following a cursory analysis of the code, this still looked
necessary. We don't spend a lot of time in these calls, so it
should not be too harmful to suspend network interrupts.
In in6_unlink_ifa(), call in6_delmulti() just once on each multicast
address (in6_multi). Previously, in6_unlink_ifa() called in6_delmulti()
on each in6_multi until in6_delmulti() removed the in6_multi from
the list and freed its memory. That's not justified: the multicast
list holds *one* reference. All other references belong to other
entities. We must wait to free the memory until the other entities
release their references, to protect against dereferencing a freed
in6_multi.
XXX I need to revisit in6_delmulti(), in6_unlink_ifa(), and friends,
XXX to pry apart the conditions where an in6_multi is removed from
XXX its list and where it is freed. Following my change, above,
XXX we still risk dereferencing a freed in6_multi.
Prevent in6_update_ifa() and in6_addremloop() from creating dangling
pointers to interfaces in the routing table. Previously, my NetBSD
tunnel concentrator, which adds and deletes a lot of P2P interfaces
with the same local address, crashed in 8 hours or less when it
dereferenced a dangling pointer to a deleted ifnet. Now, its uptime
is greater than 3 days.
Annotate a memory leak.
When copying one multicast address list to another, IFAREF before IFAFREE
to protect against using an ifaddr after (accidentally) freeing it.
LIST_REMOVE() a multicast address from its old list before
LIST_INSERT_HEAD() on its new list.
Do not count on in6_delmulti() removing its multicast-record argument
from the multicast address list that the record belongs to, because
clearly that is not what it (always) does.