aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander V. Chernikov <melifaro@FreeBSD.org>2021-03-08 20:27:29 +0000
committerAlexander V. Chernikov <melifaro@FreeBSD.org>2021-03-11 08:35:22 +0000
commit83cedad139721c6c150be8c078417cfcb311ee78 (patch)
tree9e20ed035d958927b4d20c9f000037dbfe576018
parent9cd7f222d5c9d03371b8941fb9150007dfdd1638 (diff)
downloadsrc-83cedad139721c6c150be8c078417cfcb311ee78.tar.gz
src-83cedad139721c6c150be8c078417cfcb311ee78.zip
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 (cherry picked from commit 7634919e15f1147b6f26d55354be375bc9b198db)
-rw-r--r--sys/netinet6/in6.c32
1 files changed, 18 insertions, 14 deletions
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 4665a21c28fd..02cb9df7da3a 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -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;