Skip to content

WIP Hypershift On Kubevirt Model 1 localnet-as-primary support - #83125

Open
asood-rh wants to merge 2 commits into
openshift:mainfrom
asood-rh:hypershift-on-kubevirt-model1-localnet-primary
Open

WIP Hypershift On Kubevirt Model 1 localnet-as-primary support#83125
asood-rh wants to merge 2 commits into
openshift:mainfrom
asood-rh:hypershift-on-kubevirt-model1-localnet-primary

Conversation

@asood-rh

@asood-rh asood-rh commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Add ATTACH_DEFAULT_NETWORK=localnet mode to hypershift-kubevirt-create for deploying KubeVirt hosted clusters with OVN localnet as the primary (and only) network interface, using --attach-default-network=false.

Guest VMs connect solely via a localnet NAD on the management cluster's L2 segment (192.168.111.0/24), enabling same-subnet bootstrap and EgressIP verification without a default pod network.

Changes:

  • hypershift-kubevirt-create-commands.sh: add localnet NAD creation, OVN DHCP_Options injection (with dns_server), port security clearing, and ipecho pod deployment for EgressIP source-IP verification
  • hypershift-kubevirt-create-ref.yaml: add LOCALNET_SUBNET and LOCALNET_ATTACH_DEFAULT env vars, update ATTACH_DEFAULT_NETWORK docs
  • CNO release-5.0 config: add metal-ds-ipi-ovn-kubevirt-hypershift- localnet-primary debug job on equinix-ocp-hcp

Summary by CodeRabbit

Adds CI support for KubeVirt hosted clusters that use OVN localnet as the primary and only network interface.

  • Creates a localnet NAD and configures OVN DHCP, DNS, and port security settings.
  • Supports --attach-default-network=false with configurable LOCALNET_SUBNET and LOCALNET_ATTACH_DEFAULT values.
  • Deploys an ipecho pod for EgressIP source-IP validation.
  • Adds a CNO release 5.0 localnet-primary diagnostic job on equinix-ocp-hcp.

Add ATTACH_DEFAULT_NETWORK=localnet mode to hypershift-kubevirt-create
for deploying KubeVirt hosted clusters with OVN localnet as the primary
(and only) network interface, using --attach-default-network=false.

Guest VMs connect solely via a localnet NAD on the management cluster's
L2 segment (192.168.111.0/24), enabling same-subnet bootstrap and
EgressIP verification without a default pod network.

Changes:
- hypershift-kubevirt-create-commands.sh: add localnet NAD creation,
  OVN DHCP_Options injection (with dns_server), port security clearing,
  and ipecho pod deployment for EgressIP source-IP verification
- hypershift-kubevirt-create-ref.yaml: add LOCALNET_SUBNET and
  LOCALNET_ATTACH_DEFAULT env vars, update ATTACH_DEFAULT_NETWORK docs
- CNO release-5.0 config: add metal-ds-ipi-ovn-kubevirt-hypershift-
  localnet-primary debug job on equinix-ocp-hcp
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 7, 2026
@openshift-ci
openshift-ci Bot requested review from danwinship and orenc1 August 7, 2026 19:02
@openshift-ci

openshift-ci Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: asood-rh
Once this PR has been reviewed and has the lgtm label, please assign kyrtapz, tiraboschi for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: af43b4d3-49ae-408a-aeb5-734e98305690

📥 Commits

Reviewing files that changed from the base of the PR and between 7ae91ff and dd7b1b5.

📒 Files selected for processing (1)
  • ci-operator/config/openshift/cluster-network-operator/openshift-cluster-network-operator-release-5.0.yaml
💤 Files with no reviewable changes (1)
  • ci-operator/config/openshift/cluster-network-operator/openshift-cluster-network-operator-release-5.0.yaml

Walkthrough

The change adds localnet networking support to the HyperShift KubeVirt create step and configures an optional Metal workflow with diagnostics, an 18-hour wait, and a 20-hour timeout.

Changes

HyperShift KubeVirt localnet networking

Layer / File(s) Summary
Localnet contract and cluster creation
ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-ref.yaml, ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh
The create step documents localnet, LOCALNET_SUBNET, and LOCALNET_ATTACH_DEFAULT. The script creates the localnet attachment and passes the related cluster arguments. The macvlan path remains available.
Localnet post-creation configuration
ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh
The script waits for VMIs, configures OVN DHCP options, clears localnet port security, deploys an ip-echo pod, and writes its endpoint to kubevirt_ipecho_url.
Release workflow wiring
ci-operator/config/openshift/cluster-network-operator/openshift-cluster-network-operator-release-5.0.yaml
The optional job uses the equinix-ocp-hcp profile and a three-node Metal localnet OVN KubeVirt HyperShift workflow. It adds prerequisites, diagnostics, an 18-hour wait, and a 20-hour job timeout.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Workflow
  participant CreateStep
  participant HyperShift
  participant OVN
  participant IpEchoPod
  participant SharedDirectory
  Workflow->>CreateStep: Run localnet HyperShift KubeVirt setup
  CreateStep->>HyperShift: Create cluster with localnet arguments
  CreateStep->>OVN: Configure DHCP and clear port security
  CreateStep->>IpEchoPod: Deploy localnet ip-echo pod
  IpEchoPod-->>CreateStep: Provide discovered localnet IP
  CreateStep->>SharedDirectory: Write kubevirt_ipecho_url
  Workflow->>Workflow: Run diagnostic wait test
Loading

Suggested reviewers: danwinship, orenc1


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (2 errors, 1 warning)

Check name Status Explanation Resolution
Container-Privileges ❌ Error The generated ip-echo Pod sets runAsUser: 0, and its namespace is labeled pod-security.kubernetes.io/enforce=privileged without a privilege justification. Run ip-echo as a non-root user and remove the privileged Pod Security label, or document the narrowly required privilege and minimize its scope.
No-Sensitive-Data-In-Logs ❌ Error The new debug step runs oc get nodes for both clusters, and the script echoes VMI, node, and LSP names that can expose internal hostnames in CI logs. Do not print full node listings or dynamic infrastructure identifiers. Log counts and status only, and disable xtrace around commands that include such values.
Topology-Aware Scheduling Compatibility ⚠️ Warning The new ip-echo Pod uses a keyless, effectless operator: Exists toleration, so it tolerates the arbiter NoSchedule taint and has no topology guard. Replace the wildcard toleration with explicit required tolerations and add topology-aware scheduling that excludes node-role.kubernetes.io/arbiter on TNA clusters.
✅ Passed checks (12 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: localnet-as-primary support for HyperShift on KubeVirt.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed The changed files declare no Ginkgo titles. CI names are static, and dynamic VMI, node, namespace, and IP values appear only in script output and setup bodies.
Test Structure And Quality ✅ Passed The PR changes only YAML, shell, and reference metadata; the complete feature diff contains no Go files, Ginkgo blocks, or Gomega assertions, so this check is not applicable.
Microshift Test Compatibility ✅ Passed The full PR range changes only YAML and shell files; it adds no Go files or Ginkgo It/Describe/Context/When declarations, so this check is not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The pull request changes only CI YAML/configuration and shell/reference files; no new Go/Ginkgo test declarations were added, so SNO compatibility rules do not apply.
Ote Binary Stdout Contract ✅ Passed The PR changes only YAML and a shell step; it adds no OTE binary, Go main, or suite setup, so the stdout contract is not applicable.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed The PR adds only CI YAML and shell setup; it adds no Go files or Ginkgo declarations such as It, Describe, Context, or When, so this check is not applicable.
No-Weak-Crypto ✅ Passed The PR additions contain no MD5, SHA1, DES, RC4, Blowfish, ECB, crypto API, or custom crypto code; added comparisons only test network and VMI status values.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh`:
- Around line 269-277: Make the VMI readiness loop fail after its 60th iteration
if VMI_RUNNING_COUNT remains below HYPERSHIFT_NODE_COUNT. Track whether the loop
reached the success condition, and after the loop exits return a nonzero status
with an error message when not all expected VMIs are Running; preserve the
existing success break and progress logging.
- Around line 324-365: Update the namespace and Pod manifest in the
hypershift-kubevirt creation flow: remove the privileged pod-security label and
run the container as non-root, with restricted security settings including
runAsNonRoot, allowPrivilegeEscalation=false, read-only root filesystem, dropped
capabilities, and automountServiceAccountToken=false. Add resource
requests/limits, liveness/readiness probes, and a namespace-scoped
NetworkPolicy; if localnet requires an exception, document and narrowly scope it
rather than restoring privileged execution.
- Line 266: Update the LOCALNET_GW derivation in the hypershift-kubevirt create
command flow to remove the subnet prefix length, producing only the first host
address (for example, 192.168.111.1). Preserve its use as the OVN DHCP router,
server ID, and DNS server values.
- Around line 295-298: Update the LSP_NAME lookup in the localnet discovery flow
to filter Logical_Switch_Port results by the configured network identity in
addition to the localnet topology marker, rather than selecting the first result
globally. Require exactly one matching LSP and fail clearly when the query
returns zero or multiple matches; do not use head -1 to silently choose among
candidates.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 026be615-ac8c-4f7a-99a3-da48a7c478c4

📥 Commits

Reviewing files that changed from the base of the PR and between ccfd628 and 7ae91ff.

📒 Files selected for processing (3)
  • ci-operator/config/openshift/cluster-network-operator/openshift-cluster-network-operator-release-5.0.yaml
  • ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh
  • ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-ref.yaml

if [[ "${ATTACH_DEFAULT_NETWORK}" == "localnet" ]]; then
LOCALNET_SUBNET="${LOCALNET_SUBNET:-192.168.111.0/24}"
# Derive gateway IP (.1) from the subnet
LOCALNET_GW=$(echo "${LOCALNET_SUBNET}" | sed 's|\.[0-9]*/|.1|')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Pass a host address to OVN DHCP options.

Line 266 produces 192.168.111.1/24, not 192.168.111.1. Lines 307 pass this CIDR value as the DHCP router, server ID, and DNS server. Derive the first host address without the prefix.

Proposed fix
-  LOCALNET_GW=$(echo "${LOCALNET_SUBNET}" | sed 's|\.[0-9]*/|.1|')
+  LOCALNET_GW="$(
+    python3 - "${LOCALNET_SUBNET}" <<'PY'
+import ipaddress
+import sys
+
+network = ipaddress.ip_network(sys.argv[1], strict=False)
+if network.version != 4:
+    raise ValueError("LOCALNET_SUBNET must be an IPv4 CIDR")
+print(next(network.hosts()))
+PY
+  )"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
LOCALNET_GW=$(echo "${LOCALNET_SUBNET}" | sed 's|\.[0-9]*/|.1|')
LOCALNET_GW="$(
python3 - "${LOCALNET_SUBNET}" <<'PY'
import ipaddress
import sys
network = ipaddress.ip_network(sys.argv[1], strict=False)
if network.version != 4:
raise ValueError("LOCALNET_SUBNET must be an IPv4 CIDR")
print(next(network.hosts()))
PY
)"
🧰 Tools
🪛 Shellcheck (0.11.0)

[style] 266-266: See if you can use ${variable//search/replace} instead.

(SC2001)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh`
at line 266, Update the LOCALNET_GW derivation in the hypershift-kubevirt create
command flow to remove the subnet prefix length, producing only the first host
address (for example, 192.168.111.1). Preserve its use as the OVN DHCP router,
server ID, and DNS server values.

Comment on lines +269 to +277
for i in $(seq 1 60); do
VMI_RUNNING_COUNT=$(oc get vmi -n "${CLUSTER_NAMESPACE_PREFIX}-${CLUSTER_NAME}" --no-headers 2>/dev/null | grep -c Running || true)
if [[ "${VMI_RUNNING_COUNT}" -ge "${HYPERSHIFT_NODE_COUNT}" ]]; then
echo "All ${VMI_RUNNING_COUNT} VMIs are Running"
break
fi
echo "Waiting for VMIs... (${VMI_RUNNING_COUNT}/${HYPERSHIFT_NODE_COUNT} running) [${i}/60]"
sleep 10
done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Fail when all expected VMIs do not start.

After the final iteration, the script continues even when fewer than HYPERSHIFT_NODE_COUNT VMIs run. It can then publish an ip-echo endpoint after only partial DHCP and port-security setup. Exit with an error after the timeout.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh`
around lines 269 - 277, Make the VMI readiness loop fail after its 60th
iteration if VMI_RUNNING_COUNT remains below HYPERSHIFT_NODE_COUNT. Track
whether the loop reached the success condition, and after the loop exits return
a nonzero status with an error message when not all expected VMIs are Running;
preserve the existing success break and progress logging.

Comment on lines +295 to +298
# Find the localnet Logical Switch Port for this VMI
LSP_NAME=$(oc exec -n openshift-ovn-kubernetes "${OVN_POD}" -c nbdb -- \
ovn-nbctl --columns=name --bare find Logical_Switch_Port \
"external_ids:k8s.ovn.org/topology=localnet" 2>/dev/null | head -1)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file='ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh'
printf '%s\n' '--- target context ---'
sed -n '240,330p' "$file"

printf '%s\n' '--- VMI and LSP-related references ---'
rg -n -C 3 'VMI|Logical_Switch_Port|localnet|DHCP|port.security|LSP_NAME' "$file" ci-operator/step-registry/hypershift/kubevirt 2>/dev/null || true

printf '%s\n' '--- related step files ---'
git ls-files 'ci-operator/step-registry/hypershift/kubevirt/**' | sort

Repository: openshift/release

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- all references to the target variables and OVN commands ---'
rg -n -C 4 'VMI=|VMI\b|OVN_POD|ovn-nbctl|external_ids:k8s\.ovn\.org|Logical_Switch_Port|set Logical_Switch_Port|clear Logical_Switch_Port' ci-operator/step-registry ci-operator 2>/dev/null | head -n 1200

printf '%s\n' '--- script structure ---'
ast-grep outline ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh || true

printf '%s\n' '--- full script length and relevant assignments ---'
wc -l ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh
rg -n '^[[:space:]]*[A-Za-z_][A-Za-z0-9_]*=' ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh

Repository: openshift/release

Length of output: 50374


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file='ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh'

printf '%s\n' '--- complete target script in focused chunks ---'
sed -n '1,180p' "$file"
sed -n '181,360p' "$file"
sed -n '361,520p' "$file"

printf '%s\n' '--- workflow and documentation references ---'
rg -n -C 5 'hypershift-kubevirt-create|kubevirt.*create|localnet|network identity|Logical Switch Port' \
  ci-operator/step-registry ci-operator/step-registry-config 2>/dev/null | head -n 1600 || true

Repository: openshift/release

Length of output: 50374


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- OVN LSP query patterns in repository ---'
rg -n -C 5 'find Logical_Switch_Port|external_ids:k8s\.ovn\.org|Logical_Switch_Port.*external|ovn-nbctl.*find' . \
  -g '*.sh' -g '*.yaml' -g '*.yml' -g '*.go' -g '*.py' 2>/dev/null | head -n 2000 || true

printf '%s\n' '--- VMI creation and network configuration commands ---'
rg -n -C 5 'oc create.*vmi|oc apply|virtctl|NetworkAttachmentDefinition|localnet|k8s\.ovn\.org' \
  ci-operator/step-registry/hypershift ci-operator/step-registry/kubevirt 2>/dev/null | head -n 2000 || true

Repository: openshift/release

Length of output: 50374


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file='ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh'
python3 - "$file" <<'PY'
from pathlib import Path
import re, sys

p = Path(sys.argv[1])
lines = p.read_text().splitlines()
for i, line in enumerate(lines, 1):
    if 260 <= i <= 330:
        print(f"{i:4}: {line}")

print("\nReferences to VMI and LSP in the script:")
for i, line in enumerate(lines, 1):
    if re.search(r'\bVMI\b|Logical_Switch_Port|LSP_NAME|localnet', line):
        print(f"{i:4}: {line}")
PY

printf '%s\n' '--- file metadata ---'
wc -l "$file"
git diff --stat -- "$file"

Repository: openshift/release

Length of output: 6770


🌐 Web query:

Search for the exact file hypershift-kubevirt-create-commands.shand theexternal_ids:k8s.ovn.org/topology=localnet query in the OpenShift release repository.

💡 Result:

The file hypershift-kubevirt-create-commands.sh does not exist as a standalone, commonly referenced file in the main OpenShift release repository. However, a similarly named file, hypershift-kubevirt-install-create-external-infra-kubeconfig-commands.sh, exists within the OpenShift release repository's CI operator step registry [1]. This script is located at: ci-operator/step-registry/hypershift/kubevirt/install/create-external-infra-kubeconfig/hypershift-kubevirt-install-create-external-infra-kubeconfig-commands.sh [1]. Regarding the external_ids:k8s.ovn.org/topology=localnet query, this relates to OVN-Kubernetes networking in OpenShift [2]. The string external_ids refers to attributes within the OVN Southbound database, often queried via ovn-sbctl to inspect port bindings for localnet ports [2]. The localnet topology in OpenShift is used to connect secondary networks to the physical network underlay [3][4]. When configuring or inspecting these networks—particularly when using the ClusterUserDefinedNetwork (CUDN) API—administrators ensure that the topology is set to Localnet and the physicalNetworkName matches the OVN bridge-mapping configured on cluster nodes [5][4][6]. The specific pattern topology=localnet is a characteristic configuration value for these network types [5][3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
for p in Path('.').rglob('hypershift-kubevirt-create-commands.sh'):
    print(p)
    text = p.read_text()
    print(text)
PY

Repository: openshift/release

Length of output: 15354


🏁 Script executed:

#!/bin/bash
set -euo pipefail

url='https://raw.githubusercontent.com/openshift/release/master/ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh'
if command -v curl >/dev/null 2>&1; then
  curl -fsSL --max-time 15 "$url" | sed -n '250,330p'
else
  echo 'curl unavailable'
fi

Repository: openshift/release

Length of output: 155


🌐 Web query:

site:github.com/openshift/release "Find the localnet Logical Switch Port for this VMI"

💡 Result:

In OVN-Kubernetes, a localnet logical switch port is not a direct attachment for a Virtual Machine Interface (VMI) itself; rather, it serves as the bridge between an OVN logical switch and the physical underlay network [1][2][3]. For a VMI to utilize a localnet topology, the architecture works as follows: 1. Localnet Port Purpose: The localnet port is a specialized logical switch port created on the OVN logical switch, configured with type 'localnet' and an option 'network_name' [4][5][6]. This port connects the logical switch to an Open vSwitch (OVS) bridge on the node, which is mapped to the physical network via 'ovn-bridge-mappings' [2][5][6]. 2. VMI Connectivity: A VMI connects to the logical switch via its own standard VIF (Virtual Interface) logical port, not the localnet port [6]. By attaching to a logical switch that also contains a localnet port, the VMI gains access to the physical network through that logical switch's localnet connection [1][3]. 3. Finding the Port: If you are investigating a specific VMI in an OpenShift environment, you can identify the OVN logical switch port associated with the VMI's interface. Since the VMI's interface port is of standard type (empty string), you will not find the VMI directly on a 'localnet' port [6]. Instead, you should: - Identify the OVN logical switch to which the VMI's port is attached. - List the ports on that logical switch. - Look for the port with 'type: localnet', which provides the connectivity to the physical network for all VIFs on that switch [4][6]. In the context of the openshift/release repository or OVN-Kubernetes controllers, the localnet port is typically managed by the Localnet User Defined Network controller [4]. You can verify the configuration by checking the OVN Northbound database (OVN-NB) for logical switch ports with 'type: localnet' on the specific switch associated with your VMI's secondary network [4][6].

Citations:


🌐 Web query:

OVN-Kubernetes k8s.ovn.org/topology=localnet Logical_Switch_Port external_ids pod VMI

💡 Result:

In OVN-Kubernetes, the configuration topology=localnet is a specialized network mode used to bridge pod or Virtual Machine (VM) traffic directly to an external physical network [1][2][3]. Topology and Logical Switch Ports When a secondary network is configured with topology: localnet, OVN-Kubernetes creates a cluster-wide logical switch that connects the workloads (pods or VMs) to a physical underlay [4][3]. At the OVN database level, this involves creating a logical switch port (LSP) of type localnet on the logical switch [5]. This specific LSP bridges the OVN logical network to a physical network interface on the node, enabling north-south traffic without requiring SNAT to node IP addresses [1][6]. Key Characteristics 1. Integration: Unlike standard overlay networks that use encapsulation, localnet topology wires the logical switch directly to an existing, pre-configured physical network [7][6]. 2. Configuration Requirements: To function, the OVN-Kubernetes controller requires appropriate mapping of the physical network. This is typically achieved by configuring OVS bridge mappings (e.g., via a NodeNetworkConfigurationPolicy in OpenShift/OKD environments) on the cluster nodes [2][3]. 3. Workload Support: This topology is supported for both Pods and KubeVirt VMs, allowing them to participate directly in the provider's physical subnet [1][3]. 4. VLAN Tagging: If isolation is required on the physical network, a vlanID can be specified in the NetworkAttachmentDefinition (NAD) [2][4]. When this is set, OVN-Kubernetes applies the VLAN tag to the traffic leaving the pod/VM, effectively placing the workload in a specific VLAN on the external network [4]. Logical Structure The Logical_Switch_Port (LSP) for a localnet connection is a distinct OVN construct managed by the OVN-Kubernetes CNI [5]. It is managed by the ovnkube-controller, which monitors Custom Resources (such as ClusterUserDefinedNetwork or NetworkAttachmentDefinition) and translates them into the necessary OVN Northbound database entries [1][8]. These LSPs facilitate the direct exchange of packets between the OVN logical switch and the physical switch port connected to the node [5]. It is important to note that topology: localnet is restricted to secondary networks (it cannot be used for the primary cluster network) and requires consistent configuration of physical network names across the cluster nodes to ensure correct traffic routing [1][9].

Citations:


Select the localnet LSP for the configured network.

A localnet LSP is shared by the logical switch, not by an individual VMI. However, this query can select the wrong network when multiple localnet networks exist. Filter by the network identity and require exactly one match.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh`
around lines 295 - 298, Update the LSP_NAME lookup in the localnet discovery
flow to filter Logical_Switch_Port results by the configured network identity in
addition to the localnet topology marker, rather than selecting the first result
globally. Require exactly one matching LSP and fail clearly when the query
returns zero or multiple matches; do not use head -1 to silently choose among
candidates.

Comment on lines +324 to +365
oc create namespace "${IPECHO_NAMESPACE}" --dry-run=client -o yaml | oc apply -f -
oc label ns "${IPECHO_NAMESPACE}" pod-security.kubernetes.io/enforce=privileged --overwrite 2>/dev/null || true

# Create a localnet NAD in the ip-echo namespace
oc apply -f - <<IPECHO_NAD_EOF
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
name: localnet-network
namespace: ${IPECHO_NAMESPACE}
spec:
config: '{
"cniVersion": "0.3.1",
"name": "physnet",
"type": "ovn-k8s-cni-overlay",
"topology": "localnet",
"netAttachDefName": "${IPECHO_NAMESPACE}/localnet-network",
"subnets": "${LOCALNET_SUBNET}"
}'
IPECHO_NAD_EOF

oc apply -f - <<IPECHO_EOF
apiVersion: v1
kind: Pod
metadata:
name: egressip-ipecho
namespace: ${IPECHO_NAMESPACE}
annotations:
k8s.v1.cni.cncf.io/networks: localnet-network
spec:
containers:
- name: ip-echo
image: quay.io/openshifttest/ip-echo:1.2.0
ports:
- containerPort: 80
protocol: TCP
securityContext:
runAsUser: 0
restartPolicy: Always
tolerations:
- operator: Exists
IPECHO_EOF

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Use the required restricted Pod security controls.

Line 325 labels the new namespace as privileged. Lines 360-362 run the container as root. The Pod also lacks runAsNonRoot, allowPrivilegeEscalation: false, a read-only root filesystem, dropped capabilities, resource limits, probes, and automountServiceAccountToken: false. Remove the privileged namespace label and apply the required restricted security context. If the localnet CNI requires an exception, document and scope that exception.

As per coding guidelines, step manifests must not run as root without justification. As per path instructions, Kubernetes manifests require restricted security settings, limits, probes, and a namespace NetworkPolicy.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ci-operator/step-registry/hypershift/kubevirt/create/hypershift-kubevirt-create-commands.sh`
around lines 324 - 365, Update the namespace and Pod manifest in the
hypershift-kubevirt creation flow: remove the privileged pod-security label and
run the container as non-root, with restricted security settings including
runAsNonRoot, allowPrivilegeEscalation=false, read-only root filesystem, dropped
capabilities, and automountServiceAccountToken=false. Add resource
requests/limits, liveness/readiness probes, and a namespace-scoped
NetworkPolicy; if localnet requires an exception, document and narrowly scope it
rather than restoring privileged execution.

Sources: Coding guidelines, Path instructions

@asood-rh

asood-rh commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

/pj-rehearse pull-ci-openshift-cluster-network-operator-release-5.0-metal-ds-ipi-ovn-kubevirt-hypershift-localnet-primary

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

@asood-rh: now processing your pj-rehearse request. Please allow up to 10 minutes for jobs to trigger or cancel.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

@asood-rh: job(s): pull-ci-openshift-cluster-network-operator-release-5.0-metal-ds-ipi-ovn-kubevirt-hypershift-localnet-primary either don't exist or were not found to be affected, and cannot be rehearsed

Replace the existing e2e-aws-hypershift-ovn-kubevirt job definition
with the localnet-as-primary config so pj-rehearse can detect it as
an affected job and allow rehearsal before merging.
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

[REHEARSALNOTIFIER]
@asood-rh: the pj-rehearse plugin accommodates running rehearsal tests for the changes in this PR. Expand 'Interacting with pj-rehearse' for usage details. The following rehearsable tests have been affected by this change:

Test name Repo Type Reason
pull-ci-openshift-ovn-kubernetes-release-4.20-e2e-aws-ovn-hypershift-kubevirt openshift/ovn-kubernetes presubmit Registry content changed
pull-ci-openshift-ovn-kubernetes-release-4.19-e2e-aws-ovn-hypershift-kubevirt openshift/ovn-kubernetes presubmit Registry content changed
pull-ci-openshift-ovn-kubernetes-release-4.18-e2e-aws-ovn-hypershift-kubevirt openshift/ovn-kubernetes presubmit Registry content changed
pull-ci-openshift-ovn-kubernetes-release-4.17-e2e-aws-ovn-hypershift-kubevirt openshift/ovn-kubernetes presubmit Registry content changed
pull-ci-openshift-ovn-kubernetes-release-4.16-e2e-aws-ovn-hypershift-kubevirt openshift/ovn-kubernetes presubmit Registry content changed
pull-ci-openshift-ovn-kubernetes-release-4.15-e2e-aws-ovn-hypershift-kubevirt openshift/ovn-kubernetes presubmit Registry content changed
pull-ci-openshift-ovn-kubernetes-release-4.14-e2e-aws-ovn-hypershift-kubevirt openshift/ovn-kubernetes presubmit Registry content changed
pull-ci-openshift-ovn-kubernetes-sandbox-release-4.16-e2e-aws-ovn-hypershift-kubevirt openshift/ovn-kubernetes presubmit Registry content changed
pull-ci-openshift-ovn-kubernetes-sandbox-release-4.17-e2e-aws-ovn-hypershift-kubevirt openshift/ovn-kubernetes presubmit Registry content changed
pull-ci-openshift-kubevirt-csi-driver-main-e2e-kubevirt-aws-csi openshift/kubevirt-csi-driver presubmit Registry content changed
pull-ci-openshift-kubevirt-csi-driver-release-5.1-e2e-kubevirt-aws-csi openshift/kubevirt-csi-driver presubmit Registry content changed
pull-ci-openshift-kubevirt-csi-driver-release-5.0-e2e-kubevirt-aws-csi openshift/kubevirt-csi-driver presubmit Registry content changed
pull-ci-openshift-kubevirt-csi-driver-release-4.23-e2e-kubevirt-aws-csi openshift/kubevirt-csi-driver presubmit Registry content changed
pull-ci-openshift-kubevirt-csi-driver-release-4.22-e2e-kubevirt-aws-csi openshift/kubevirt-csi-driver presubmit Registry content changed
pull-ci-openshift-kubevirt-csi-driver-release-4.21-e2e-kubevirt-aws-csi openshift/kubevirt-csi-driver presubmit Registry content changed
pull-ci-openshift-kubevirt-csi-driver-release-4.20-e2e-kubevirt-aws-csi openshift/kubevirt-csi-driver presubmit Registry content changed
pull-ci-openshift-kubevirt-csi-driver-release-4.19-e2e-kubevirt-aws-csi openshift/kubevirt-csi-driver presubmit Registry content changed
pull-ci-openshift-kubevirt-csi-driver-release-4.18-e2e-kubevirt-aws-csi openshift/kubevirt-csi-driver presubmit Registry content changed
pull-ci-openshift-kubevirt-csi-driver-release-4.17-e2e-kubevirt-aws-csi openshift/kubevirt-csi-driver presubmit Registry content changed
pull-ci-openshift-kubevirt-csi-driver-release-4.16-e2e-kubevirt-aws-csi openshift/kubevirt-csi-driver presubmit Registry content changed
pull-ci-openshift-kubevirt-csi-driver-release-4.15-e2e-kubevirt-aws-csi openshift/kubevirt-csi-driver presubmit Registry content changed
pull-ci-openshift-kubevirt-csi-driver-release-4.14-e2e-kubevirt-aws-csi openshift/kubevirt-csi-driver presubmit Registry content changed
pull-ci-openshift-cluster-network-operator-release-5.0-e2e-aws-hypershift-ovn-kubevirt openshift/cluster-network-operator presubmit Ci-operator config changed
pull-ci-openshift-cluster-network-operator-master-e2e-aws-hypershift-ovn-kubevirt openshift/cluster-network-operator presubmit Registry content changed
pull-ci-openshift-cluster-network-operator-release-5.1-e2e-aws-hypershift-ovn-kubevirt openshift/cluster-network-operator presubmit Registry content changed

A total of 279 jobs have been affected by this change. The above listing is non-exhaustive and limited to 25 jobs.

A full list of affected jobs can be found here

Interacting with pj-rehearse

Comment: /pj-rehearse to run up to 5 rehearsals
Comment: /pj-rehearse skip to opt-out of rehearsals
Comment: /pj-rehearse {test-name}, with each test separated by a space, to run one or more specific rehearsals
Comment: /pj-rehearse more to run up to 10 rehearsals
Comment: /pj-rehearse max to run up to 25 rehearsals
Comment: /pj-rehearse auto-ack to run up to 5 rehearsals, and add the rehearsals-ack label on success
Comment: /pj-rehearse list to get an up-to-date list of affected jobs
Comment: /pj-rehearse abort to abort all active rehearsals
Comment: /pj-rehearse network-access-allowed to allow rehearsals of tests that have the restrict_network_access field set to false. This must be executed by an openshift org member who is not the PR author

Once you are satisfied with the results of the rehearsals, comment: /pj-rehearse ack to unblock merge. When the rehearsals-ack label is present on your PR, merge will no longer be blocked by rehearsals.
If you would like the rehearsals-ack label removed, comment: /pj-rehearse reject to re-block merging.

@asood-rh

asood-rh commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

/pj-rehearse pull-ci-openshift-cluster-network-operator-release-5.0-e2e-aws-hypershift-ovn-kubevirt

1 similar comment
@asood-rh

asood-rh commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

/pj-rehearse pull-ci-openshift-cluster-network-operator-release-5.0-e2e-aws-hypershift-ovn-kubevirt

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

@asood-rh: now processing your pj-rehearse request. Please allow up to 10 minutes for jobs to trigger or cancel.

@openshift-ci

openshift-ci Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

@asood-rh: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/rehearse/openshift/cluster-network-operator/release-5.0/e2e-aws-hypershift-ovn-kubevirt dd7b1b5 link unknown /pj-rehearse pull-ci-openshift-cluster-network-operator-release-5.0-e2e-aws-hypershift-ovn-kubevirt
ci/prow/generated-config dd7b1b5 link true /test generated-config

Full PR test history. Your PR dashboard.

Details

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 kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant