USHIFT-7432: Fix OVN multinode SBDB connectivity regression - #7344
USHIFT-7432: Fix OVN multinode SBDB connectivity regression#7344eslutsky wants to merge 12 commits into
Conversation
Commit 8a0f4f2 (PR #6912, Jun 2026 rebase) removed the --nb-address/--sb-address flags from ovnkube --init-node, which were the only mechanism telling worker nodes where to find the primary's OVN NB/SB databases. After the removal, worker nodes fell back to a local unix socket that doesn't exist on workers, resulting in each node forming an isolated 1-node OVN RAFT cluster with no inter-node geneve tunnels. Root cause: after the upstream ovnkube binary dropped those CLI flags (deprecated in favour of config-file), the ovnkube.conf had no [OvnNorth] / [OvnSouth] section to replace them. Fix (3 files): 1. assets/components/ovn/common/configmap.yaml Add [OvnNorth] / [OvnSouth] sections in multinode mode, pointing all nodes at the primary's TCP NB/SB databases (tcp:PRIMARY_IP:9641/9642). The primary's NodeIP is already available in the render params. 2. pkg/components/networking.go - Pass MultiNodeEnabled as a render param so the configmap template can conditionally emit the [OvnNorth]/[OvnSouth] stanzas. - Worker nodes (identified by BootstrapKubeConfigExists()) only deploy the node DaemonSet, not the master DaemonSet. This prevents worker nodes from starting an isolated SBDB/NBDB raft cluster of their own. 3. assets/components/ovn/multi-node/node/daemonset.yaml Replace the hard "wait for local SBDB unix socket" guard with a combined condition: - Primary: exits when local socket appears (existing fast path). - Worker: exits when ovnkube-node sets ovn-remote=tcp:... in OVS external_ids (which happens once it connects to the primary SBDB via the new configmap stanzas). Also fixes the grep anchor (^tcp: → tcp:) so quoted OVS output "tcp:..." is correctly matched. Validated on a 2-VM KVM cluster (CentOS Stream 9, MicroShift 5.0 rc.1): - geneve tunnels form on both nodes - cross-node pod ping: 5/5 packets, 0% loss, ~1ms RTT - ovnkube-master runs only on the primary node - 440 CNCF conformance tests run; 0 sig-network failures Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
@eslutsky: This pull request explicitly references no jira issue. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
|
Pipeline controller notification For optional jobs, comment This repository is configured in: LGTM mode |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository YAML (base), Central YAML (inherited) Review profile: CHILL Plan: Enterprise Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: eslutsky The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
/test ? |
|
/test e2e-aws-tests-bootc-periodic-el10 e2e-aws-tests-bootc-periodic-arm-el9 Testing periodic jobs because they run the multi-node CNCF scenarios |
|
@eslutsky: This pull request references USHIFT-7432 which is a valid jira issue. Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the bug to target the "5.0.0" version, but no target version was set. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
Make it explicit that node/daemonset.yaml is shared across all nodes while master/daemonset.yaml is primary-only, instead of repeating the node entry in both branches of an if/else. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
/test all |
4d53726 to
358e6c8
Compare
…ation Disable the EXCLUDE_CNCF_CONFORMANCE gate so the CNCF conformance scenario runs unconditionally while the multinode OVN SBDB fix (PR #7344) is validated in CI. Revert once the job is confirmed green. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
/test e2e-aws-tests-bootc-periodic-el10 e2e-aws-tests-bootc-periodic-arm-el9 |
… label In MicroShift multinode mode both nodes carry node-role.kubernetes.io/master, so the ovnkube-master DaemonSet (which uses that nodeSelector) was being scheduled on all nodes regardless of the networking.go primary/worker split. Each node ended up running its own isolated OVN SBDB, preventing geneve tunnel formation and breaking all cross-node pod networking. Fix: at kubelet startup the primary node (identified by the absence of a bootstrap kubeconfig) receives the label node.microshift.io/role=primary. The ovnkube-master DaemonSet nodeSelector is updated to match that label, so it is scheduled exclusively on the primary node. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
/test e2e-aws-tests-bootc-periodic-el10 e2e-aws-tests-bootc-periodic-arm-el9 |
… mode In multinode mode the ovnkube-config ConfigMap contains [OvnNorth] and [OvnSouth] stanzas with the primary node's IP address. Both the primary and worker previously called ApplyConfigMaps unconditionally, so whichever node wrote last won: the worker overwrote the correct primary IP with its own IP, causing ovn-controller on all nodes to attempt SBDB connections to the worker's address (which has no SBDB), breaking cluster networking. Fix: skip ApplyConfigMaps on worker nodes in multinode mode. The primary writes the configmap once at startup with the correct IP; workers only read it via the DaemonSet volume mount. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
microshift-cleanup-data removed the br-int bridge and killed OVN processes, but left OVN-related entries (ovn-remote, ovn-encap-ip, etc.) in the OVS Open_vSwitch external_ids table. On a subsequent MicroShift start in multinode mode the stale ovn-remote value (e.g. a unix socket path or a worker's own TCP address from a previous run) prevented ovn-controller from connecting to the correct SBDB, breaking cluster networking. Clear all OVN-managed external_ids keys during full/OVN cleanup so the next startup always begins from a clean OVS state. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The previous commit placed the ovs-vsctl external_ids removal loop after 'systemctl stop ovsdb-server', making ovs-vsctl fail silently because the OVS socket was already gone. The stale ovn-remote value was never cleared. Move the loop before the ovsdb-server stop so ovs-vsctl can still reach the running daemon. ovsdb-server and OVN processes are killed afterwards as before. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…ode DaemonSet The ovnkube binary may not parse the [OvnSouth] address= stanza from ovnkube.conf, causing it to default ovn-remote to the local unix socket path instead of the primary's TCP endpoint. On worker nodes this breaks geneve tunnel formation because ovn-controller connects to a non-existent local socket rather than the primary SBDB. Before starting ovnkube --init-node, read the [OvnSouth] address= value directly from the mounted configmap file using awk and set it explicitly in OVS external_ids. This ensures ovn-controller on worker nodes connects to the primary's SBDB over TCP regardless of how the ini file is parsed. The snippet is a no-op on the primary where [OvnSouth].address is absent. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…startup The previous commit set ovn-remote so ovn-controller could reach the primary SBDB, but ovn-controller also needs ovn-encap-type=geneve and ovn-encap-ip=<node-ip> in OVS external_ids to register the local chassis and form geneve tunnels. These are normally set by ovnkube --init-node, but ovnkube is blocked waiting for a NBDB connection it cannot complete (same ini-parse issue). Set them explicitly before starting ovnkube so ovn-controller can proceed independently. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The ovnkube binary cannot parse [OvnNorth]/[OvnSouth] address= fields
from the ini config (upstream format mismatch in this binary version).
Without the primary's NB/SB TCP addresses, ovnkube-node on workers falls
back to the local unix socket paths, which do not exist on workers, and
stalls before it can set the encap external_ids needed by ovn-controller.
Fix the ovnkube-node startup script to handle workers explicitly:
1. Extract NB/SB addresses from the mounted configmap using awk.
2. Set ovn-encap-type=geneve and ovn-encap-ip=<node-ip> in OVS so
ovn-controller can register the chassis and form geneve tunnels.
3. On worker nodes (SB address points to a different host):
a. Remove stale socket files from any previous run.
b. Start socat relays that serve the local unix sockets and forward
connections to the primary's TCP NB (9641) and SB (9642) ports.
This lets the ovnkube binary connect via its expected unix path
while actually reaching the remote primary databases.
c. Set ovn-remote=tcp:PRIMARY:9642 in OVS so ovn-controller connects
directly to the primary SBDB over TCP (faster than the relay).
d. Export OVN_SB_DB/OVN_NB_DB so ovn-sbctl/ovn-nbctl subprocess
calls inside ovnkube also reach the primary.
4. Improve ovn-controller wait logic: for unix: remotes verify the
socket actually accepts connections (not just the file exists).
5. Handle stale ovn-controller processes and .ctl sockets gracefully.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
/test e2e-aws-tests-bootc-periodic-el10 e2e-aws-tests-bootc-periodic-arm-el9 |
The val=$(ovs-vsctl ...) assignment in the OVN external_ids cleanup loop ran under set -euo pipefail without || true. If ovsdb-server was already stopped (e.g., by a prior --ovn cleanup or by the test body), ovs-vsctl would exit non-zero and kill the script immediately, leaving cleanup incomplete and causing the test teardown to fail. Add || true to the assignment so a failed ovs-vsctl call is treated as "key not present" rather than a fatal error, making the loop idempotent when ovsdb-server is unavailable. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The 'A && B || C' pattern triggers SC2015 because if B fails, C runs unexpectedly. Replace with an explicit if/fi block to make the intent clear and silence the shellcheck warning. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
/test e2e-aws-tests-bootc-periodic-el10 e2e-aws-tests-bootc-periodic-arm-el9 |
|
/test all |
|
@eslutsky: The following test failed, say
Full PR test history. Your PR dashboard. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
Summary
Fixes the OVN multinode networking regression introduced by PR #6912 (June 2026 rebase), which removed
--nb-address/--sb-addressfromovnkube --init-nodewithout providing an equivalent inovnkube.conf. Worker nodes lost their only pointer to the primary's NB/SB databases, causing each node to form an isolated 1-node OVN RAFT cluster — no geneve tunnels formed, all cross-node pod traffic dropped.Root Cause
Commit
8a0f4f23eb(PR #6912) removed deprecated CLI flags without a config-file equivalent:The
ovnkube.confhad no[OvnNorth]/[OvnSouth]sections to replace them. Subsequently, PR #7052 cleaned up the render params and added the stale-socket wait guard — which works for single-node but blocks indefinitely on worker nodes that have no local SBDB.Fix
assets/components/ovn/common/configmap.yaml— add[OvnNorth]/[OvnSouth]sections in multinode mode, pointing all nodes at the primary's TCP databases:pkg/components/networking.go— two changes:MultiNodeEnabledrender param so the configmap template can conditionally emit the stanzas.BootstrapKubeConfigExists() == true) only deploy thenode/daemonset.yaml, notmaster/daemonset.yaml— prevents workers from starting an isolated SBDB/NBDB raft cluster.assets/components/ovn/multi-node/node/daemonset.yaml— replace the hard local-socket wait with a combined condition that handles both primary (socket) and worker (TCPovn-remoteset by ovnkube-node). Also fixes a grep anchor bug (^tcp:→tcp:) so quoted OVS output"tcp:..."is correctly matched.Validation
Tested on a 2-VM KVM cluster (CentOS Stream 9, MicroShift 5.0 rc.1):
[OvnNorth]/[OvnSouth]in configmap pointing to primaryaddLogicalPortOVN errors ongoing[sig-network]failures in CNCF conformance440 CNCF conformance tests ran to completion; the 6 non-networking failures (StatefulSet, SchedulerPreemption, Aggregator) were due to missing
oc adm policy add-scc-to-groupgrants in the test setup, unrelated to this fix.Remaining known limitation
The primary VM must allow TCP 9641/9642/9643/9644 from worker nodes.
configure-node.shstops firewalld, but on some base images explicit iptables rules may be needed. This should be addressed in a follow-up toconfigure-node.sh.Test plan
periodic-ci-openshift-microshift-release-5.0-periodics-e2e-aws-tests-nightlypassesel98-src@cncf-conformancescenarioovnkube-masterpod runs only on primary node in multinode mode🤖 Generated with Claude Code