Skip to content

Commit

Permalink
IPv6: Only advertise addresses when needed
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rsmarples committed Sep 11, 2024
1 parent 4f96487 commit d0fef9f
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 10 deletions.
8 changes: 7 additions & 1 deletion src/ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
6 changes: 4 additions & 2 deletions src/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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 {
Expand Down
38 changes: 31 additions & 7 deletions src/ipv6nd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -529,30 +530,53 @@ 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 ||
iaf->iface->metric > iap->iface->metric)
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);
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit d0fef9f

Please sign in to comment.