aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet6/in6_src.c
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2012-02-14 11:51:32 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2012-02-14 11:51:32 +0000
commit1b46c7f83201c70bc284b319a970764d3811e63f (patch)
tree7747d02f7ac0c5e3e66e8ac0cdc0574cb41e4c2a /sys/netinet6/in6_src.c
parentaaf04b7cb637af9400e6b9ae1bd531ef828a7c82 (diff)
downloadsrc-1b46c7f83201c70bc284b319a970764d3811e63f.tar.gz
src-1b46c7f83201c70bc284b319a970764d3811e63f.zip
Allow to provide a hint to in6_selectsrc() for the interface using the
return ifnet double pointer. Pass that hint down to in6_selectif() to be used when i) the default FIB is queried and ii) route lookup fails because the network is not present (i.e. someone deleted the connected subnet). This hint should not be generally used from anywhere outside the neighbor discovery code. We just make use of it from nd6_ns_output(). Extend the nd6_na_output() interface by a nd6_na_output_fib() version and pass the FIB number from the NS mbuf on to NA to allow the new mbuf to inherit the FIB tag and a later lookup from ip6_output() to succeed in the aformentioned example case. Provide a wrapper function for the old public interface also used from CARP but mark it with BURN_BRIDGES to cleanup in HEAD after MFC. Sponsored by: Cisco Systems, Inc.
Notes
Notes: svn path=/projects/multi-fibv6/head/; revision=231671
Diffstat (limited to 'sys/netinet6/in6_src.c')
-rw-r--r--sys/netinet6/in6_src.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c
index 295ea715e36b..9ed3eab8aefd 100644
--- a/sys/netinet6/in6_src.c
+++ b/sys/netinet6/in6_src.c
@@ -131,7 +131,8 @@ static int selectroute __P((struct sockaddr_in6 *, struct ip6_pktopts *,
struct ip6_moptions *, struct route_in6 *, struct ifnet **,
struct rtentry **, int, int));
static int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *,
- struct ip6_moptions *, struct route_in6 *ro, struct ifnet **, int));
+ struct ip6_moptions *, struct route_in6 *ro, struct ifnet **,
+ struct ifnet *, int));
static struct in6_addrpolicy *lookup_addrsel_policy(struct sockaddr_in6 *);
@@ -182,7 +183,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
struct ifnet **ifpp, struct in6_addr *srcp)
{
struct in6_addr dst, tmp;
- struct ifnet *ifp = NULL;
+ struct ifnet *ifp = NULL, *oifp = NULL;
struct in6_ifaddr *ia = NULL, *ia_best = NULL;
struct in6_pktinfo *pi = NULL;
int dst_scope = -1, best_scope = -1, best_matchlen = -1;
@@ -195,8 +196,18 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
KASSERT(srcp != NULL, ("%s: srcp is NULL", __func__));
dst = dstsock->sin6_addr; /* make a copy for local operation */
- if (ifpp)
+ if (ifpp) {
+ /*
+ * Save a possibly passed in ifp for in6_selectsrc. Only
+ * neighbor discovery code should use this feature, where
+ * we may know the interface but not the FIB number holding
+ * the connected subnet in case someone deleted it from the
+ * default FIB and we need to check the interface.
+ */
+ if (*ifpp != NULL)
+ oifp = *ifpp;
*ifpp = NULL;
+ }
if (inp != NULL) {
INP_LOCK_ASSERT(inp);
@@ -217,7 +228,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
struct in6_ifaddr *ia6;
/* get the outgoing interface */
- if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp,
+ if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp, oifp,
(inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB))
!= 0)
return (error);
@@ -283,7 +294,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
* the outgoing interface and the destination address.
*/
/* get the outgoing interface */
- if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp,
+ if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp, oifp,
(inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB)) != 0)
return (error);
@@ -750,12 +761,14 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
static int
in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp,
- int fibnum)
+ struct ifnet *oifp, int fibnum)
{
int error;
struct route_in6 sro;
struct rtentry *rt = NULL;
+ KASSERT(retifp != NULL, ("%s: retifp is NULL", __func__));
+
if (ro == NULL) {
bzero(&sro, sizeof(sro));
ro = &sro;
@@ -765,6 +778,11 @@ in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
&rt, 1, fibnum)) != 0) {
if (ro == &sro && rt && rt == sro.ro_rt)
RTFREE(rt);
+ /* Help ND. See oifp comment in in6_selectsrc(). */
+ if (oifp != NULL && fibnum == RT_DEFAULT_FIB) {
+ *retifp = oifp;
+ error = 0;
+ }
return (error);
}