Skip to content

atenet: bind the Envoy sockets and Services dual-stack - #911

Open
Yuan Gao (ygao-g) wants to merge 2 commits into
agent-substrate:mainfrom
ygao-g:atenet-envoy-dualstack
Open

atenet: bind the Envoy sockets and Services dual-stack#911
Yuan Gao (ygao-g) wants to merge 2 commits into
agent-substrate:mainfrom
ygao-g:atenet-envoy-dualstack

Conversation

@ygao-g

@ygao-g Yuan Gao (ygao-g) commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Fixes #910
Part of #246

It's a good idea to open an issue first for discussion.

  • Tests pass
  • Appropriate changes to documentation are included in the PR (none needed — no flags, APIs, or user-facing behaviour change)

The router and egress manifests bind the IPv4 wildcard on every Envoy socket, and neither gateway's Service asks for a second IP family. On a dual-stack cluster the router answers on its IPv4 ClusterIP and on nothing at all for IPv6; on an IPv6-primary cluster the kubelet cannot probe the pod on its only address, so atenet-egress crashloops while Envoy itself starts fine.

Both gateways now bind :: as well, and both Services ask for PreferDualStack. A new hack/verify check guards the ipv4_compat flag that the in-pod loopback callers depend on, since nothing else in the tree reads these manifests. The experimental atenet-egress-with-sdsmint.yaml variant is deliberately out of scope.

This makes both gateways accept IPv6; it does not make them reach IPv6 destinations. The egress dns_lookup_family, the DNS AAAA path, and atunnel's original-destination lookup stay IPv4, and are tracked in #246 and #686.

Testing

CI has no IP-family matrix, so the green e2e run here is the IPv4 regression check and nothing more. The other two families were verified by hand on kind, using IP_FAMILY from #877.

  • Dual-stack. The networking suite passes with zero skips: an actor is reached over each of the router's ClusterIPs, and an IPv4 actor transits the egress [::]:443 socket. Reverting only the two bind lines turns those assertions red, so they are not passing vacuously. ipv4_compat was read from /config_dump/listeners never emits it.
  • IPv6-only, with the kind CoreDNS fix from hack: fix DNS on IPv6-only kind clusters #958 underneath. atenet-egress goes from 1/2 CrashLoopBackOff (64 restarts, startup probe refused) to 2/2 Running, and TestActorDirectAccess passes, including through the router's ingress. TestActorEgress still fails inside the actor's netns, which is ateomnet: enable IPv6 forwarding in worker pod netns #979's scope.

🤖 Generated with Claude Code

@ygao-g

Copy link
Copy Markdown
Collaborator Author

Bowei Du (@bowei) mind taking a look?

Comment thread cmd/atenet/internal/router/xds.go
@ygao-g
Yuan Gao (ygao-g) force-pushed the atenet-envoy-dualstack branch 2 times, most recently from 5257d6b to 580afef Compare August 18, 2026 14:59
@ygao-g Yuan Gao (ygao-g) changed the title atenet: bind the Envoy listeners, admin sockets, and Services dual-stack atenet: bind the Envoy sockets and Services dual-stack Aug 18, 2026
@ygao-g Yuan Gao (ygao-g) added kind/bug Something isn't working / bugfixes area/network labels Aug 18, 2026
@ygao-g
Yuan Gao (ygao-g) force-pushed the atenet-envoy-dualstack branch 3 times, most recently from 378c535 to 5c35bdc Compare August 19, 2026 03:40
@ygao-g
Yuan Gao (ygao-g) force-pushed the atenet-envoy-dualstack branch 3 times, most recently from 24055c6 to 6c1910d Compare August 19, 2026 22:58
Comment thread cmd/atenet/internal/router/dataplane.go Outdated
Comment thread cmd/atenet/internal/router/xds.go Outdated
Comment thread manifests/ate-install/atenet-egress.yaml Outdated
The router and egress manifests bind the IPv4 wildcard on every Envoy
socket, and neither gateway's Service asks for a second IP family. On a
dual-stack cluster the router answers on its IPv4 ClusterIP and on
nothing at all for IPv6; on an IPv6-primary cluster the kubelet cannot
probe the pod on its only address, so atenet-egress crashloops while
Envoy itself starts fine.

Both gateways now bind `::` as well and ask for PreferDualStack. That
makes them accept IPv6, not reach it: the egress dns_lookup_family, the
DNS AAAA path, and atunnel's original-destination lookup stay IPv4. The
experimental sdsmint egress variant is untouched.
Yuan Gao (ygao-g) added a commit to ygao-g/substrate that referenced this pull request Aug 20, 2026
Nothing checked that the router's dataplane listeners bind more than an
IPv4 socket, and nothing reached an actor over the router's IPv6
ClusterIP. Every other path a test has into the router -- a
port-forward, the pods/proxy and services/proxy subresources -- is
mediated by the API server, which picks the family, so no existing test
could have caught a listener that lost its IPv6 socket. Reads the bound
addresses from Envoy's own admin /listeners, and drives an in-cluster
probe pod at the router over each ClusterIP in turn.

Red until agent-substrate#911 binds those sockets, so this stays a draft until then.
The per-family probe skips on a single-stack cluster. Part of agent-substrate#246.
Yuan Gao (ygao-g) added a commit to ygao-g/substrate that referenced this pull request Aug 20, 2026
Nothing checked that the router's dataplane listeners bind more than an
IPv4 socket, and nothing reached an actor over the router's IPv6
ClusterIP. Every other path a test has into the router -- a
port-forward, the pods/proxy and services/proxy subresources -- is
mediated by the API server, which picks the family, so no existing test
could have caught a listener that lost its IPv6 socket. Reads the bound
addresses from Envoy's own admin /listeners, and drives an in-cluster
probe pod at the router over each ClusterIP in turn.

Red until agent-substrate#911 binds those sockets, so this stays a draft until then.
The per-family probe skips on a single-stack cluster. Part of agent-substrate#246.
Yuan Gao (ygao-g) added a commit to ygao-g/substrate that referenced this pull request Aug 21, 2026
Nothing checked that the router's dataplane listeners bind more than an
IPv4 socket, and nothing reached an actor over the router's IPv6
ClusterIP. Every other path a test has into the router -- a
port-forward, the pods/proxy and services/proxy subresources -- is
mediated by the API server, which picks the family, so no existing test
could have caught a listener that lost its IPv6 socket. Reads the bound
addresses from Envoy's own admin /listeners, and drives an in-cluster
probe pod at the router over each ClusterIP in turn.

Red until agent-substrate#911 binds those sockets, so this stays a draft until then.
The per-family probe skips on a single-stack cluster. Part of agent-substrate#246.
Yuan Gao (ygao-g) added a commit to ygao-g/substrate that referenced this pull request Aug 21, 2026
The rcode assertions in the previous commit prove the zone stops failing
an AAAA query, not that it ever answers one. Nothing checks that the
record the zone does publish is the router's IPv6 ClusterIP, so agent-substrate#938
could regress to an empty answer and every existing test would still be
green.

Kept separate from TestActorDNSZone because it is the only assertion
here whose expected result changes with the cluster: it skips wherever
atenet-router has a single ClusterIP, which is every cluster until agent-substrate#911
gives the Service a dual-stack policy. Part of agent-substrate#246.
Yuan Gao (ygao-g) added a commit to ygao-g/substrate that referenced this pull request Aug 21, 2026
Nothing checked that the router's dataplane listeners bind more than an
IPv4 socket, and nothing reached an actor over the router's IPv6
ClusterIP. Every other path a test has into the router -- a
port-forward, the pods/proxy and services/proxy subresources -- is
mediated by the API server, which picks the family, so no existing test
could have caught a listener that lost its IPv6 socket. Reads the bound
addresses from Envoy's own admin /listeners, and drives an in-cluster
probe pod at the router over each ClusterIP in turn.

Red until agent-substrate#911 binds those sockets, so this stays a draft until then.
The per-family probe skips on a single-stack cluster. Part of agent-substrate#246.
Yuan Gao (ygao-g) added a commit to ygao-g/substrate that referenced this pull request Aug 21, 2026
Nothing checked that the router's dataplane listeners bind more than an
IPv4 socket, and nothing reached an actor over the router's IPv6
ClusterIP. Every other path a test has into the router -- a
port-forward, the pods/proxy and services/proxy subresources -- is
mediated by the API server, which picks the family, so no existing test
could have caught a listener that lost its IPv6 socket. Reads the bound
addresses from Envoy's own admin /listeners, and drives an in-cluster
probe pod at the router over each ClusterIP in turn.

Red until agent-substrate#911 binds those sockets, so this stays a draft until then.
The per-family probe skips on a single-stack cluster. Part of agent-substrate#246.
Comment thread hack/verify/atenet-admin-bind.sh Outdated
@@ -0,0 +1,86 @@
#!/usr/bin/env bash

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this script used for

I think we should just rely on e2e tests to tell us that IPv6 is working.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed. CI does catch it on the egress side — the kubelet probes that admin port, so dropping ipv4_compat means the pod never goes Ready and every run turns red. The router's admin port has no such probe, and the drain reads a refused dial as "Envoy already exited", so I dropped the dependency instead of guarding it: the in-pod callers dial localhost now, with a unit test against an IPv6-only loopback listener.

@bowei

Copy link
Copy Markdown
Collaborator

Changes look ok, but can we remove the extra script?

The router's dataplane health check and the drain sequence dial the
Envoy admin interface on the IPv4 loopback, which now depends on the
admin socket keeping ipv4_compat set alongside its `::` bind. Losing
that fails silently: the drain reads the refused dial as "Envoy already
exited" and reports a drain it never performed.

Both callers now dial localhost, which resolves to either loopback, so
the drain no longer depends on how the socket is spelled. ipv4_compat
stays for the egress kubelet probe, where a regression turns any IPv4
run red on the spot.
@ygao-g

Copy link
Copy Markdown
Collaborator Author

Done. The in-pod callers now dial localhost so nothing quietly depends on ipv4_compat; reasoning in the thread on the file.

Yuan Gao (ygao-g) added a commit to ygao-g/substrate that referenced this pull request Aug 21, 2026
The rcode assertions in the previous commit prove the zone stops failing
an AAAA query, not that it ever answers one. Nothing checks that the
record the zone does publish is the router's IPv6 ClusterIP, so agent-substrate#938
could regress to an empty answer and every existing test would still be
green.

Kept separate from TestActorDNSZone because it is the only assertion
here whose expected result changes with the cluster: it skips wherever
atenet-router has a single ClusterIP, which is every cluster until agent-substrate#911
gives the Service a dual-stack policy. Part of agent-substrate#246.
Yuan Gao (ygao-g) added a commit to ygao-g/substrate that referenced this pull request Aug 21, 2026
Nothing checked that the router's dataplane listeners bind more than an
IPv4 socket, and nothing reached an actor over the router's IPv6
ClusterIP. Every other path a test has into the router -- a
port-forward, the pods/proxy and services/proxy subresources -- is
mediated by the API server, which picks the family, so no existing test
could have caught a listener that lost its IPv6 socket. Reads the bound
addresses from Envoy's own admin /listeners, and drives an in-cluster
probe pod at the router over each ClusterIP in turn.

Red until agent-substrate#911 binds those sockets, so this stays a draft until then.
The per-family probe skips on a single-stack cluster. Part of agent-substrate#246.
Yuan Gao (ygao-g) added a commit to ygao-g/substrate that referenced this pull request Aug 21, 2026
Nothing checked that the router's dataplane listeners bind more than an
IPv4 socket, and nothing reached an actor over the router's IPv6
ClusterIP. Every other path a test has into the router -- a
port-forward, the pods/proxy and services/proxy subresources -- is
mediated by the API server, which picks the family, so no existing test
could have caught a listener that lost its IPv6 socket. Reads the bound
addresses from Envoy's own admin /listeners, and drives an in-cluster
probe pod at the router over each ClusterIP in turn.

Red until agent-substrate#911 binds those sockets, so this stays a draft until then.
The per-family probe skips on a single-stack cluster. Part of agent-substrate#246.
@ygao-g
Yuan Gao (ygao-g) removed the request for review from haiyanmeng August 21, 2026 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/network kind/bug Something isn't working / bugfixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

atenet Envoy sockets and Services lack IPv6 support (hardcoded to 0.0.0.0)

2 participants