⚙️ Silent Reachability Failure

MetalLB speaker Failing Gratuitous ARP: no such device or address

MetalLB gratuitous ARP failure occurs when the speaker daemonset cannot send an ARP announcement for a LoadBalancer IP because the network interface it is sending on does not exist or is down. The error is sendto: no such device or address. Without the announcement, upstream ARP caches keep pointing at whichever node last claimed the address, so traffic is delivered to a node that no longer owns it and disappears.

TL;DRIn layer 2 mode, one node claims each LoadBalancer IP and announces ownership by broadcasting gratuitous ARP. When the announcement fails, nothing on the Kubernetes side changes: the service has an IP, endpoints are Ready, and the speaker pod stays running. Only the network forgets who owns the address. Traffic follows a stale ARP entry to the wrong node and is dropped, producing connection timeouts that no pod, service, or probe can explain.

What does the MetalLB ARP announcement failure look like?

The speaker logs structured JSON, one entry per address per attempt:

{"caller":"announcer.go:210",
   "error":"writing \"OperationRequest\" gratuitous packet for \"10.30.40.201\":
    write packet ee:ee:ee:ee:ee:ee: sendto: no such device or address",
   "ip":"10.30.40.201","level":"error",
   "msg":"failed to make gratuitous ARP announcement",
   "op":"gratuitousAnnounce","ts":"2026-08-15T20:14:50Z"}
  

Two details are worth reading carefully.

sendto: no such device or address is the syscall failing, not the network rejecting the packet. This is ENXIO: the socket is bound to an interface that is not there. Nothing left the node.

The ip field varies across entries while everything else stays constant. A real occurrence produced forty errors in one minute across five distinct addresses, all from a single speaker pod on a single node. That shape identifies the failure as node-local rather than address-specific, which narrows the investigation immediately.

Not to be confused with Address pool exhaustion looks different and is easier to catch: the Service stays in Pending with no external IP, and the controller logs the allocation failure. Here allocation succeeded, the Service has its IP, and the failure is downstream at the announcement step. Check whether the Service has an external IP before assuming a pool problem.

Why does the interface disappear?

MetalLB in layer 2 mode elects one node per service IP. That node’s speaker sends gratuitous ARP so upstream switches and routers learn which MAC owns the address, and it re-announces periodically and on failover.

The announcement requires a raw socket on a specific interface. It fails when:

  1. The interface named in L2Advertisement does not exist on that node. A node built from a different image, a different NIC layout, or a cloud instance type with different device naming. This is the leading cause on mixed-hardware clusters.
  2. Predictable interface naming changed after a kernel or firmware update, so ens192 becomes ens161 and the selector no longer matches.
  3. A bond or VLAN interface went down, taking its children with it.
  4. A CNI restart removed and recreated interfaces, leaving the speaker’s socket bound to a device that no longer exists.
  5. The interface exists but is administratively down, so the kernel refuses the send.

Cause four explains the intermittent, self-resolving variant. The interface returns and announcements resume, so the incident closes without anyone acting, and then recurs the next time the CNI restarts.

Why is this dangerous rather than merely noisy?

Because every signal Kubernetes produces says the system is healthy.

  • The Service has an external IP. Allocation worked.
  • Endpoints are Ready. The backing pods are fine.
  • The speaker pod is Running. It logs the error and keeps going. No restart, no probe failure, no event.
  • Other nodes’ speakers are unaffected, so a cluster-wide view looks normal.

Meanwhile, upstream ARP caches hold whatever they learned last. If the previous owner node is still up, traffic goes there and is dropped because it no longer holds the address. If the entry ages out, the address becomes unreachable entirely. Either way, from the client side the symptom is a connection timeout to a service that Kubernetes reports as perfectly healthy, on a node that reports as perfectly healthy.

This is the failure mode most likely to consume an afternoon of application debugging before anyone looks at ARP.

How do I diagnose and fix it?

1. Identify the node from the speaker pod

kubectl -n metallb-system get pods -l app=metallb,component=speaker -o wide
  kubectl -n metallb-system logs <speaker-pod> --tail=100 | grep gratuitous
  

Errors from one pod and not its peers confirm a node-local problem.

2. Compare the configured interface against reality

kubectl -n metallb-system get l2advertisement -o yaml | grep -A 5 interfaces
  

Then on the affected node:

ip -br link show
  

A name in spec.interfaces with no match in ip link is the whole answer. Compare against a healthy node; different naming between nodes is the common finding.

3. Check interface state, not just existence

ip -br link show | grep -vE 'UP'
  

An interface that exists but is DOWN produces the same error as one that is absent.

4. Confirm the reachability impact

From a host on the same layer 2 segment:

arping -I <iface> 10.30.40.201
  ip neigh show 10.30.40.201
  

No reply, or a MAC belonging to a node that should not own the address, confirms the announcement never landed. This is the check that connects a log error to real impact.

5. Fix the selector or the interface

If node interface names differ, either omit spec.interfaces so MetalLB selects automatically, or split into per-node-selector L2Advertisement resources. Omitting is usually correct; the selector exists for multi-homed nodes, not as a default.

6. Force re-announcement

kubectl -n metallb-system rollout restart daemonset speaker
  

Announcements are periodic, so without a restart the corrected configuration may take a full interval to take effect and will look like it did not work.

7. Treat recurrence as the real signal

If this has happened before on the same node and self-resolved, the underlying cause is still present. The same pattern appearing twice eleven days apart on the same node is a configuration problem waiting for its next trigger, not two unrelated blips.

How does Dstl8 detect this?

A burst of forty errors lasting three seconds, from one daemonset pod, at a level most pipelines discard, ending before any evaluation window closes. Nothing restarts and no metric moves. Dstl8 baselines each service against its own history, so a pattern that was not there before registers regardless of how brief it is, and repeat occurrences are visible as a series rather than as isolated noise.

Real Detection
Powered by CONTROLTHEORY
Incident Resolved PLATFORM

speaker daemonset failing to make gratuitous ARP announcements

MetalLB speaker failing to make gratuitous ARP announcements for managed IP addresses, producing no such device or address errors that prevent address announcement. 40 errors in a one-minute window across 5 IP addresses, all from a single pod on a single worker node. Second occurrence of this pattern in 11 days. No alert rule configured.

Started
20:14
Aug 15
Span
3s
Severity
Minor
Events
3

A three-second failure is shorter than most evaluation intervals, which is why nothing conventional catches it. The detail that matters most is not the burst itself but that it was the second occurrence of the same pattern on the same node, which turns an ignorable blip into a standing configuration problem.

Frequently asked questions

What does sendto: no such device or address mean in MetalLB speaker?

The speaker tried to send a gratuitous ARP packet on a network interface that does not exist or is down. This is the ENXIO syscall error, meaning nothing left the node. Common causes are an interface named in L2Advertisement that is absent on that node, predictable naming changing after a kernel update, a bond or VLAN going down, or a CNI restart removing interfaces.

Why does my LoadBalancer service time out when everything looks healthy?

If MetalLB cannot send its gratuitous ARP announcement, upstream ARP caches keep pointing at whichever node last claimed the address. Traffic is delivered to a node that no longer owns the IP and is dropped. The Service has an external IP, endpoints are Ready, and the speaker pod is Running, so no Kubernetes signal reflects the failure.

Does MetalLB speaker restart when ARP announcements fail?

No. It logs the error and continues. There is no restart, no probe failure, and no Kubernetes event. Speakers on other nodes are unaffected, so a cluster-wide view looks entirely normal while one node’s addresses are unreachable.

Related patterns

References

Three seconds of errors. Hours of application debugging.

Dstl8 surfaces brief patterns that end before any evaluation window closes, and shows you when the same one has happened before. No rules to write, no thresholds to tune.

Start Free 14-Day Trial →