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.
This commit is contained in:
Bjoern A. Zeeb 2012-02-14 11:51:32 +00:00
parent aaf04b7cb6
commit 1b46c7f832
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/multi-fibv6/head/; revision=231671
2 changed files with 53 additions and 15 deletions

View File

@ -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);
}

View File

@ -85,6 +85,8 @@ static void nd6_dad_timer(struct dadq *);
static void nd6_dad_ns_output(struct dadq *, struct ifaddr *);
static void nd6_dad_ns_input(struct ifaddr *);
static void nd6_dad_na_input(struct ifaddr *);
static void nd6_na_output_fib(struct ifnet *, const struct in6_addr *,
const struct in6_addr *, u_long, int, struct sockaddr *, u_int);
VNET_DEFINE(int, dad_ignore_ns) = 0; /* ignore NS in DAD - specwise incorrect*/
VNET_DEFINE(int, dad_maxtry) = 15; /* max # of *tries* to transmit DAD packet */
@ -344,19 +346,20 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
in6_all = in6addr_linklocal_allnodes;
if (in6_setscope(&in6_all, ifp, NULL) != 0)
goto bad;
nd6_na_output(ifp, &in6_all, &taddr6,
nd6_na_output_fib(ifp, &in6_all, &taddr6,
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL);
rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL,
M_GETFIB(m));
goto freeit;
}
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen,
ND_NEIGHBOR_SOLICIT, 0);
nd6_na_output(ifp, &saddr6, &taddr6,
nd6_na_output_fib(ifp, &saddr6, &taddr6,
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
rflag | ND_NA_FLAG_SOLICITED, tlladdr,
proxy ? (struct sockaddr *)&proxydl : NULL);
proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
freeit:
if (ifa != NULL)
ifa_free(ifa);
@ -508,14 +511,16 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
int error;
struct sockaddr_in6 dst_sa;
struct in6_addr src_in;
struct ifnet *oifp;
bzero(&dst_sa, sizeof(dst_sa));
dst_sa.sin6_family = AF_INET6;
dst_sa.sin6_len = sizeof(dst_sa);
dst_sa.sin6_addr = ip6->ip6_dst;
oifp = ifp;
error = in6_selectsrc(&dst_sa, NULL,
NULL, &ro, NULL, NULL, &src_in);
NULL, &ro, NULL, &oifp, &src_in);
if (error) {
char ip6buf[INET6_ADDRSTRLEN];
nd6log((LOG_DEBUG,
@ -957,13 +962,14 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
* tlladdr - 1 if include target link-layer address
* sdl0 - sockaddr_dl (= proxy NA) or NULL
*/
void
nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
static void
nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0,
const struct in6_addr *taddr6, u_long flags, int tlladdr,
struct sockaddr *sdl0)
struct sockaddr *sdl0, u_int fibnum)
{
struct mbuf *m;
struct m_tag *mtag;
struct ifnet *oifp;
struct ip6_hdr *ip6;
struct nd_neighbor_advert *nd_na;
struct ip6_moptions im6o;
@ -999,6 +1005,7 @@ nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
if (m == NULL)
return;
m->m_pkthdr.rcvif = NULL;
M_SETFIB(m, fibnum);
if (IN6_IS_ADDR_MULTICAST(&daddr6)) {
m->m_flags |= M_MCAST;
@ -1040,7 +1047,8 @@ nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
* Select a source whose scope is the same as that of the dest.
*/
bcopy(&dst_sa, &ro.ro_dst, sizeof(dst_sa));
error = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, NULL, &src);
oifp = ifp;
error = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, &oifp, &src);
if (error) {
char ip6buf[INET6_ADDRSTRLEN];
nd6log((LOG_DEBUG, "nd6_na_output: source can't be "
@ -1129,6 +1137,18 @@ nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
return;
}
#ifndef BURN_BRIDGES
void
nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
const struct in6_addr *taddr6, u_long flags, int tlladdr,
struct sockaddr *sdl0)
{
nd6_na_output_fib(ifp, daddr6_0, taddr6, flags, tlladdr, sdl0,
RT_DEFAULT_FIB);
}
#endif
caddr_t
nd6_ifptomac(struct ifnet *ifp)
{