Skip to content

neutron: document DNS resolution for OVN - #1041

Open
ideaship wants to merge 1 commit into
mainfrom
doc-gap-ovn-dns
Open

ideaship wants to merge 1 commit into
mainfrom
doc-gap-ovn-dns

Conversation

@ideaship

@ideaship ideaship commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

What

Adds a DNS Resolution for Instances (OVN) section to the Neutron configuration guide, documenting which DNS servers Neutron hands to instances and how to control them on an OSISM deployment.

Why

The precedence itself is upstream-documented — subnet dns_nameservers, then dns_servers in the [ovn] section, then the resolvers of the host running neutron-server. The third level is the problem, and nothing in the guide says so.

osism.commons.resolvconf points /etc/resolv.conf at the systemd-resolved stub (127.0.0.53) and keeps the real upstream resolvers in resolved.conf. Syntactic validity is the only test Neutron applies to the entries it reads there, so the loopback stub passes, and the containers run in the host network namespace — 127.0.0.53 is what reaches the instances, where it resolves nothing. An instance on a subnet without dns_nameservers then has no working DNS at all, internal name resolution included.

The failure is silent on both DHCP paths: for IPv4 Neutron warns only when it finds no resolver, and the stub is a valid address; the DHCPv6 path omits the option without warning either way.

How

  • States the three-level precedence, notes that levels 2 and 3 are filtered by the subnet's IP version while level 1 is not, and links the upstream admin guide.
  • Names per-subnet dns_nameservers as the recommended approach.
  • Explains why the host-resolvers level does not work on OSISM, and gives the deployment-wide fix via environments/kolla/files/overlays/neutron/ml2_conf.ini.
  • Covers three behaviours an operator meets after setting the option: an IPv4-only list leaves IPv6 subnets with no resolver at all; 0.0.0.0 / :: suppress the DHCP option, but only as the sole remaining entry for that IP version; and a changed [ovn] dns_servers does not reach subnets that already exist, because neutron_sync_mode defaults to log.
  • Notes that neutron_dnsmasq_dns_servers, which defaults to public resolvers, applies only to the ML2/OVS DHCP agent and has no effect under OVN.

Verification

Checked against a live OVN deployment, not only against the source:

  • neutron_server runs with NetworkMode: host, and /etc/resolv.conf inside the container is nameserver 127.0.0.53 — the exact file Neutron reads for level 3.
  • A tenant subnet with empty dns_nameservers received dns_server="{9.9.9.9, 149.112.112.9}" from [ovn] dns_servers; its IPv6 sibling received no dns_server key at all, the config list being IPv4-only.
  • After changing [ovn] dns_servers and restarting neutron-server on all three control nodes, existing subnets kept their old resolvers across six minutes with no API activity; a subnet created afterwards got the new ones; a subnet update then flipped the existing one. An update that changes no attribute has no effect — the client sends no request and still exits successfully.

Markdown-only addition to an existing page; yarn build has not been run locally.

Related

Top of a two-PR stack. This section cross-references Customization of the service configurations, which the PR below repairs, so that one merges first:

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown

MegaLinter analysis: Success

Descriptor Linter Files Fixed Errors Max errors Warnings Elapsed time
✅ ACTION actionlint 5 0 0 0.08s
✅ JSON jsonlint 4 0 0 0.08s
✅ JSON prettier 4 0 0 0.35s
✅ JSON v8r 4 0 0 7.79s
✅ MARKDOWN markdownlint 169 0 0 2.36s
✅ MARKDOWN markdown-table-formatter 169 0 0 0.36s
✅ REPOSITORY betterleaks yes no no 0.68s
✅ REPOSITORY checkov yes no no 17.21s
✅ REPOSITORY git_diff yes no no 0.1s
✅ REPOSITORY secretlint yes no no 3.27s
✅ REPOSITORY trufflehog yes no no 4.58s
✅ SPELL codespell 179 0 0 0.62s
✅ SPELL lychee 179 0 0 41.41s
✅ YAML prettier 6 0 0 0.34s
✅ YAML v8r 6 0 0 7.96s
✅ YAML yamllint 6 0 0 0.47s

See detailed reports in MegaLinter artifacts

Your project could benefit from a custom flavor, which would allow you to run only the linters you need, and thus improve runtime performances. (Skip this info by defining FLAVOR_SUGGESTIONS: false)

  • Documentation: Custom Flavors
  • Command: npx mega-linter-runner@10.0.0 --custom-flavor-setup --custom-flavor-linters ACTION_ACTIONLINT,JSON_JSONLINT,JSON_V8R,JSON_PRETTIER,MARKDOWN_MARKDOWNLINT,MARKDOWN_MARKDOWN_TABLE_FORMATTER,REPOSITORY_CHECKOV,REPOSITORY_GIT_DIFF,REPOSITORY_BETTERLEAKS,REPOSITORY_SECRETLINT,REPOSITORY_TRUFFLEHOG,SPELL_LYCHEE,SPELL_CODESPELL,YAML_PRETTIER,YAML_YAMLLINT,YAML_V8R

MegaLinter is provided by OX Security
Show us your support by starring ⭐ the repository

@garloff

garloff commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Ideally, we'd have an optional setting in https://github.com/openstack/kolla-ansible/blob/master/ansible/roles/neutron/templates/ml2_conf.ini.j2, no?
If we don't, we'd need to create a full drop-in replacement as overlay, which I always want to avoid (as it kills robustness and flexibility and introduces the risk for errors -- or did I overlook some intelligent merge strategy for config files ...?)

@ideaship

Copy link
Copy Markdown
Contributor Author

Ideally, we'd have an optional setting in https://github.com/openstack/kolla-ansible/blob/master/ansible/roles/neutron/templates/ml2_conf.ini.j2, no? If we don't, we'd need to create a full drop-in replacement as overlay, which I always want to avoid (as it kills robustness and flexibility and introduces the risk for errors -- or did I overlook some intelligent merge strategy for config files ...?)

kolla's merge_configs already merges custom configs. Having the two lines as documented in the file is sufficient.

@ideaship
ideaship changed the base branch from main to doc-gap-overlay-exact-names August 30, 2026 11:24
@ideaship
ideaship force-pushed the doc-gap-ovn-dns branch 2 times, most recently from 3c2f8f4 to 3313e7c Compare August 30, 2026 11:29
@ideaship ideaship moved this from In progress to Ready for review in Human Board Aug 30, 2026
@ideaship
ideaship marked this pull request as ready for review August 30, 2026 11:34
Base automatically changed from doc-gap-overlay-exact-names to main August 31, 2026 07:44
The configuration guide does not mention instance DNS anywhere, yet every
OVN deployment has to make a decision about it, because the fallback that
applies when nothing is configured does not work on OSISM.

Neutron picks the DNS servers it advertises to instances from the subnet's
dns_nameservers, else the [ovn] dns_servers option, else the resolvers of
the host running neutron-server. That last step is the problem: the
osism.commons.resolvconf role deliberately points /etc/resolv.conf at the
systemd-resolved stub (127.0.0.53) and keeps the real upstream resolvers
in resolved.conf. Syntactic validity is the only test neutron applies to
the entries it reads there, so the loopback stub passes, and the
containers run in the host network namespace, so 127.0.0.53 is what
reaches the instances, where it resolves nothing. An instance on a subnet
without dns_nameservers then has no working DNS at all.

The failure is silent. For IPv4 neutron warns only when it finds no
resolver at all, and the stub is a syntactically valid address, so there
is nothing for it to warn about; the DHCPv6 path omits the option without
warning either way.

This is not an upstream bug -- the precedence is deliberate and
documented, and per-subnet DNS is the recommended path -- but nothing told
OSISM operators about the interaction, so each one rediscovers it and
hand-writes the same overlay. Document the precedence, the fallback
caveat, and the [ovn] dns_servers override, next to the MTU section that
already points at the same overlay file.

Cover three behaviours an operator meets after setting the option:

* dns_servers is a single list filtered per IP version, so an IPv4-only
  list leaves IPv6 subnets falling through to the host resolvers, which on
  a systemd-resolved host are IPv4-only as well -- the DHCPv6 reply then
  carries no DNS server at all.
* 0.0.0.0 (IPv4) and :: (IPv6) suppress the DHCP option, but only as the
  sole remaining entry for that IP version.
* A changed [ovn] dns_servers does not reach subnets that already exist.
  Neutron reconciles them at startup only when neutron_sync_mode is set to
  repair, and the default is log, so a restart on its own changes nothing.
  The subnet has to be updated, and an update that changes no attribute
  sends no request at all.

Also note that neutron_dnsmasq_dns_servers, which defaults to public
resolvers, only applies to the ML2/OVS DHCP agent and does nothing on an
OVN deployment -- a reasonable thing to expect to help, and it does not.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Roger Luethi <luethi@osism.tech>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Ready for review

Development

Successfully merging this pull request may close these issues.

4 participants