From: Roy Marples Date: Tue, 8 Oct 2019 12:35:50 +0000 (+0100) Subject: ARP: Don't send an initial ARP announcement for newly added addresses X-Git-Tag: v8.1.0~15 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1c6064da648c9b67a79d7f2b9d19e91d17db2177;p=thirdparty%2Fdhcpcd.git ARP: Don't send an initial ARP announcement for newly added addresses The kernel will do this for us. --- diff --git a/src/arp.c b/src/arp.c index 33725211..55b6203b 100644 --- a/src/arp.c +++ b/src/arp.c @@ -425,6 +425,7 @@ arp_announce1(void *arg) { struct arp_state *astate = arg; struct interface *ifp = astate->iface; + struct ipv4_addr *ia; if (++astate->claims < ANNOUNCE_NUM) logdebugx("%s: ARP announcing %s (%d of %d), " @@ -435,24 +436,26 @@ arp_announce1(void *arg) logdebugx("%s: ARP announcing %s (%d of %d)", ifp->name, inet_ntoa(astate->addr), astate->claims, ANNOUNCE_NUM); + + /* The kernel will send a Gratuitous ARP for newly added addresses. + * So we can avoid sending the same. */ + ia = ipv4_iffindaddr(ifp, &astate->addr, NULL); + if (astate->claims == 1 && ia != NULL && ia->flags & IPV4_AF_NEW) + goto skip_request; + if (arp_request(ifp, &astate->addr, &astate->addr) == -1) logerr(__func__); + +skip_request: + /* No longer a new address. */ + if (ia != NULL) + ia->flags |= ~IPV4_AF_NEW; + eloop_timeout_add_sec(ifp->ctx->eloop, ANNOUNCE_WAIT, astate->claims < ANNOUNCE_NUM ? arp_announce1 : arp_announced, astate); } -/* - * XXX FIXME - * Kernels supporting RFC5227 will announce the address when it's - * added. - * dhcpcd should not announce when this happens, nor need to open - * a BPF socket for it. - * Also, an address might be added to a non preferred inteface when - * the same address exists on a preferred one so we need to instruct - * the kernel not to announce the address somehow. - */ - void arp_announce(struct arp_state *astate) { @@ -498,6 +501,9 @@ arp_ifannounceaddr(struct interface *ifp, const struct in_addr *ia) { struct arp_state *astate; + if (ifp->flags & IFF_NOARP) + return; + astate = arp_find(ifp, ia); if (astate == NULL) { astate = arp_new(ifp, ia); diff --git a/src/ipv4.c b/src/ipv4.c index 8c89dc73..c55a7da6 100644 --- a/src/ipv4.c +++ b/src/ipv4.c @@ -622,7 +622,6 @@ ipv4_addaddr(struct interface *ifp, const struct in_addr *addr, { struct ipv4_state *state; struct ipv4_addr *ia; - bool is_new = false; #ifdef ALIAS_ADDR int replaced, blank; struct ipv4_addr *replaced_ia; @@ -653,8 +652,9 @@ ipv4_addaddr(struct interface *ifp, const struct in_addr *addr, #ifdef IN_IFF_TENTATIVE ia->addr_flags = IN_IFF_TENTATIVE; #endif - is_new = true; - } + ia->flags = IPV4_AF_NEW; + } else + ia->flags |= ~IPV4_AF_NEW; ia->mask = *mask; ia->brd = *bcast; @@ -698,7 +698,7 @@ ipv4_addaddr(struct interface *ifp, const struct in_addr *addr, } #endif - if (is_new) + if (ia->flags & IPV4_AF_NEW) TAILQ_INSERT_TAIL(&state->addrs, ia, next); return ia; } @@ -743,8 +743,7 @@ ipv4_applyaddr(void *arg) #ifdef ARP /* Announce the preferred address to * kick ARP caches. */ - if (!(ifp->flags & IFF_NOARP)) - arp_announceaddr(ifp->ctx,&lease->addr); + arp_announceaddr(ifp->ctx,&lease->addr); #endif } script_runreason(ifp, state->reason); @@ -806,8 +805,7 @@ ipv4_applyaddr(void *arg) rt_build(ifp->ctx, AF_INET); #ifdef ARP - if (!(ifp->flags & IFF_NOARP)) - arp_announceaddr(ifp->ctx, &state->addr->addr); + arp_announceaddr(ifp->ctx, &state->addr->addr); #endif if (state->state == DHS_BOUND) { diff --git a/src/ipv4.h b/src/ipv4.h index eaa0dcce..59b48a53 100644 --- a/src/ipv4.h +++ b/src/ipv4.h @@ -100,6 +100,7 @@ struct ipv4_addr { TAILQ_HEAD(ipv4_addrhead, ipv4_addr); #define IPV4_AF_STALE (1U << 0) +#define IPV4_AF_NEW (1U << 1) #define IPV4_ADDR_EQ(a1, a2) ((a1) && (a1)->addr.s_addr == (a2)->addr.s_addr) #define IPV4_MASK1_EQ(a1, a2) ((a1) && (a1)->mask.s_addr == (a2)->mask.s_addr)