Date: Sun, 17 Jan 2021 20:32:32 GMT From: "Alexander V. Chernikov" <melifaro@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: f9e0752e3573 - main - Create new in6_purgeifaddr() which purges bound ifa prefix if it gets unused. Message-ID: <202101172032.10HKWWAi045957@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=f9e0752e3573e0b60e578e58ee2eac3d42ff533a commit f9e0752e3573e0b60e578e58ee2eac3d42ff533a Author: Alexander V. Chernikov <melifaro@FreeBSD.org> AuthorDate: 2021-01-13 00:18:00 +0000 Commit: Alexander V. Chernikov <melifaro@FreeBSD.org> CommitDate: 2021-01-17 20:32:25 +0000 Create new in6_purgeifaddr() which purges bound ifa prefix if it gets unused. Currently if_purgeifaddrs() uses in6_purgeaddr() to remove IPv6 ifaddrs. in6_purgeaddr() does not trrigger prefix removal if number of linked ifas goes to 0, as this is a low-level function. As a result, if_purgeifaddrs() purges all IPv4/IPv6 addresses but keeps corresponding IPv6 prefixes. Fix this by creating higher-level wrapper which handles unused prefix usecase and use it in if_purgeifaddrs(). Differential revision: https://reviews.freebsd.org/D28128 --- sys/net/if.c | 2 +- sys/netinet6/in6.c | 53 +++++++++++++++++++++++++++++--------------------- sys/netinet6/in6_var.h | 1 + 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/sys/net/if.c b/sys/net/if.c index 68ed4cf65dc1..74fdd066fd2d 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1077,7 +1077,7 @@ if_purgeaddrs(struct ifnet *ifp) #endif /* INET */ #ifdef INET6 if (ifa->ifa_addr->sa_family == AF_INET6) { - in6_purgeaddr(ifa); + in6_purgeifaddr((struct in6_ifaddr *)ifa); /* ifp_addrhead is already updated */ continue; } diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index b42cc16cdb6f..48fa8dd2efc6 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -696,31 +696,10 @@ aifaddr_out: } case SIOCDIFADDR_IN6: - { - struct nd_prefix *pr; - - /* - * If the address being deleted is the only one that owns - * the corresponding prefix, expire the prefix as well. - * XXX: theoretically, we don't have to worry about such - * relationship, since we separate the address management - * and the prefix management. We do this, however, to provide - * as much backward compatibility as possible in terms of - * the ioctl operation. - * Note that in6_purgeaddr() will decrement ndpr_addrcnt. - */ - pr = ia->ia6_ndpr; - in6_purgeaddr(&ia->ia_ifa); - if (pr != NULL && pr->ndpr_addrcnt == 0) { - ND6_WLOCK(); - nd6_prefix_unlink(pr, NULL); - ND6_WUNLOCK(); - nd6_prefix_del(pr); - } + in6_purgeifaddr(ia); EVENTHANDLER_INVOKE(ifaddr_event_ext, ifp, &ia->ia_ifa, IFADDR_EVENT_DEL); break; - } default: if (ifp->if_ioctl == NULL) { @@ -1364,6 +1343,36 @@ in6_purgeaddr(struct ifaddr *ifa) in6_unlink_ifa(ia, ifp); } +/* + * Removes @ia from the corresponding interfaces and unlinks corresponding + * prefix if no addresses are using it anymore. + */ +void +in6_purgeifaddr(struct in6_ifaddr *ia) +{ + struct nd_prefix *pr; + + /* + * If the address being deleted is the only one that owns + * the corresponding prefix, expire the prefix as well. + * XXX: theoretically, we don't have to worry about such + * relationship, since we separate the address management + * and the prefix management. We do this, however, to provide + * as much backward compatibility as possible in terms of + * the ioctl operation. + * Note that in6_purgeaddr() will decrement ndpr_addrcnt. + */ + pr = ia->ia6_ndpr; + in6_purgeaddr(&ia->ia_ifa); + if (pr != NULL && pr->ndpr_addrcnt == 0) { + ND6_WLOCK(); + nd6_prefix_unlink(pr, NULL); + ND6_WUNLOCK(); + nd6_prefix_del(pr); + } +} + + static void in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) { diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index f5e6a931ae64..5f4364c6fba0 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -887,6 +887,7 @@ int in6_update_ifa(struct ifnet *, struct in6_aliasreq *, void in6_prepare_ifra(struct in6_aliasreq *, const struct in6_addr *, const struct in6_addr *); void in6_purgeaddr(struct ifaddr *); +void in6_purgeifaddr(struct in6_ifaddr *); int in6if_do_dad(struct ifnet *); void in6_savemkludge(struct in6_ifaddr *); void *in6_domifattach(struct ifnet *);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202101172032.10HKWWAi045957>