shelly-manager resolves Shelly *.local names over mDNS. The queries leave on the pod's default interface eth0 to 224.0.0.251:5353, which the egress lockdown (#1432) does not allow. Hubble shows them as Policy denied (home-assistant/shelly-manager → 224.0.0.251:5353 world-ipv4), and since 15:07Z shelly-manager logs HttpRequestException: Name or service not known (shellyplug-s-4382e5.local:80) and similar.
Adds 224.0.0.251/32 UDP 5353 to shelly-manager-egress. IPv4 only: the mDNS library (Zeroconf) never uses ff02::fb (shelly-manager-mdns-library-replacement-decision), and the IPv6 drops Hubble shows are Invalid source ip, not policy.
Validation: kubectl apply --dry-run=server passes. After merge: the Hubble drops stop and the .local errors in the shelly-manager log stop.
shelly-manager resolves Shelly `*.local` names over mDNS. The queries leave on the pod's default interface `eth0` to `224.0.0.251:5353`, which the egress lockdown (#1432) does not allow. Hubble shows them as `Policy denied` (`home-assistant/shelly-manager → 224.0.0.251:5353 world-ipv4`), and since 15:07Z shelly-manager logs `HttpRequestException: Name or service not known (shellyplug-s-4382e5.local:80)` and similar.
Adds `224.0.0.251/32` UDP 5353 to `shelly-manager-egress`. IPv4 only: the mDNS library (Zeroconf) never uses `ff02::fb` ([[shelly-manager-mdns-library-replacement-decision]]), and the IPv6 drops Hubble shows are `Invalid source ip`, not policy.
Validation: `kubectl apply --dry-run=server` passes. After merge: the Hubble drops stop and the `.local` errors in the shelly-manager log stop.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
shelly-manager resolves device *.local names via mDNS; the queries leave on
eth0 to 224.0.0.251:5353 and have been dropped since the egress lockdown
(#1432), failing with 'Name or service not known' since 15:07Z.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🤖Automated review — model claude-opus-5-5, commit 9bcc1cb420335f5ab7a404f18e781707d75c7112.
Automated review by the review-bot: it approves only when it found nothing red or yellow, and a human still merges. Push new commits to get a fresh review.
Summary
This PR adds 224.0.0.251/32 UDP 5353 egress to shelly-manager-egress so the mDNS queries that #1432 now drops can leave on eth0. The PR is mergeable against main at b10b50f. The file on main is the post-#1432 version (merged at 14:50Z as b341b26), and no other open PR touches it. The rule itself is small and well scoped, but the repo's own manifests indicate that mDNS sent on eth0 cannot reach the IoT VLAN. So this will probably silence the Hubble drops without fixing the .local errors it is meant to fix.
⚪ Unverified
The diagnosis probably does not explain the outage. These rules in the repo all suggest the new rule at kubernetes/infrastructure/network-policies/home-assistant-ns.yaml:381-386 will not restore resolution:
Multicast on eth0 reaches nothing.kubernetes/apps/home-assistant-iot/mdns-relay-deployment.yaml:5-7 says Cilium runs "in tunnel mode without enable-multicast, so re-emitted multicast is dropped by the CNI". Lines 12-13 say "HA-initiated browsing still dies on eth0".
net1 exists to work around exactly that.shelly-manager-deployment.yaml:28-32 and shelly-manager-network-attachment.yaml:2-8 give shelly-manager a macvlan net1 on v30iot because "multicast doesn't cross the L3 boundary" from the pod CIDR. shelly-manager-deployment.yaml:38-40 adds that "macvlan traffic bypasses Cilium policy entirely", so the queries that can actually reach Shellies were never affected by this CNP.
The eth0 copies were always dead traffic. Before #1432, the namespace-wide world allow just let them die later instead of showing as Policy denied.
The error points elsewhere. In shelly-manager's src/ShellyManager.Web/Shelly/MdnsConnectCallback.cs (ConnectAsync, read on main), .local hosts are resolved first as <id>.iot.renner.uno through the system resolver (ShellyManager__DnsSuffix, shelly-manager-deployment.yaml:88-89). Only then does it fall back to the mDNS cache. It throws SocketException(HostNotFound) ("Name or service not known") only when neither path produced a single candidate. A blocked TCP connect would surface as a timeout instead.
Where to look instead. It is worth checking the suffix lookup (e.g. getent hosts shellyplug-s-4382e5.iot.renner.uno from the pod) and whether net1 is attached with a DHCP lease. I could not observe the cluster. This rests on the repo's own documentation of Cilium's multicast mode, not on live behaviour.
The IPv4-only reasoning cites the wrong library. The PR body says the mDNS library is Zeroconf and "never uses ff02::fb". But shelly-manager replaced Zeroconf with dual-stack MeaMod.DNS on 2026-07-25 (commit ac64514, "Zeroconf … never joined FF02::FB … Replace it with MeaMod.DNS"). ShellyManager.Web.csproj references MeaMod.DNS 1.0.71. The deployed tag build.1792387459 decodes as a Unix time to about mid-October 2026, well after that change. I could not map the tag to a commit. If the eth0 path mattered, the v6 group would matter too. The Hubble "Invalid source ip" note in the body may still be accurate.
🟡 Suggestions
home-assistant-ns.yaml:381-386: before merging, check that this rule actually fixes the symptom, not just the Hubble drop count. The body's own post-merge check ("the .local errors … stop") is the right test. If the errors continue, the cause is the suffix lookup or net1, and this rule only reduces drop noise. If keeping it for noise reduction is the intent, say so in the PR and the comment.
🟢 Nits
home-assistant-ns.yaml:363-364: "mDNS queries for their *.local names (sent out the default interface eth0)" reads as though the eth0 path is how resolution works. That contradicts mdns-relay-deployment.yaml:12-13. If the rule stays, a wording like "suppresses drops of the eth0 copy; resolution uses net1, which bypasses Cilium" would keep the next reader from relying on it.
Tests
Manifest-only change. The repo has no policy tests, and the server-side dry-run in the body covers syntax. The real check is the runtime one described above.
Recommendation
Looks reasonable — no blocking issues. The rule is narrow and harmless, but please confirm it actually fixes the .local failures before relying on it as the fix.
🤖 **Automated review** — model `claude-opus-5-5`, commit `9bcc1cb420335f5ab7a404f18e781707d75c7112`.
> Automated review by the `review-bot`: it approves only when it found nothing red or yellow, and a human still merges. Push new commits to get a fresh review.
---
## Summary
This PR adds `224.0.0.251/32` UDP 5353 egress to `shelly-manager-egress` so the mDNS queries that #1432 now drops can leave on `eth0`. The PR is mergeable against `main` at `b10b50f`. The file on `main` is the post-#1432 version (merged at 14:50Z as `b341b26`), and no other open PR touches it. The rule itself is small and well scoped, but the repo's own manifests indicate that mDNS sent on `eth0` cannot reach the IoT VLAN. So this will probably silence the Hubble drops without fixing the `.local` errors it is meant to fix.
## ⚪ Unverified
- **The diagnosis probably does not explain the outage.** These rules in the repo all suggest the new rule at `kubernetes/infrastructure/network-policies/home-assistant-ns.yaml:381-386` will not restore resolution:
- **Multicast on `eth0` reaches nothing.** `kubernetes/apps/home-assistant-iot/mdns-relay-deployment.yaml:5-7` says Cilium runs "in tunnel mode without enable-multicast, so re-emitted multicast is dropped by the CNI". Lines 12-13 say "HA-initiated browsing still dies on eth0".
- **`net1` exists to work around exactly that.** `shelly-manager-deployment.yaml:28-32` and `shelly-manager-network-attachment.yaml:2-8` give shelly-manager a macvlan `net1` on v30iot because "multicast doesn't cross the L3 boundary" from the pod CIDR. `shelly-manager-deployment.yaml:38-40` adds that "macvlan traffic bypasses Cilium policy entirely", so the queries that can actually reach Shellies were never affected by this CNP.
- **The `eth0` copies were always dead traffic.** Before #1432, the namespace-wide `world` allow just let them die later instead of showing as `Policy denied`.
- **The error points elsewhere.** In shelly-manager's `src/ShellyManager.Web/Shelly/MdnsConnectCallback.cs` (`ConnectAsync`, read on `main`), `.local` hosts are resolved first as `<id>.iot.renner.uno` through the system resolver (`ShellyManager__DnsSuffix`, `shelly-manager-deployment.yaml:88-89`). Only then does it fall back to the mDNS cache. It throws `SocketException(HostNotFound)` ("Name or service not known") only when neither path produced a single candidate. A blocked TCP connect would surface as a timeout instead.
- **Where to look instead.** It is worth checking the suffix lookup (e.g. `getent hosts shellyplug-s-4382e5.iot.renner.uno` from the pod) and whether `net1` is attached with a DHCP lease. I could not observe the cluster. This rests on the repo's own documentation of Cilium's multicast mode, not on live behaviour.
- **The IPv4-only reasoning cites the wrong library.** The PR body says the mDNS library is Zeroconf and "never uses ff02::fb". But shelly-manager replaced Zeroconf with dual-stack MeaMod.DNS on 2026-07-25 (commit `ac64514`, "Zeroconf … never joined FF02::FB … Replace it with MeaMod.DNS"). `ShellyManager.Web.csproj` references `MeaMod.DNS` 1.0.71. The deployed tag `build.1792387459` decodes as a Unix time to about mid-October 2026, well after that change. I could not map the tag to a commit. If the `eth0` path mattered, the v6 group would matter too. The Hubble "Invalid source ip" note in the body may still be accurate.
## 🟡 Suggestions
- `home-assistant-ns.yaml:381-386`: before merging, check that this rule actually fixes the symptom, not just the Hubble drop count. The body's own post-merge check ("the `.local` errors … stop") is the right test. If the errors continue, the cause is the suffix lookup or `net1`, and this rule only reduces drop noise. If keeping it for noise reduction is the intent, say so in the PR and the comment.
## 🟢 Nits
- `home-assistant-ns.yaml:363-364`: "mDNS queries for their *.local names (sent out the default interface eth0)" reads as though the `eth0` path is how resolution works. That contradicts `mdns-relay-deployment.yaml:12-13`. If the rule stays, a wording like "suppresses drops of the eth0 copy; resolution uses net1, which bypasses Cilium" would keep the next reader from relying on it.
## Tests
Manifest-only change. The repo has no policy tests, and the server-side dry-run in the body covers syntax. The real check is the runtime one described above.
## Recommendation
Looks reasonable — no blocking issues. The rule is narrow and harmless, but please confirm it actually fixes the `.local` failures before relying on it as the fix.
<!-- pr-review:sha=9bcc1cb420335f5ab7a404f18e781707d75c7112 -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
shelly-manager resolves Shelly
*.localnames over mDNS. The queries leave on the pod's default interfaceeth0to224.0.0.251:5353, which the egress lockdown (#1432) does not allow. Hubble shows them asPolicy denied(home-assistant/shelly-manager → 224.0.0.251:5353 world-ipv4), and since 15:07Z shelly-manager logsHttpRequestException: Name or service not known (shellyplug-s-4382e5.local:80)and similar.Adds
224.0.0.251/32UDP 5353 toshelly-manager-egress. IPv4 only: the mDNS library (Zeroconf) never usesff02::fb(shelly-manager-mdns-library-replacement-decision), and the IPv6 drops Hubble shows areInvalid source ip, not policy.Validation:
kubectl apply --dry-run=serverpasses. After merge: the Hubble drops stop and the.localerrors in the shelly-manager log stop.🤖 Generated with Claude Code
🤖 Automated review — model
claude-opus-5-5, commit9bcc1cb420335f5ab7a404f18e781707d75c7112.Summary
This PR adds
224.0.0.251/32UDP 5353 egress toshelly-manager-egressso the mDNS queries that #1432 now drops can leave oneth0. The PR is mergeable againstmainatb10b50f. The file onmainis the post-#1432 version (merged at 14:50Z asb341b26), and no other open PR touches it. The rule itself is small and well scoped, but the repo's own manifests indicate that mDNS sent oneth0cannot reach the IoT VLAN. So this will probably silence the Hubble drops without fixing the.localerrors it is meant to fix.⚪ Unverified
kubernetes/infrastructure/network-policies/home-assistant-ns.yaml:381-386will not restore resolution:eth0reaches nothing.kubernetes/apps/home-assistant-iot/mdns-relay-deployment.yaml:5-7says Cilium runs "in tunnel mode without enable-multicast, so re-emitted multicast is dropped by the CNI". Lines 12-13 say "HA-initiated browsing still dies on eth0".net1exists to work around exactly that.shelly-manager-deployment.yaml:28-32andshelly-manager-network-attachment.yaml:2-8give shelly-manager a macvlannet1on v30iot because "multicast doesn't cross the L3 boundary" from the pod CIDR.shelly-manager-deployment.yaml:38-40adds that "macvlan traffic bypasses Cilium policy entirely", so the queries that can actually reach Shellies were never affected by this CNP.eth0copies were always dead traffic. Before #1432, the namespace-wideworldallow just let them die later instead of showing asPolicy denied.src/ShellyManager.Web/Shelly/MdnsConnectCallback.cs(ConnectAsync, read onmain),.localhosts are resolved first as<id>.iot.renner.unothrough the system resolver (ShellyManager__DnsSuffix,shelly-manager-deployment.yaml:88-89). Only then does it fall back to the mDNS cache. It throwsSocketException(HostNotFound)("Name or service not known") only when neither path produced a single candidate. A blocked TCP connect would surface as a timeout instead.getent hosts shellyplug-s-4382e5.iot.renner.unofrom the pod) and whethernet1is attached with a DHCP lease. I could not observe the cluster. This rests on the repo's own documentation of Cilium's multicast mode, not on live behaviour.ac64514, "Zeroconf … never joined FF02::FB … Replace it with MeaMod.DNS").ShellyManager.Web.csprojreferencesMeaMod.DNS1.0.71. The deployed tagbuild.1792387459decodes as a Unix time to about mid-October 2026, well after that change. I could not map the tag to a commit. If theeth0path mattered, the v6 group would matter too. The Hubble "Invalid source ip" note in the body may still be accurate.🟡 Suggestions
home-assistant-ns.yaml:381-386: before merging, check that this rule actually fixes the symptom, not just the Hubble drop count. The body's own post-merge check ("the.localerrors … stop") is the right test. If the errors continue, the cause is the suffix lookup ornet1, and this rule only reduces drop noise. If keeping it for noise reduction is the intent, say so in the PR and the comment.🟢 Nits
home-assistant-ns.yaml:363-364: "mDNS queries for their *.local names (sent out the default interface eth0)" reads as though theeth0path is how resolution works. That contradictsmdns-relay-deployment.yaml:12-13. If the rule stays, a wording like "suppresses drops of the eth0 copy; resolution uses net1, which bypasses Cilium" would keep the next reader from relying on it.Tests
Manifest-only change. The repo has no policy tests, and the server-side dry-run in the body covers syntax. The real check is the runtime one described above.
Recommendation
Looks reasonable — no blocking issues. The rule is narrow and harmless, but please confirm it actually fixes the
.localfailures before relying on it as the fix.