Fix 'in6_purgeaddr: err=65, destination address delete failed' message.
P2P ifa may require 2 routes: one is the loopback route, another is the "prefix" route towards its destination. Current code marks loopback routes existence with IFA_RTSELF and "prefix" p2p routes with IFA_ROUTE. For historic reasons, we fill in ifa_dstaddr for loopback interfaces. To avoid installing the same route twice, we preemptively set IFA_RTSELF when adding "prefix" route for loopback. However, the teardown part doesn't have this hack, so we try to remove the same route twice. Fix this by checking if ifa_dstaddr is different from the ifa_addr and moving this logic into a separate function. Reviewed By: kp Differential Revision: https://reviews.freebsd.org/D29121 MFC after: 3 days
This commit is contained in:
parent
f2f8405cf6
commit
7634919e15
@ -1294,13 +1294,27 @@ in6_handle_dstaddr_rtrequest(int cmd, struct in6_ifaddr *ia)
|
||||
return (error);
|
||||
}
|
||||
|
||||
static bool
|
||||
ifa_is_p2p(struct in6_ifaddr *ia)
|
||||
{
|
||||
int plen;
|
||||
|
||||
plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
|
||||
|
||||
if ((plen == 128) && (ia->ia_dstaddr.sin6_family == AF_INET6) &&
|
||||
!IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &ia->ia_dstaddr.sin6_addr))
|
||||
return (true);
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
void
|
||||
in6_purgeaddr(struct ifaddr *ifa)
|
||||
{
|
||||
struct ifnet *ifp = ifa->ifa_ifp;
|
||||
struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
|
||||
struct in6_multi_mship *imm;
|
||||
int plen, error;
|
||||
int error;
|
||||
|
||||
if (ifa->ifa_carp)
|
||||
(*carp_detach_p)(ifa, false);
|
||||
@ -1328,10 +1342,7 @@ in6_purgeaddr(struct ifaddr *ifa)
|
||||
free(imm, M_IP6MADDR);
|
||||
}
|
||||
/* Check if we need to remove p2p route */
|
||||
plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
|
||||
if (ia->ia_dstaddr.sin6_family != AF_INET6)
|
||||
plen = 0;
|
||||
if ((ia->ia_flags & IFA_ROUTE) && plen == 128) {
|
||||
if ((ia->ia_flags & IFA_ROUTE) && ifa_is_p2p(ia)) {
|
||||
error = in6_handle_dstaddr_rtrequest(RTM_DELETE, ia);
|
||||
if (error != 0)
|
||||
log(LOG_INFO, "%s: err=%d, destination address delete "
|
||||
@ -1434,7 +1445,7 @@ static int
|
||||
in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia,
|
||||
struct in6_aliasreq *ifra, int hostIsNew)
|
||||
{
|
||||
int error = 0, plen, ifacount = 0;
|
||||
int error = 0, ifacount = 0;
|
||||
struct ifaddr *ifa;
|
||||
struct sockaddr_in6 *pdst;
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
@ -1487,14 +1498,7 @@ in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia,
|
||||
* XXX: the logic below rejects assigning multiple addresses on a p2p
|
||||
* interface that share the same destination.
|
||||
*/
|
||||
plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
|
||||
if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 &&
|
||||
ia->ia_dstaddr.sin6_family == AF_INET6) {
|
||||
/*
|
||||
* Handle the case for ::1 .
|
||||
*/
|
||||
if (ifp->if_flags & IFF_LOOPBACK)
|
||||
ia->ia_flags |= IFA_RTSELF;
|
||||
if (!(ia->ia_flags & IFA_ROUTE) && ifa_is_p2p(ia)) {
|
||||
error = in6_handle_dstaddr_rtrequest(RTM_ADD, ia);
|
||||
if (error)
|
||||
goto done;
|
||||
|
Loading…
Reference in New Issue
Block a user