This patch fixes the following issues:

- Interface link-local address is not reachable within the
  node that owns the interface, this is due to the mismatch
  in address scope as the result of the installed interface
  address loopback route. Therefore for each interface
  address loopback route, the rt_gateway field (of AF_LINK
  type) will be used to track which interface a given
  address belongs to. This will aid the address source to
  use the proper interface for address scope/zone validation.
- The loopback address is not reachable. The root cause is
  the same as the above.
- Empty nd6 entries are created for the IPv6 loopback addresses
  only for validation reason. Doing so will eliminate as much
  of the special case (loopback addresses) handling code
  as possible, however, these empty nd6 entries should not
  be returned to the userland applications such as the
  "ndp" command.
Since both of the above issues contain common files, these
files are committed together.

Reviewed by:	bz
MFC after:	immediately
This commit is contained in:
qingli 2009-09-05 16:43:16 +00:00
parent 36333bfcba
commit 0cca60c70d
4 changed files with 44 additions and 21 deletions

View File

@ -263,6 +263,15 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
__func__, dl->sdl_index);
return EINVAL;
}
if (ifp->if_flags & IFF_LOOPBACK) {
struct ifaddr *ia;
ia = ifa_ifwithaddr(dst);
if (ia != NULL) {
ifp = ia->ifa_ifp;
ifa_free(ia);
} else
return EINVAL;
}
switch (rtm->rtm_type) {
case RTM_ADD:

View File

@ -1201,8 +1201,8 @@ in6_purgeaddr(struct ifaddr *ifa)
bzero(&null_sdl, sizeof(null_sdl));
null_sdl.sdl_len = sizeof(null_sdl);
null_sdl.sdl_family = AF_LINK;
null_sdl.sdl_type = V_loif->if_type;
null_sdl.sdl_index = V_loif->if_index;
null_sdl.sdl_type = ia->ia_ifp->if_type;
null_sdl.sdl_index = ia->ia_ifp->if_index;
bzero(&info, sizeof(info));
info.rti_flags = ia->ia_flags | RTF_HOST | RTF_STATIC;
info.rti_info[RTAX_DST] = (struct sockaddr *)&ia->ia_addr;
@ -1782,9 +1782,9 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
if (error == 0 && rt != NULL) {
RT_LOCK(rt);
((struct sockaddr_dl *)rt->rt_gateway)->sdl_type =
rt->rt_ifp->if_type;
ifp->if_type;
((struct sockaddr_dl *)rt->rt_gateway)->sdl_index =
rt->rt_ifp->if_index;
ifp->if_index;
RT_REMREF(rt);
RT_UNLOCK(rt);
} else if (error != 0)
@ -2495,6 +2495,9 @@ in6_lltable_dump(struct lltable *llt, struct sysctl_req *wr)
} ndpc;
int i, error;
if (ifp->if_flags & IFF_LOOPBACK)
return 0;
LLTABLE_LOCK_ASSERT();
error = 0;

View File

@ -85,6 +85,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sx.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <net/if_llatbl.h>
#ifdef RADIX_MPATH
@ -697,8 +698,25 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
if (error == EHOSTUNREACH)
V_ip6stat.ip6s_noroute++;
if (retifp != NULL)
if (retifp != NULL) {
*retifp = ifp;
/*
* Adjust the "outgoing" interface. If we're going to loop
* the packet back to ourselves, the ifp would be the loopback
* interface. However, we'd rather know the interface associated
* to the destination address (which should probably be one of
* our own addresses.)
*/
if (rt) {
if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) &&
(rt->rt_gateway->sa_family == AF_LINK))
*retifp =
ifnet_byindex(((struct sockaddr_dl *)
rt->rt_gateway)->sdl_index);
}
}
if (retrt != NULL)
*retrt = rt; /* rt may be NULL */
@ -750,16 +768,6 @@ in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
return (flags);
}
/*
* Adjust the "outgoing" interface. If we're going to loop the packet
* back to ourselves, the ifp would be the loopback interface.
* However, we'd rather know the interface associated to the
* destination address (which should probably be one of our own
* addresses.)
*/
if (rt && rt->rt_ifa && rt->rt_ifa->ifa_ifp)
*retifp = rt->rt_ifa->ifa_ifp;
if (ro == &sro && rt && rt == sro.ro_rt)
RTFREE(rt);
return (0);

View File

@ -602,15 +602,12 @@ skip_ipsec2:;
rt->rt_use++;
}
/*
* The outgoing interface must be in the zone of source and
* destination addresses. We should use ia_ifp to support the
* case of sending packets to an address of our own.
* destination addresses.
*/
if (ia != NULL && ia->ia_ifp)
origifp = ia->ia_ifp;
else
origifp = ifp;
origifp = ifp;
src0 = ip6->ip6_src;
if (in6_setscope(&src0, origifp, &zone))
@ -634,6 +631,12 @@ skip_ipsec2:;
goto badscope;
}
/* We should use ia_ifp to support the case of
* sending packets to an address of our own.
*/
if (ia != NULL && ia->ia_ifp)
ifp = ia->ia_ifp;
/* scope check is done. */
goto routefound;