Repository: moby/moby
File: libnetwork/osl/interface_linux.go (Go)

Code before:
	}
	return len(stpState) > 0 && stpState[0] != '0'
}

// advertiseAddrs triggers send unsolicited ARP and Neighbour Advertisement
// messages, so that caches are updated with the MAC address currently associated
// with the interface's IP addresses.
//
// IP addresses are recycled quickly when endpoints are dropped on network
// disconnect or container stop. A new MAC address may have been generated, so
// this is necessary to avoid packets sent to the old MAC address getting dropped
// until the ARP/Neighbour cache entries expire.
//
// Note that the kernel's arp_notify sysctl setting is not respected.
func (n *Namespace) advertiseAddrs(ctx context.Context, ifIndex int, i *Interface, nlh nlwrap.Handle) error {
	mac := i.MacAddress()
	address4 := i.Address()
	address6 := i.AddressIPv6()
	ctx = log.WithLogger(ctx, log.G(ctx).WithFields(log.Fields{
		"iface": i.dstName,
		"ifi":   ifIndex,
		"mac":   mac.String(),
		"ip4":   address4,
		"ip6":   address6,
	}))

	if address4 == nil && address6 == nil {
		// Nothing to do - for example, a bridge with no configured addresses.
		log.G(ctx).Debug("No IP addresses to advertise")
		return nil
	}
	if mac == nil {
		// Nothing to do - for example, a layer-3 ipvlan.
		log.G(ctx).Debug("No MAC address to advertise")
		return nil
	}
	if i.advertiseAddrNMsgs == 0 {
		log.G(ctx).Debug("Unsolicited ARP/NA is disabled")
		return nil
	}

	arpSender, naSender := n.prepAdvertiseAddrs(ctx, i, ifIndex)
	if arpSender == nil && naSender == nil {
		return nil
	}
	cleanup := func() {
		if arpSender != nil {
			arpSender.Close()
		}
		if naSender != nil {
			naSender.Close()

Review comment (suggestion):
Wondering if something like a ticker and/or `ctx, cancel := context.WithTimeout(200 * time.Millisecond)` would be something to consider?

I'm horrible at tickers though, as they always confuse me, but I think @vvoland is better at them 😂 🙈 

Code after:
		return false
	}
	return len(stpState) > 0 && stpState[0] != '0'
}

// waitForMcastRoute waits for an interface to have a route from ::1 to the IPv6 LL all-nodes
// address (ff02::1), if that route is needed to send a neighbour advertisement for an IPv6
// interface address.
//
// After waiting, or a failure, if there is no route - no error is returned. The NA send may
// fail, but try it anyway.
//
// In CI, the NA send failed with "write ip ::1->ff02::1: sendmsg: network is unreachable".
// That error has not been seen since addition of the check that the veth's parent bridge port
// is forwarding, so that may have been the issue. But, in case it's a timing problem that's
// only less-likely because of delay caused by that check, make sure the route exists.
func waitForMcastRoute(ctx context.Context, ifIndex int, i *Interface, nlh nlwrap.Handle) {
	if i.addressIPv6 == nil || i.advertiseAddrNMsgs == 0 {
		return
	}
	ctx, span := otel.Tracer("").Start(ctx, "libnetwork.osl.waitForMcastRoute")
	defer span.End()

	const pollInterval = 10 * time.Millisecond
	const maxWait = 200 * time.Millisecond
	for range int64(maxWait / pollInterval) {
		routes, err := nlh.RouteGetWithOptions(net.IPv6linklocalallnodes, &netlink.RouteGetOptions{
			IifIndex: ifIndex,
			SrcAddr:  net.IPv6loopback,
		})
		if errors.Is(err, unix.EMSGSIZE) {
			// FIXME(robmry) - if EMSGSIZE is returned (why?), it seems to be persistent.
			//  So, skip the delay and continue to the NA send as it seems to succeed.
			log.G(ctx).Info("Skipping check for route to send NA, EMSGSIZE")
			return
		}
		if err != nil || len(routes) == 0 {
			log.G(ctx).WithFields(log.Fields{"error": err, "nroutes": len(routes)}).Info("Waiting for route to send NA")
			time.Sleep(pollInterval)
			continue
		}
		return
	}
	log.G(ctx).WithField("", maxWait).Warn("No route for neighbour advertisement")
}

// advertiseAddrs triggers send unsolicited ARP and Neighbour Advertisement
// messages, so that caches are updated with the MAC address currently associated
// with the interface's IP addresses.
//
// IP addresses are recycled quickly when endpoints are dropped on network