diff options
author | Alexander V. Chernikov <melifaro@FreeBSD.org> | 2015-09-16 14:26:28 +0000 |
---|---|---|
committer | Alexander V. Chernikov <melifaro@FreeBSD.org> | 2015-09-16 14:26:28 +0000 |
commit | 1fe201c322f93424e29581c5622da7cde44db51f (patch) | |
tree | e04e3fcd4841d6aa1ce593fcc38aa9bb51b4cd33 /sys/netinet6/nd6.h | |
parent | 5c5fb901eb05f91db8e914500357953bf475b8a0 (diff) | |
download | src-1fe201c322f93424e29581c5622da7cde44db51f.tar.gz src-1fe201c322f93424e29581c5622da7cde44db51f.zip |
Simplify the way of attaching IPv6 link-layer header.
Problem description:
How do we currently perform layer 2 resolution and header imposition:
For IPv4 we have the following chain:
ip_output() -> (ether|atm|whatever)_output() -> arpresolve()
Lookup is done in proper place (link-layer output routine) and it is possible
to provide cached lle data.
For IPv6 situation is more complex:
ip6_output() -> nd6_output() -> nd6_output_ifp() -> (whatever)_output() ->
nd6_storelladdr()
We have ip6_ouput() which calls nd6_output() instead of link output routine.
nd6_output() does the following:
* checks if lle exists, creates it if needed (similar to arpresolve())
* performes lle state transitions (similar to arpresolve())
* calls nd6_output_ifp() which pushes packets to link output routine along
with running SeND/MAC hooks regardless of lle state
(e.g. works as run-hooks placeholder).
After that, iface output routine like ether_output() calls nd6_storelladdr()
which performs lle lookup once again.
As a result, we perform lookup twice for each outgoing packet for most types
of interfaces. We also need to maintain runtime-checked table of 'nd6-free'
interfaces (see nd6_need_cache()).
Fix this behavior by eliminating first ND lookup. To be more specific:
* make all nd6_output() consumers use nd6_output_ifp() instead
* rename nd6_output[_slow]() to nd6_resolve_[slow]()
* convert nd6_resolve() and nd6_resolve_slow() to arpresolve() semantics,
e.g. copy L2 address to buffer instead of pushing packet towards lower
layers
* Make all nd6_storelladdr() users use nd6_resolve()
* eliminate nd6_storelladdr()
The resulting callchain is the following:
ip6_output() -> nd6_output_ifp() -> (whatever)_output() -> nd6_resolve()
Error handling:
Currently sending packet to non-existing la results in ip6_<output|forward>
-> nd6_output() -> nd6_output _lle() which returns 0.
In new scenario packet is propagated to <ether|whatever>_output() ->
nd6_resolve() which will return EWOULDBLOCK, and that result
will be converted to 0.
(And EWOULDBLOCK is actually used by IB/TOE code).
Sponsored by: Yandex LLC
Differential Revision: https://reviews.freebsd.org/D1469
Notes
Notes:
svn path=/head/; revision=287861
Diffstat (limited to 'sys/netinet6/nd6.h')
-rw-r--r-- | sys/netinet6/nd6.h | 11 |
1 files changed, 4 insertions, 7 deletions
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index 52bc97fef8e7..41df9e4b7341 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -414,22 +414,19 @@ void nd6_llinfo_settimer_locked(struct llentry *, long); void nd6_timer(void *); void nd6_purge(struct ifnet *); void nd6_nud_hint(struct rtentry *, struct in6_addr *, int); -int nd6_resolve(struct ifnet *, struct rtentry *, struct mbuf *, - struct sockaddr *, u_char *); +int nd6_resolve(struct ifnet *, int, struct mbuf *, + const struct sockaddr *, u_char *, uint32_t *); int nd6_ioctl(u_long, caddr_t, struct ifnet *); void nd6_cache_lladdr(struct ifnet *, struct in6_addr *, char *, int, int, int); -int nd6_output(struct ifnet *, struct ifnet *, struct mbuf *, - struct sockaddr_in6 *, struct rtentry *); void nd6_grab_holdchain(struct llentry *, struct mbuf **, struct sockaddr_in6 *); int nd6_flush_holdchain(struct ifnet *, struct ifnet *, struct mbuf *, struct sockaddr_in6 *); -int nd6_need_cache(struct ifnet *); int nd6_add_ifa_lle(struct in6_ifaddr *); void nd6_rem_ifa_lle(struct in6_ifaddr *, int); -int nd6_storelladdr(struct ifnet *, struct mbuf *, - const struct sockaddr *, u_char *, uint32_t *); +int nd6_output_ifp(struct ifnet *, struct ifnet *, struct mbuf *, + struct sockaddr_in6 *); /* nd6_nbr.c */ void nd6_na_input(struct mbuf *, int, int); |