Skip to content

Commit

Permalink
Announce IPv4 addresses (GARP) before IPv6 NA
Browse files Browse the repository at this point in the history
To announce IPv6 addresses, SendUnsolicitedNeighborAdvertisement()
possibly needs to wait for tentative IPv6 addresses to become usable
(DAD). This can take more than a second.

Instead of looping over IPv4 and IPv6 addresses together, split the
loop. Iterate first over IPv4 addresses, which potentially can complete
fast without waiting.

While at it, don't let the first error shortcut the announcement of
future addresses. Loop over all addresses, but return the first error we
encountered. The caller anyway ignores the error and only uses it for
debug logging.
  • Loading branch information
thom311 committed Jul 31, 2024
1 parent fff0e1d commit ca6eccc
Showing 1 changed file with 19 additions and 11 deletions.
30 changes: 19 additions & 11 deletions pkg/utils/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,28 +197,36 @@ func AnnounceIPs(ifName string, ipConfigs []*current.IPConfig) error {
return fmt.Errorf("invalid Ethernet MAC address: %q", linkObj.Attrs().HardwareAddr)
}

var errResult error

retryUntil := time.Now().Add(3000 * time.Millisecond)

// For all the IP addresses assigned by IPAM, we will send either a GARP (IPv4) or Unsolicited NA (IPv6).
//
// Note that SendUnsolicitedNeighborAdvertisement() can wait for tentative
// IPv6 addresses. We thus first iterate over the IPv4 addresses to not
// delay announcing those.
for _, ipc := range ipConfigs {
if IsIPv4(ipc.Address.IP) {
err := SendGratuitousArp(ipc.Address.IP, linkObj)
if err != nil && errResult == nil {
errResult = fmt.Errorf("failed to send GARP message for ip %s on interface %q: %v", ipc.Address.IP.String(), ifName, err)
}
}
}
for _, ipc := range ipConfigs {
var err error
if IsIPv6(ipc.Address.IP) {
/* As per RFC 4861, sending unsolicited neighbor advertisements should be considered as a performance
* optimization. It does not reliably update caches in all nodes. The Neighbor Unreachability Detection
* algorithm is more reliable although it may take slightly longer to update.
*/
err = SendUnsolicitedNeighborAdvertisement(ipc.Address.IP, linkObj, retryUntil)
} else if IsIPv4(ipc.Address.IP) {
err = SendGratuitousArp(ipc.Address.IP, linkObj)
} else {
return fmt.Errorf("the IP %s on interface %q is neither IPv4 or IPv6", ipc.Address.IP.String(), ifName)
}

if err != nil {
return fmt.Errorf("failed to send GARP/NA message for ip %s on interface %q: %v", ipc.Address.IP.String(), ifName, err)
err := SendUnsolicitedNeighborAdvertisement(ipc.Address.IP, linkObj, retryUntil)
if err != nil && errResult == nil {
errResult = fmt.Errorf("failed to send NA message for ip %s on interface %q: %v", ipc.Address.IP.String(), ifName, err)
}
}
}
return nil
return errResult
}

// Blocking wait for interface ifName to have carrier (!NO_CARRIER flag).
Expand Down

0 comments on commit ca6eccc

Please sign in to comment.