IPv6: Only advertise addresses when needed

Remember when we have advertised an address.
If we want to advertise it again, check this first.
If we still want to advertise it, clear this flag for all other
matching addresses.
Clear advertised flags from all addresses on carrier up.

This reduces needless NA spam from dhcpcd when the IPv6 Router
is needlessly chatty with RA.
This commit is contained in:
Roy Marples 2024-09-11 10:28:58 +01:00
parent 4f9648737c
commit d0fef9f768
3 changed files with 42 additions and 10 deletions

View File

@ -1832,16 +1832,19 @@ ipv6_startstatic(struct interface *ifp)
int
ipv6_start(struct interface *ifp)
{
#ifdef IPV6_POLLADDRFLAG
#if defined(ND6_ADVERTISE) || defined(IPV6_POLLADDRFLAG)
struct ipv6_state *state;
/* We need to update the address flags. */
if ((state = IPV6_STATE(ifp)) != NULL) {
struct ipv6_addr *ia;
#ifdef IPV6_POLLADDRFLAG
const char *alias;
int flags;
#endif
TAILQ_FOREACH(ia, &state->addrs, next) {
#ifdef IPV6_POLLADDRFLAG
#ifdef ALIAS_ADDR
alias = ia->alias;
#else
@ -1850,6 +1853,9 @@ ipv6_start(struct interface *ifp)
flags = if_addrflags6(ia->iface, &ia->addr, alias);
if (flags != -1)
ia->addr_flags = flags;
#endif
/* hwaddr could have changed */
ia->flags &= ~IPV6_AF_ADVERTISED;
}
}
#endif

View File

@ -160,7 +160,8 @@
/*
* ND6 Advertising is only used for IP address sharing to prefer
* the address on a specific interface.
* the address on a specific interface or when the hardware address
* of the interface changes.
* This just fails to work on OpenBSD and causes erroneous duplicate
* address messages on BSD's other then DragonFly and NetBSD.
*/
@ -227,8 +228,9 @@ struct ipv6_addr {
#define IPV6_AF_EXTENDED (1U << 13)
#define IPV6_AF_REGEN (1U << 14)
#define IPV6_AF_ROUTER (1U << 15)
#define IPV6_AF_ADVERTISED (1U << 16)
#ifdef IPV6_MANAGETEMPADDR
#define IPV6_AF_TEMPORARY (1U << 16)
#define IPV6_AF_TEMPORARY (1U << 17)
#endif
struct ll_callback {

View File

@ -514,6 +514,7 @@ ipv6nd_advertise(struct ipv6_addr *ia)
struct interface *ifp;
struct ipv6_state *state;
struct ipv6_addr *iap, *iaf;
bool found_another = false;
struct nd_neighbor_advert *na;
if (IN6_IS_ADDR_MULTICAST(&ia->addr))
@ -529,20 +530,20 @@ ipv6nd_advertise(struct ipv6_addr *ia)
iaf = NULL;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
state = IPV6_STATE(ifp);
if (state == NULL || !if_is_link_up(ifp))
if (state == NULL)
continue;
TAILQ_FOREACH(iap, &state->addrs, next) {
if (!IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr))
continue;
/* Cancel any current advertisement. */
eloop_timeout_delete(ctx->eloop,
ipv6nd_sendadvertisement, iap);
if (iaf != NULL)
found_another = true;
/* Don't advertise what we can't use. */
if (iap->prefix_vltime == 0 ||
iap->addr_flags & IN6_IFF_NOTUSEABLE)
iap->addr_flags & IN6_IFF_NOTUSEABLE ||
!if_is_link_up(ifp))
continue;
if (iaf == NULL ||
@ -550,9 +551,32 @@ ipv6nd_advertise(struct ipv6_addr *ia)
iaf = iap;
}
}
if (iaf == NULL)
/* If we have already advertised the address, return. */
if (iaf == NULL || iaf->flags & IPV6_AF_ADVERTISED)
return;
/* Now cancel any other advertisements for the same address. */
if (found_another) {
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
state = IPV6_STATE(ifp);
if (state == NULL)
continue;
TAILQ_FOREACH(iap, &state->addrs, next) {
if (!IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr))
continue;
iap->flags &= ~IPV6_AF_ADVERTISED;
eloop_timeout_delete(ctx->eloop,
ipv6nd_sendadvertisement, iap);
}
}
} else {
eloop_timeout_delete(ctx->eloop,
ipv6nd_sendadvertisement, iaf);
}
/* Make the packet. */
ifp = iaf->iface;
iaf->na_len = sizeof(*na);
@ -588,7 +612,7 @@ ipv6nd_advertise(struct ipv6_addr *ia)
iaf->na_count = 0;
free(iaf->na);
iaf->na = na;
eloop_timeout_delete(ctx->eloop, ipv6nd_sendadvertisement, iaf);
iaf->flags |= IPV6_AF_ADVERTISED;
ipv6nd_sendadvertisement(iaf);
}
#elif !defined(SMALL)