<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Networking on TechBlog about OpenShift/Ansible/Satellite and much more</title><link>https://blog.stderr.at/categories/networking/</link><description>TechBlog about OpenShift/Ansible/Satellite and much more</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>Toni Schmidbauer &amp; Thomas Jungbauer</copyright><lastBuildDate>Thu, 05 Feb 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.stderr.at/categories/networking/index.xml" rel="self" type="application/rss+xml"/><item><title>OpenShift Virtualization Networking - The Overview</title><link>https://blog.stderr.at/openshift-platform/virtualization/2025-12-29-openshift-virtualization-networking/</link><pubDate>Mon, 29 Dec 2025 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/openshift-platform/virtualization/2025-12-29-openshift-virtualization-networking/</guid><description>&lt;div class="paragraph"&gt;
&lt;p&gt;It’s time to dig into OpenShift Virtualization. You read that right, OpenShift Virtualization, based on &lt;strong&gt;kubevirt&lt;/strong&gt; allows you to run Virtual Machines on top of OpenShift, next to Pods.
If you come from a pure Kubernetes background, OpenShift Virtualization can feel like stumbling into a different dimension. In the world of Pods, we rarely care about Layer 2, MAC addresses, or VLANs. The SDN (Software Defined Network) handles the magic and we are happy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;But Virtual Machines are different…​.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;They are needy creatures. They often refuse to live in the bubble of the default Pod network. They want to talk to the external Oracle database on the bare metal server next door, they need a static IP from the corporate range, or they need to be reachable via a specific VLAN.
Networking is a key part of the Virtualization story and we need to master it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;To achieve this, we need to understand two tools: &lt;strong&gt;NMState Operator&lt;/strong&gt; and &lt;strong&gt;Multus&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In this guide, I will try to discuss some of the basics for &amp;#34;Multihomed Nodes&amp;#34; and look at the three main ways to connect your VMs to the outside world.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_who_does_what_nmstate_vs_multus"&gt;Who does what: NMState vs. Multus&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Before we look at YAML, we need to clear up a common confusion. Who does what?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Think of your OpenShift Node as a house.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;NMState (The Electrician)&lt;/strong&gt;: This operator works on the Node (Host) level. It drills holes in the walls, lays the physical cables, and installs the wall sockets. In technical terms: It configures Bridges, Bonds, and VLANs on the Linux OS of the worker nodes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Multus (The Extension Cord)&lt;/strong&gt;: This CNI plugin works on the VM/Pod level. It plugs the VM into the socket that NMState created. It allows a VM to have more than one network interface (eth0, eth1, etc.).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;You usually need both. First, NMState builds the bridge. Then, Multus connects the VM to it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="imageblock"&gt;
&lt;div class="content"&gt;
&lt;img src="https://blog.stderr.at/openshift-platform/virtualization/images/network-overview/nmstate_and_multus.png" alt="NMState and Multus in action"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_nmstate_operator_installation"&gt;NMState Operator Installation&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;While Multus is installed by default, NMState is not. You need to install the Operator first.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;To install the NMState Operator, you can use the Web UI or the CLI. For the Web UI, you can use the following steps:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;
&lt;p&gt;In the OpenShift Web Console, navigate to Operators → OperatorHub (or Ecosystem → Software Catalog in version 4.20+).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the OperatorHub, search for &lt;strong&gt;NMState&lt;/strong&gt; and select the Operator from the list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click on the &lt;strong&gt;NMState&lt;/strong&gt; Operator and click on the &lt;strong&gt;Install&lt;/strong&gt; button.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the &lt;strong&gt;Install&lt;/strong&gt; button to install the Operator.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After the Operator is installed, you can check the status of the Operator in the &lt;strong&gt;Installed Operators&lt;/strong&gt; view.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="imageblock"&gt;
&lt;div class="content"&gt;
&lt;img src="https://blog.stderr.at/openshift-platform/virtualization/images/network-overview/nmState-Operator.png" alt="NMState Operator Installation"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Once done you will need to create an instance of the NMState Operator. Simply create the following resource:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: nmstate.io/v1
kind: NMState
metadata:
name: nmstate
spec:
probeConfiguration:
dns:
host: root-servers.net&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_nmstate_operator_resource_types"&gt;NMState Operator Resource Types&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The NMState Operator provides the three custom resource types to manage the node networking:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;NodeNetworkState (NNS)&lt;/strong&gt; → The &amp;#34;As-Is&amp;#34; State:&lt;/p&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;This is an automatically generated report of the current status. It effectively tells you: &amp;#34;On Server 1, I currently see Network Card A and B, and IP address X is configured.&amp;#34;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Purpose: To verify the current reality on the ground before you make changes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;NodeNetworkConfigurationPolicy (NNCP)&lt;/strong&gt; → The &amp;#34;To-Be&amp;#34; State (The Blueprint):&lt;/p&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;This is the most critical resource. This resource is used to configure the network on the node. Here you tell the cluster that &amp;#34;I want a bridge named br1 to exist on all servers, and it must be connected to port ens4.&amp;#34;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The operator will try to configure this configuration across your nodes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;NodeNetworkConfigurationEnactment (NNCE)&lt;/strong&gt; → The Result report:&lt;/p&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;This resource is created autoamtically after the NNCP (the blueprint) has been created.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It resports back: This resource is used to enact the network configuration on the node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It reports back on the execution: &amp;#34;Success! The bridge has been built,&amp;#34; or &amp;#34;Failure! Cable not found.&amp;#34;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;With NMState in place, we can now start to configure the network on the node.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_part_1_building_the_bridge_nmstate"&gt;Part 1: Building the Bridge (NMState)&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;By default, Virtual Machines (VMs) are connected to the default pod network of the cluster as any other Pod. Using this network, the VM can communicate with other resources inside the cluster, or any resources that are reachable through the node network. Sometimes the VM needs a connection to a different network. In such a case you must connect the VM to an additional network. The VM will be configured with an additional network interface and is considered as multihomed VM.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;To connect a VM to the physical network, we first need a bridge on the worker nodes. A bridge forwards packets between connected interfaces, similar to a network switch. We have two choices: Linux Bridge or OVS (Open vSwitch) Bridge.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Linux Bridge&lt;/strong&gt;: The sturdy, wooden bridge. Simple, robust, standard Linux kernel tech. Use this for 90% of your use cases (Static IPs, simple VLAN access).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OVS Bridge&lt;/strong&gt;: The magical, floating bridge. Complex, programmable, supports SDN logic. Use this only if you need advanced tunneling or integration with OVN policies on the physical interface.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Let’s create a standard Linux Bridge called &lt;strong&gt;br1&lt;/strong&gt; on all our worker nodes, attached to physical interface &lt;strong&gt;ens4&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We do this by applying a NodeNetworkConfigurationPolicy (NNCP).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: nmstate.io/v1
kind: NodeNetworkConfigurationPolicy
metadata:
name: br1-policy
spec:
nodeSelector:
node-role.kubernetes.io/worker: &amp;#34;&amp;#34; &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
desiredState:
interfaces:
- name: br1 &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
description: Linux bridge linked to ens4 &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
type: linux-bridge &lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
state: up &lt;i class="conum" data-value="5"&gt;&lt;/i&gt;&lt;b&gt;(5)&lt;/b&gt;
ipv4:
dhcp: true &lt;i class="conum" data-value="6"&gt;&lt;/i&gt;&lt;b&gt;(6)&lt;/b&gt;
enabled: true
bridge: &lt;i class="conum" data-value="7"&gt;&lt;/i&gt;&lt;b&gt;(7)&lt;/b&gt;
options:
stp:
enabled: false
port: &lt;i class="conum" data-value="8"&gt;&lt;/i&gt;&lt;b&gt;(8)&lt;/b&gt;
- name: ens4&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Apply to all worker nodes. If omitted, the policy will be applied to all nodes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Name of the bridge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Description of the bridge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Type of the bridge (linux-bridge)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="5"&gt;&lt;/i&gt;&lt;b&gt;5&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;State of the bridge (up)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="6"&gt;&lt;/i&gt;&lt;b&gt;6&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;DHCP is enabled for the bridge (true)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="7"&gt;&lt;/i&gt;&lt;b&gt;7&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Options for the bridge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="8"&gt;&lt;/i&gt;&lt;b&gt;8&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Port of the bridge (ens4)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="admonitionblock caution"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-caution" title="Caution"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
Setting an interface to absent or deleting an NNCP resource does not restore the previous configuration. A cluster administrator must define a policy with the previous configuration to restore settings.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_part_2_defining_the_networkattachmentdefinition_nad"&gt;Part 2: Defining the NetworkAttachmentDefinition (NAD)&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Now that the bridge br1 exists on the nodes, we need to tell OpenShift how to use it. We do this with a NetworkAttachmentDefinition (NAD).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;There are three distinct &amp;#34;Types&amp;#34; of networks you can define in a NAD.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_1_the_linux_bridge_cni_plugin"&gt;1. The Linux Bridge (CNI-Plugin)&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Linux bridges and OVS bridges both connect VMs to additional networks. A Linux bridge offers a simple, stable and sturdy solution and is well established. The OVS bridge on the other hand provides an advanced feature set for software-defined networks and is more challenging to troubleshoot.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Use Case: Direct Layer 2 connection to the physical network.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Behavior: The VM is practically &amp;#34;on the wire&amp;#34; of your datacenter. It can do DHCP with your corporate router.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
name: bridge-network
namespace: my-vm-namespace
spec:
config: &amp;#39;{
&amp;#34;cniVersion&amp;#34;: &amp;#34;0.3.1&amp;#34;,
&amp;#34;name&amp;#34;: &amp;#34;bridge-network&amp;#34;,
&amp;#34;type&amp;#34;: &amp;#34;bridge&amp;#34;, &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
&amp;#34;bridge&amp;#34;: &amp;#34;br1&amp;#34;, &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
&amp;#34;ipam&amp;#34;: {
&amp;#34;type&amp;#34;: &amp;#34;dhcp&amp;#34;
}
}&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Type of the network (bridge)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Name of the bridge (br1)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
type: &amp;#34;bridge&amp;#34; refers to the CNI plugin that utilizes the Linux Bridge we created earlier.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="sect3"&gt;
&lt;h4 id="_a_note_on_ipam_ip_address_management"&gt;A note on IPAM (IP Address Management)&lt;/h4&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;You might have noticed the &amp;#34;ipam&amp;#34; section in the NAD examples. You have three main choices there:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;dhcp&lt;/strong&gt;: Passes DHCP requests to the physical network (requires an external DHCP server).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;static&lt;/strong&gt;: You manually define IPs in the VM config (hard work).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;whereabouts&lt;/strong&gt;: A &amp;#34;Cluster-wide DHCP&amp;#34; for private networks. Perfect for the OVN L2 Overlay scenario where no external DHCP exists.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_2_ovn_kubernetes_l2_overlay"&gt;2. OVN Kubernetes L2 Overlay&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;A switched (layer 2) topology network interconnects workloads through a cluster-wide logical switch.
This configuration allows East-West traffic only (packets between Pods within a cluster).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Use Case: You need a private network between your VMs (East-West traffic only), but you don’t want them to talk to the physical network.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Behavior: It creates a Geneve tunnel (like VXLAN) over the network.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
name: private-overlay
namespace: my-vm-namespace
spec:
config: &amp;#39;{
&amp;#34;cniVersion&amp;#34;: &amp;#34;0.4.0&amp;#34;,
&amp;#34;name&amp;#34;: &amp;#34;private-overlay&amp;#34;,
&amp;#34;type&amp;#34;: &amp;#34;ovn-k8s-cni-overlay&amp;#34;,
&amp;#34;topology&amp;#34;: &amp;#34;layer2&amp;#34;, &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
&amp;#34;netAttachDefName&amp;#34;: &amp;#34;my-vm-namespace/private-overlay&amp;#34; &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
}&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Topology of the network (layer2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;NetworkAttachmentDefinition name (my-vm-namespace/private-overlay)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;A pod with the annotation &lt;code&gt;k8s.v1.cni.cncf.io/networks: private-overlay&lt;/code&gt; will be connected to the private-overlay network.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_3_ovn_kubernetes_secondary_localnet"&gt;3. OVN Kubernetes Secondary Localnet&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;OVN-Kubernetes also supports a &lt;strong&gt;localnet&lt;/strong&gt; topology for secondary networks. This type creates a connection between a secondary network and a physical network, allowing VMs to communicate with destinations that are outside of the cluster.
You must map the secondary network to the OVS bridge on the node. This is done by using a NodeNetworkConfigurationPolicy resource.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Use Case: You want to connect to the physical network (like the Linux Bridge), but you want to leverage OVN features (like NetworkPolicies) on that traffic.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Behavior: Uses Open vSwitch mapping to connect the OVN logic to the physical port.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Let’s create the bridge mapping by applying the following NodeNetworkConfigurationPolicy resource:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: nmstate.io/v1
kind: NodeNetworkConfigurationPolicy
metadata:
name: br0-ovs
spec:
nodeSelector:
node-role.kubernetes.io/worker: &amp;#34;&amp;#34; &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
desiredState:
interfaces:
- name: br0-ovs &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
description: OVS bridge with ens4 as a port
type: ovs-bridge &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
state: up
ipv4:
dhcp: true
enabled: true
bridge:
options:
stp: true
port:
- name: ens4 &lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
ovn:
bridge-mappings:
- localnet: br0-network &lt;i class="conum" data-value="5"&gt;&lt;/i&gt;&lt;b&gt;(5)&lt;/b&gt;
bridge: br0-ovs &lt;i class="conum" data-value="6"&gt;&lt;/i&gt;&lt;b&gt;(6)&lt;/b&gt;
state: present&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Apply to all worker nodes. If omitted, the policy will be applied to all nodes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Name of the bridge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Type of the bridge (ovs-bridge)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Port of the bridge (ens4)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="5"&gt;&lt;/i&gt;&lt;b&gt;5&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Localnet network name (br0-network)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="6"&gt;&lt;/i&gt;&lt;b&gt;6&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;OVS bridge name (br0-ovs)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Now let’s create the NetworkAttachmentDefinition for the localnet network so that VMs can connect to it.
This NAD is created in the namespace of the VM.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
If the NAD is created in the &lt;strong&gt;default&lt;/strong&gt; namespace, the configuration will be available to all namespaces.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
name: ovn-localnet
namespace: my-vm-namespace
spec:
config: &amp;#39;{
&amp;#34;cniVersion&amp;#34;: &amp;#34;0.4.0&amp;#34;,
&amp;#34;name&amp;#34;: &amp;#34;ovn-localnet&amp;#34;, &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
&amp;#34;type&amp;#34;: &amp;#34;ovn-k8s-cni-overlay&amp;#34;, &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
&amp;#34;topology&amp;#34;: &amp;#34;localnet&amp;#34;, &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
&amp;#34;netAttachDefName&amp;#34;: &amp;#34;my-vm-namespace/br0-network&amp;#34; &lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
}&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Name of the network (ovn-localnet)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Type of the network (ovn-k8s-cni-overlay)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Topology of the network (localnet)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Reference to the localnet mapping name defined in the NNCP (my-vm-namespace/br0-network)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_part_3_connecting_the_vm"&gt;Part 3: Connecting the VM&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Finally, we have our &amp;#34;socket&amp;#34; (the NAD). Let’s plug the VM in. In your VirtualMachine manifest, you add the network to the spec.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This can be done via the Web Console or via the CLI.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Via the Web Console:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;In the OpenShift Web Console, navigate to Virtualization → VirtualMachines.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click on the VM you want to connect to the network.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the &amp;#34;Configuration&amp;#34; tab&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select &amp;#34;Network&amp;#34;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="imageblock"&gt;
&lt;div class="content"&gt;
&lt;img src="https://blog.stderr.at/openshift-platform/virtualization/images/network-overview/VM-config.png?width=520px" alt="VM Configuration"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Click &amp;#34;Add network interface&amp;#34;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the Popup enter a name for the interface&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Model keep as &amp;#34;virtio&amp;#34;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the &amp;#34;Network&amp;#34; select the NAD you created in the previous step.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="imageblock"&gt;
&lt;div class="content"&gt;
&lt;img src="https://blog.stderr.at/openshift-platform/virtualization/images/network-overview/VM-additional-nic.png?width=520px" alt="VM Configure additional network interface"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Click &amp;#34;Save&amp;#34;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The VM will now have a Pending state. This is because the VM is waiting for a migration to activate the new network interface.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="imageblock"&gt;
&lt;div class="content"&gt;
&lt;img src="https://blog.stderr.at/openshift-platform/virtualization/images/network-overview/VM-Pending.png?width=640px" alt="VM Pending Configuration"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In the action menu you can select &amp;#34;Migrate&amp;#34; &amp;gt; &amp;#34;Compute&amp;#34; to start the migration process. After a while the new NIC will be active.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="imageblock"&gt;
&lt;div class="content"&gt;
&lt;img src="https://blog.stderr.at/openshift-platform/virtualization/images/network-overview/VM-migrated.png?width=640px" alt="VM Migrated"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Via the CLI:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Here is a VM connected to the Linux Bridge NAD we created in step 1:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: helloworld-vm
namespace: my-vm-namespace
spec:
template:
spec:
domain:
devices:
interfaces:
- name: default
masquerade: {} &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
- name: br0-network
bridge: {} &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
networks:
- name: default
pod: {}
- name: br0-network &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
multus:
networkName: br0-network &lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;The standard Pod Network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Our new connection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;The NAD name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;The NAD name&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Advanced br-ex Configuration with Bonding on OpenShift</title><link>https://blog.stderr.at/openshift-platform/networking/2026-02-05-advanced-br-ex-with-bonding/</link><pubDate>Thu, 05 Feb 2026 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/openshift-platform/networking/2026-02-05-advanced-br-ex-with-bonding/</guid><description>&lt;div class="paragraph"&gt;
&lt;p&gt;In standard OpenShift Container Platform (OCP) installations, the cluster networking operator relies on default scripts to configure the external bridge, &lt;strong&gt;br-ex&lt;/strong&gt;. While these defaults work for simple setups, production environments frequently demand robust and redundant setups, such as LACP bonding or active-backup configurations that the default scripts cannot guess.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In this article, we explore advanced configurations for the &lt;strong&gt;br-ex&lt;/strong&gt; bridge on OpenShift. We will configure a worker node with a high-availability active-backup bond, attach it to an OVS bridge (br-ex), and ensure the node maintains connectivity.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_introduction"&gt;Introduction&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The &lt;strong&gt;br-ex&lt;/strong&gt; (external bridge) is a critical component in OpenShift’s OVN-Kubernetes network architecture. It handles external traffic flowing in and out of the cluster. By default, br-ex is attached to a single network interface, but in production environments, you often need:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;High Availability&lt;/strong&gt;: If one network link fails, traffic continues through the remaining links&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Increased Bandwidth&lt;/strong&gt;: Aggregate bandwidth from multiple interfaces&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Load Balancing&lt;/strong&gt;: Distribute traffic across multiple physical connections&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;If you already have a cluster running, you can migrate your br-ex bridge to NMState. In this article, I have summarized the process step by step.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
The official documentation can be found at &lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/installing_on_bare_metal/index#migrating-br-ex-bridge-nmstate_bare-metal-postinstallation-configuration"&gt;Migrating a configured br-ex bridge to NMState&lt;/a&gt;.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_why_customization_is_necessary"&gt;Why Customization is Necessary&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;By default, OVN-Kubernetes expects a bridge named br-ex to handle traffic exiting the cluster. If you need this bridge to sit on top of a specific bond (like bond-public) rather than a single physical interface, or if you need to enforce specific MAC address policies, you must intervene before the node boots into the cluster.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This method allows you to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Migrate br-ex bridge to NMState and make postinstallation changes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Define complex topologies (Bonds, VLANs, Bridges) declaratively.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Persist configuration across reboots and upgrades via the Machine Config Operator.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Decouple networking from the OS installation process.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_prerequisites"&gt;Prerequisites&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Before configuring bonding with br-ex, ensure you have:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;OpenShift 4.x cluster with OVN-Kubernetes CNI&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OPTIONAL: NMState Operator installed (helps to verify and visualize the configuration on the node)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Multiple network interfaces (interface1 and interface2) available on your nodes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Understanding of your network topology and switch configuration&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_understanding_bonding_modes"&gt;Understanding Bonding Modes&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Linux supports several bonding modes. The most common ones for OpenShift deployments and supported by OpenShift Virtualization are:&lt;/p&gt;
&lt;/div&gt;
&lt;table class="tableblock frame-all grid-all stretch"&gt;
&lt;colgroup&gt;
&lt;col style="width: 16.6666%;"/&gt;
&lt;col style="width: 33.3333%;"/&gt;
&lt;col style="width: 50.0001%;"/&gt;
&lt;/colgroup&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th class="tableblock halign-left valign-top"&gt;Mode&lt;/th&gt;
&lt;th class="tableblock halign-left valign-top"&gt;Name&lt;/th&gt;
&lt;th class="tableblock halign-left valign-top"&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;1&lt;/p&gt;&lt;/td&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;active-backup&lt;/p&gt;&lt;/td&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;Only one interface active at a time. Failover when active fails. No switch configuration required.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;2&lt;/p&gt;&lt;/td&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;balance-xor&lt;/p&gt;&lt;/td&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;XOR-based load balancing. Requires switch configuration.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;4&lt;/p&gt;&lt;/td&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;802.3ad (LACP)&lt;/p&gt;&lt;/td&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;Dynamic link aggregation. Requires switch support for LACP.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
Mode LACP is recommended for production environments &lt;strong&gt;when switch support is available&lt;/strong&gt;, as it provides both redundancy and load balancing.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_the_technical_setup"&gt;The Technical Setup&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We will implement the following network topology:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Physical Interfaces: &lt;strong&gt;interface1&lt;/strong&gt; and &lt;strong&gt;interface2&lt;/strong&gt; (configured as secondary).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bond Interface: &lt;strong&gt;bond-public&lt;/strong&gt; in active-backup mode.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OVS Bridge: &lt;strong&gt;br-ex&lt;/strong&gt; (the standard OVN external bridge) using &lt;strong&gt;bond-public&lt;/strong&gt; as a port.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Host Networking: The node’s IP address will be assigned to the &lt;strong&gt;br-ex&lt;/strong&gt; OVS interface (internal port), effectively moving the management IP from the physical NIC to the bridge.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_migration_process"&gt;Migration Process&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The migration process is quite simple. We will use the MachineConfig Operator to apply the configuration to the node.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This means we will:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;
&lt;p&gt;Create the NMState configuration file&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Encode it as base64&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a MachineConfig object for the required nodes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Apply the MachineConfig object to the required nodes aka reboot the node&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_create_the_nmstate_configuration_file"&gt;Create the NMState configuration file&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;First, we need to create the NMState configuration file. This file will be used to configure the network on the node.
We will define two interfaces &lt;strong&gt;interface1&lt;/strong&gt; and &lt;strong&gt;interface2&lt;/strong&gt; and a bond interface &lt;strong&gt;bond-public&lt;/strong&gt; in active-backup mode. The &lt;strong&gt;br-ex&lt;/strong&gt; bridge will be configured to use the &lt;strong&gt;bond-public&lt;/strong&gt; interface.
The MAC address from &lt;strong&gt;interface2&lt;/strong&gt; will be copied to the &lt;strong&gt;bond-public&lt;/strong&gt; and &lt;strong&gt;br-ex&lt;/strong&gt; interfaces. This ensures consistent MAC addressing for ARP/DHCP and prevents IP conflicts during failover.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock caution"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-caution" title="Caution"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
This is the crucial step in the migration process.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;interfaces:
########################################################
# Interface 1
########################################################
- name: interface1 &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
type: ethernet
state: up
ipv4:
enabled: false
ipv6:
enabled: false
########################################################
# Interface 2
########################################################
- name: interface2 &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
type: ethernet
state: up
ipv4:
enabled: false
ipv6:
enabled: false
########################################################
# Bond interface
########################################################
- description: Bond interface for public LAN interfaces
ipv4:
enabled: false
link-aggregation:
mode: active-backup &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
port: &lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
- interface1
- interface2
name: bond-public &lt;i class="conum" data-value="5"&gt;&lt;/i&gt;&lt;b&gt;(5)&lt;/b&gt;
state: up
type: bond
copy-mac-from: interface2 &lt;i class="conum" data-value="6"&gt;&lt;/i&gt;&lt;b&gt;(6)&lt;/b&gt;
########################################################
# OVS Bridge
########################################################
- name: br-ex &lt;i class="conum" data-value="7"&gt;&lt;/i&gt;&lt;b&gt;(7)&lt;/b&gt;
type: ovs-bridge &lt;i class="conum" data-value="8"&gt;&lt;/i&gt;&lt;b&gt;(8)&lt;/b&gt;
state: up
ipv4:
enabled: false
dhcp: false
ipv6:
enabled: false
dhcp: false
bridge:
options:
mcast-snooping-enable: true
port: &lt;i class="conum" data-value="9"&gt;&lt;/i&gt;&lt;b&gt;(9)&lt;/b&gt;
- name: bond-public
- name: br-ex
########################################################
# OVS Interface
########################################################
- name: br-ex
type: ovs-interface
state: up
copy-mac-from: interface2 &lt;i class="conum" data-value="10"&gt;&lt;/i&gt;&lt;b&gt;(10)&lt;/b&gt;
ipv4:
enabled: true
dhcp: true
auto-route-metric: 48 &lt;i class="conum" data-value="11"&gt;&lt;/i&gt;&lt;b&gt;(11)&lt;/b&gt;
ipv6:
enabled: false&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Specification of interface1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Specification of interface2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Bonding mode: &lt;strong&gt;active-backup&lt;/strong&gt; in this example&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Port of the bond interface (interface1 and interface2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="5"&gt;&lt;/i&gt;&lt;b&gt;5&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Name of the bond interface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="6"&gt;&lt;/i&gt;&lt;b&gt;6&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Copy the MAC address from the interface2 to the bond interface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="7"&gt;&lt;/i&gt;&lt;b&gt;7&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Specification of the bridge (ovs-bridge)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="8"&gt;&lt;/i&gt;&lt;b&gt;8&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Type of the bridge (ovs-bridge)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="9"&gt;&lt;/i&gt;&lt;b&gt;9&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Port of the bridge (bond-public and br-ex)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="10"&gt;&lt;/i&gt;&lt;b&gt;10&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Copy the MAC address from the interface2 to the interface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="11"&gt;&lt;/i&gt;&lt;b&gt;11&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Auto-route metric - Set the parameter to 48 to ensure the br-ex default route always has the highest precedence (lowest metric). This configuration prevents routing conflicts with any other interfaces that are automatically configured by the NetworkManager service.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;With this configuration we can now create a MachineConfig object and roll out the changes.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_encode_the_configuration_as_base64"&gt;Encode the Configuration as base64&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We need to encode the configuration as base64. This is required by the MachineConfig Operator.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Assuming you have the command line tool &lt;code&gt;base64&lt;/code&gt; installed and stored the configuration in a file called &lt;code&gt;br-ex-public.yaml&lt;/code&gt;, you can encode the configuration as follows.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;cat br-ex-public.yaml | base64 -w 0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The result will be a long string of characters. This is the base64 encoded configuration, that we will use in the next step.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_create_the_machineconfig_object"&gt;Create the MachineConfig object&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;To apply this during installation (or via the Machine Config Operator after the deployment), we wrap the NMState YAML above into a MachineConfig object.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We need the base64 encoded string and will place it in a specific path: &lt;strong&gt;/etc/nmstate/openshift/&amp;lt;filename&amp;gt;.yml&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;From the official documentation:
&amp;#34;For each node in your cluster, specify the hostname path to your node and the base-64 encoded Ignition configuration file data for the machine type. The worker role is the default role for nodes in your cluster. You must use the .yml (not yaml !) extension for configuration files, such as $(hostname -s).yml when specifying the short hostname path for each node or all nodes in the MachineConfig manifest file.&amp;#34;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In short: For each node, create a file named &lt;code&gt;&amp;lt;hostname&amp;gt;.yml&lt;/code&gt; containing the base64-encoded NMState configuration. Note that you must use the &lt;code&gt;.yml&lt;/code&gt; extension (not &lt;code&gt;.yaml&lt;/code&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
If you have one single configuration for ALL nodes, you can create one configuration file called cluster.yml. However, I personally do not recommend this approach, as over time new nodes might have different hardware and therefore different network configurations.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In the configuration below, we are targeting a specific worker named wrk01.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
labels:
machineconfiguration.openshift.io/role: worker &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
name: 10-br-ex-wrk01 &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
spec:
config:
ignition:
version: 3.2.0
storage:
files:
- contents:
# This source is the Base64 encoded version of the NMState YAML above
source: data:text/plain;charset=utf-8;base64,&amp;lt;BASE64_ENCODED_STRING&amp;gt; &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
mode: 0644
overwrite: true
# The path determines which node picks up the config.
# Use &amp;#39;cluster.yml&amp;#39; to apply to all nodes in this MachineConfig pool.
path: /etc/nmstate/openshift/wrk01.yml &lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Valid for node with the role worker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Name of the MachineConfig object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Base64 encoded configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Path to the configuration file. This configuration is valid for the node with the hostname wrk01.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_apply_the_machineconfig_object"&gt;Apply the MachineConfig Object&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The above MachineConfig object must now be applied to the cluster. There are two scenarios to do this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect3"&gt;
&lt;h4 id="_scenario_a_post_installation_migration_of_existing_nodes"&gt;Scenario A: Post-Installation / Migration of existing nodes&lt;/h4&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;
&lt;p&gt;Save the YAML to 10-br-ex-wrk01.yaml.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run &lt;strong&gt;oc apply -f 10-br-ex-wrk01.yaml&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reboot the applicable nodes to apply the configuration. You can either do this manually or use the MachineConfigPool to reboot the nodes.
The following example forces a reboot on all nodes with the role worker.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
labels:
machineconfiguration.openshift.io/role: worker
name: 10-force-reboot-worker
spec:
config:
ignition:
version: 3.2.0
storage:
files:
- contents:
source: data:text/plain;charset=utf-8;base64,
mode: 0644
overwrite: true
path: /etc/force-reboot&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect3"&gt;
&lt;h4 id="_scenario_b_during_installation"&gt;Scenario B: During Installation&lt;/h4&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Here the configuration will be applied during the installation process.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;
&lt;p&gt;Run &lt;strong&gt;openshift-install create manifests&lt;/strong&gt; to create the manifest files.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy the YAML file above into the openshift/ directory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run openshift-install create ignition-configs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy your nodes. The configuration will be applied on the very first boot.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_verifying_the_configuration"&gt;Verifying the Configuration&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Once the node is online, it is crucial to verify that the interfaces came up correctly and that traffic is flowing through the bond.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;# Check bond status
oc debug node/&amp;lt;node-name&amp;gt; -- chroot /host cat /proc/net/bonding/bond-public
# Check the state of the specific interfaces
nmstatectl show br-ex bond-public
# Look for state: up on both interfaces and ensure bond-public lists the correct ports (interface1 and interface2).
# Verify br-ex bridge
oc debug node/&amp;lt;node-name&amp;gt; -- chroot /host ovs-vsctl show
#Expected Output:
#
#Plaintext
# Bridge br-ex
# Port br-ex
# Interface br-ex
# type: internal
# Port bond-public
# Interface bond-public
# type: bond&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_test_failover"&gt;Test Failover&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;To test the active-backup bonding:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;
&lt;p&gt;Start a continuous ping to an external IP, for example: &lt;code&gt;ping 8.8.8.8&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Physically disconnect (or administratively down) the active interface (e.g., interface1).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Observe the ping. You should see minimal packet loss (usually just 1 or 2 packets) as traffic fails over to interface2.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_troubleshooting"&gt;Troubleshooting&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_common_issues"&gt;Common Issues&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;strong&gt;Bond not forming:&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Verify both interfaces are physically connected&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check switch port configuration matches bonding mode&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Review NMState logs: &lt;code&gt;oc logs -n openshift-nmstate deployment/nmstate-handler&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;strong&gt;Traffic not flowing:&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Verify br-ex is properly attached to the bond&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check OVN-Kubernetes pods are running&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Review node network configuration: &lt;code&gt;oc debug node/&amp;lt;node-name&amp;gt; — chroot /host nmcli connection show&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_rollback_procedure"&gt;Rollback Procedure&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;If the configuration fails and the node becomes unreachable:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;
&lt;p&gt;Boot the node into single-user mode or use console access&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Remove the NMState configuration file: &lt;code&gt;rm /etc/nmstate/openshift/&amp;lt;hostname&amp;gt;.yml&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Restart NetworkManager: &lt;code&gt;systemctl restart NetworkManager&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The node should revert to the default network configuration&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Alternatively, delete the MachineConfig from the cluster (from a working node):&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;oc delete machineconfig 10-br-ex-wrk01&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This will trigger a rollback on the affected nodes during the next reboot.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;By using MachineConfig to inject an NMState policy at /etc/nmstate/openshift/, we successfully bypassed the default network scripts. We created a robust OVS bridge (br-ex) backed by an active-backup bond (bond-public), ensuring that our OpenShift worker node (wrk01) is both redundant and compliant with OVN-Kubernetes networking requirements.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Configuring br-ex with bonding provides essential redundancy and can improve network throughput for your OpenShift cluster. Choose the appropriate bonding mode based on your switch capabilities and requirements:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;strong&gt;active-backup&lt;/strong&gt; for simple failover without switch configuration&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;strong&gt;802.3ad (LACP)&lt;/strong&gt; for optimal redundancy and load balancing when switches support it&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;strong&gt;balance-alb&lt;/strong&gt; when you need load balancing but lack switch support&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Always test your configuration in a non-production environment before applying to production clusters.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item></channel></rss>