Skip to content

Commit af06130

Browse files
committed
sno-nxsw-netconf scenario
Assisted-By: Claude Code/claude-4.5-sonnet Signed-off-by: Harald Jensås <hjensas@redhat.com>
1 parent 527a5ba commit af06130

18 files changed

Lines changed: 3419 additions & 0 deletions
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
# SNO-NXSW-NETCONF Scenario
2+
3+
## Overview
4+
5+
The `sno-nxsw-netconf` scenario is a Single Node OpenShift (SNO) deployment scenario
6+
for HotStack that deploys OpenStack on OpenShift with ironic bare metal
7+
provisioning capabilities and network switch integration using networking-baremetal's
8+
netconf-openconfig ML2 driver.
9+
10+
## Architecture
11+
12+
This scenario provisions:
13+
14+
- **1x Controller Node**: Management and DNS/DHCP services
15+
- **1x OpenShift Master Node**: Single node OpenShift cluster running OpenStack services
16+
- **1x Switch Node**: NXSW switch with trunk ports for tenant VLAN networks
17+
- **2x Ironic Nodes**: Virtual bare metal nodes for testing Ironic provisioning workflows
18+
19+
## Features
20+
21+
- **Complete OpenStack Stack**: Full OpenStack deployment with ironic bare
22+
metal service
23+
- **Network Switch Integration**: Automated switch configuration with
24+
POAP (Power-On Auto Provisioning) and networking-baremetal netconf-openconfig driver
25+
- **NETCONF/OpenConfig**: Uses standard NETCONF protocol and vendor-neutral
26+
OpenConfig YANG models for switch configuration
27+
- **Complete Networking**: All OpenStack service networks with dedicated
28+
ironic networks
29+
- **SNO Deployment**: Single node OpenShift optimized for OpenStack services
30+
- **Development Ready**: Ideal for testing and development environments
31+
- **Bare Metal Provisioning**: Ironic service with 2 nodes for testing bare
32+
metal workflows
33+
- **Ironic Neutron Agent**: Includes ironic-neutron-agent for handling port
34+
binding notifications from Ironic to Neutron
35+
36+
## Networks
37+
38+
- **machine-net**: 192.168.32.0/24 - External access network
39+
- **ctlplane-net**: 192.168.122.0/24 - Control plane network
40+
- **internal-api-net**: 172.17.0.0/24 - OpenStack internal API network
41+
- **storage-net**: 172.18.0.0/24 - Storage network
42+
- **tenant-net**: 172.19.0.0/24 - Tenant network for OpenStack workloads
43+
- **ironic-net**: 172.20.1.0/24 - Ironic network for bare metal provisioning
44+
- **tenant-vlan103**: 172.20.3.0/24 - Tenant VLAN network (VLAN 103)
45+
- **tenant-vlan104**: 172.20.4.0/24 - Tenant VLAN network (VLAN 104)
46+
- **ironic0-br-net**: 172.20.5.0/29 - Ironic0 bridge network
47+
- **ironic1-br-net**: 172.20.5.8/29 - Ironic1 bridge network
48+
49+
## Switch Instance Configuration (Nested Virtualization)
50+
51+
This scenario uses a **nested virtualization** approach where:
52+
1. A Linux host VM (`hotstack-switch-host` image) runs on OpenStack
53+
2. Inside that VM, the NXOS switch runs as a nested KVM guest
54+
3. Network interfaces are bridged between the host VM and the nested switch
55+
56+
### Host VM Network Interfaces
57+
58+
```text
59+
Host VM (hotstack-switch-host):
60+
├── eth0: machine-net (192.168.32.6) - Host VM management (unbridged, for SSH)
61+
├── eth1: machine-net (192.168.32.7) - Nested switch management (bridged to sw-br0)
62+
├── eth2: trunk (ironic:101, tenant-vlan103:103, tenant-vlan104:104) - bridged to sw-br1
63+
├── eth3: ironic0-br-net (bridged to sw-br2)
64+
└── eth4: ironic1-br-net (bridged to sw-br3)
65+
```
66+
67+
### Nested NXOS Switch Interfaces
68+
69+
```text
70+
Nested NXOS Switch:
71+
├── eth0: sw-br0 → Switch management IP (192.168.32.7, via POAP)
72+
├── eth1: sw-br1 → Trunk port (VLANs 101-104)
73+
├── eth2: sw-br2 → Access port to ironic0-br-net
74+
└── eth3: sw-br3 → Access port to ironic1-br-net
75+
```
76+
77+
The nested switch boots and is automatically configured via POAP (Power-On Auto Provisioning).
78+
79+
### VLAN Mapping
80+
81+
- **VLAN 101**: ironic (172.20.1.0/24)
82+
- **VLAN 102**: Default native VLAN
83+
- **VLAN 103**: tenant-vlan103 (172.20.3.0/24)
84+
- **VLAN 104**: tenant-vlan104 (172.20.4.0/24)
85+
86+
The switch uses the `nxsw` image and provides dual trunk ports for redundancy
87+
and high availability.
88+
89+
### POAP (Power-On Auto Provisioning)
90+
91+
POAP is a Cisco NX-OS feature that automates the initial configuration of
92+
network switches. When the switch boots up, it automatically:
93+
94+
1. **Downloads Configuration**: Fetches the switch configuration from a
95+
TFTP/HTTP server
96+
2. **Applies Settings**: Automatically configures interfaces, VLANs, and
97+
network settings
98+
3. **Enables Services**: Activates required network services (NETCONF, LACP, LLDP)
99+
4. **Validates Setup**: Performs integrity checks using MD5 checksums
100+
101+
In this scenario, POAP enables zero-touch deployment of the NX-OS switch with pre-configured:
102+
103+
- **Interface Configuration**: Trunk and access ports for tenant VLANs
104+
- **VLAN Setup**: VLANs for network segmentation
105+
- **Management Settings**: IP addressing, DNS, and routing configuration
106+
- **Security**: User accounts and access control
107+
108+
## Ironic Nodes
109+
110+
The scenario includes 2 virtual bare metal nodes for testing Ironic provisioning:
111+
112+
### Ironic Node 0
113+
114+
- **Network**: ironic0-br-net (172.20.5.0/29)
115+
- **Purpose**: Bare metal provisioning testing
116+
- **Configuration**: Virtual media boot capable with sushy-tools
117+
118+
### Ironic Node 1
119+
120+
- **Network**: ironic1-br-net (172.20.5.8/29)
121+
- **Purpose**: Bare metal provisioning testing
122+
- **Configuration**: Virtual media boot capable with sushy-tools
123+
124+
## Networking-Baremetal Integration
125+
126+
This scenario uses the `networking-baremetal` ML2 mechanism driver with the
127+
`netconf-openconfig` device driver. This provides:
128+
129+
### NETCONF/OpenConfig Driver Features
130+
131+
- **Standards-Based**: Uses NETCONF protocol (RFC 6241) and OpenConfig YANG models
132+
- **Vendor Support**: Tested with Cisco NXOS and Arista EOS switches
133+
- **LACP Support**: Can manage Link Aggregation Control Protocol (LACP) port channels
134+
- **VLAN Management**: Automatic VLAN creation and port configuration
135+
- **Port MTU**: Supports configuring MTU on switch ports
136+
- **SSH Key Authentication**: Supports password and SSH key authentication
137+
138+
### Configuration
139+
140+
The switch configuration is defined in `manifests/networking-baremetal/config.yaml`:
141+
142+
- **Driver**: `netconf-openconfig` - Uses NETCONF with OpenConfig YANG models
143+
- **Device Parameters**: `name:nexus` - ncclient device handler for Cisco NXOS
144+
- **Switch ID**: MAC address of the switch for identification
145+
- **Physical Networks**: Maps OpenStack physical networks to the device
146+
- **LACP Management**: Configures automatic management of LACP aggregates
147+
- **Port ID Substitution**: Converts LLDP port names to NETCONF port format
148+
149+
### Ironic Neutron Agent
150+
151+
The `ironic-neutron-agent` service handles communication between Ironic and Neutron:
152+
153+
- Listens for port binding notifications from Neutron
154+
- Triggers switch port configuration when Ironic nodes are provisioned
155+
- Manages VLAN assignment and port activation
156+
157+
## Usage
158+
159+
This scenario is ideal for:
160+
161+
- Testing OpenStack deployments with networking-baremetal ML2 driver
162+
- Validating bare metal provisioning workflows with Ironic
163+
- Network switch integration testing with NETCONF/OpenConfig
164+
- Development and testing of networking-baremetal functionality
165+
- Evaluating vendor-neutral network automation with OpenConfig
166+
167+
## Files
168+
169+
- `bootstrap_vars.yml`: Main configuration variables
170+
- `heat_template.yaml`: OpenStack Heat template for infrastructure
171+
- `automation-vars.yml`: Automation pipeline definition
172+
- `manifests/`: OpenShift/Kubernetes manifests
173+
- `test-operator/`: Test automation configuration
174+
175+
## Switch Host Image
176+
177+
This scenario uses the `hotstack-switch-host` image, which is a CentOS 9 Stream
178+
image with KVM/libvirt and scripts to run nested switch VMs.
179+
180+
### Building the Switch Host Image
181+
182+
The switch host image must be built with the NXOS disk image embedded:
183+
184+
1. Build the base switch-host image:
185+
```bash
186+
cd images/
187+
make switch-host
188+
```
189+
190+
2. Add the NXOS image to the switch-host:
191+
```bash
192+
# The NXOS qcow2 image will be placed in /opt/nxos/ inside the image
193+
make switch-host-nxos NXOS_IMAGE=/path/to/nexus9300v.10.5.3.F.qcow2
194+
```
195+
196+
3. Upload to OpenStack:
197+
```bash
198+
openstack image create hotstack-switch-host \
199+
--disk-format qcow2 \
200+
--file switch-host-nxos.qcow2 \
201+
--public \
202+
--property hw_disk_bus=scsi \
203+
--property hw_vif_model=virtio \
204+
--property hw_video_model=qxl
205+
```
206+
207+
### NXOS Version Requirements
208+
209+
**Important:** For networking-baremetal netconf-openconfig support, you need:
210+
- **NXOS 10.2 or later** - Required for OpenConfig YANG model support
211+
- NXOS 9.x versions do NOT have adequate OpenConfig support
212+
213+
See [images/README.md](../../images/README.md) and
214+
[switch-host-scripts/README.md](../../images/switch-host-scripts/README.md)
215+
for detailed instructions.
216+
217+
## Switch NETCONF Configuration
218+
219+
NETCONF is automatically enabled on the NXOS switch via the POAP (Power-On Auto
220+
Provisioning) configuration file (`poap.cfg`). The following features are enabled:
221+
222+
- `feature netconf` - Enables NETCONF protocol on port 830
223+
- `feature lacp` - Enables Link Aggregation Control Protocol
224+
225+
After the switch boots and applies the POAP configuration, you can verify NETCONF
226+
is running:
227+
228+
```bash
229+
switch# show netconf status
230+
```
231+
232+
## Container Image Requirements
233+
234+
The standard OpenStack operator images include the required networking-baremetal
235+
components:
236+
237+
- `networking-baremetal` - ML2 mechanism driver and ironic-neutron-agent
238+
- `ncclient` - Python NETCONF client library
239+
- `pyangbind` - Python bindings for YANG models
240+
- OpenConfig Python bindings - For OpenConfig YANG models
241+
242+
## Deployment
243+
244+
Follow the standard HotStack deployment process with this scenario by setting
245+
the scenario name to `sno-nxsw-netconf` in your deployment configuration.
246+
247+
### Prerequisites
248+
249+
1. **Switch Host Image**: The `hotstack-switch-host` image with NXOS 10.2+
250+
embedded must be available in your OpenStack cloud
251+
2. **Nested Virtualization**: The OpenStack compute nodes must support nested
252+
virtualization (Intel VT-x/AMD-V with nested EPT/RVI enabled)
253+
3. **Sufficient Resources**: The switch host requires a `hotstack.xlarge` flavor
254+
or larger to run the nested NXOS VM
255+
256+
### How It Works
257+
258+
1. Heat creates the switch-host VM with multiple network ports
259+
2. Cloud-init configures the host and writes `/etc/hotstack-switch-vm/config`
260+
3. The `start-switch-vm.sh` script:
261+
- Creates Linux bridges for each network interface
262+
- Starts the nested NXOS VM using libvirt/KVM
263+
- Bridges host interfaces to the nested switch VM
264+
4. The NXOS switch boots and uses POAP to fetch its configuration from the
265+
controller
266+
5. After POAP completes, the switch is ready for netconf-openconfig connections
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
---
2+
stages:
3+
- name: TopoLVM Dependencies
4+
stages: >-
5+
{{
6+
lookup("ansible.builtin.template",
7+
"common/stages/topolvm-deps-stages.yaml.j2")
8+
}}
9+
10+
- name: Dependencies
11+
stages: >-
12+
{{
13+
lookup("ansible.builtin.template",
14+
"common/stages/deps-stages.yaml.j2")
15+
}}
16+
17+
- name: Cinder LVM
18+
stages: >-
19+
{{
20+
lookup("ansible.builtin.file",
21+
"common/stages/cinder-lvm-label-stages.yaml")
22+
}}
23+
24+
- name: TopoLVM
25+
stages: >-
26+
{{
27+
lookup("ansible.builtin.template",
28+
"common/stages/topolvm-stages.yaml.j2")
29+
}}
30+
31+
- name: OLM Openstack
32+
stages: >-
33+
{{
34+
lookup("ansible.builtin.template",
35+
"common/stages/olm-openstack-stages.yaml.j2")
36+
}}
37+
38+
- name: NodeNetworkConfigurationPolicy (nncp)
39+
manifest: manifests/networking/nncp.yaml
40+
wait_conditions:
41+
- >-
42+
oc wait -n openstack nncp -l osp/nncm-config-type=standard
43+
--for jsonpath='{.status.conditions[0].reason}'=SuccessfullyConfigured
44+
--timeout=180s
45+
46+
- name: NetworkAttchmentDefinition (NAD)
47+
manifest: manifests/networking/nad.yaml
48+
49+
- name: MetalLB - L2Advertisement and IPAddressPool
50+
manifest: manifests/networking/metallb.yaml
51+
52+
- name: Netconfig
53+
manifest: manifests/networking/netconfig.yaml
54+
55+
- name: Networking Baremetal config (netconf-openconfig)
56+
manifest: manifests/networking-baremetal/config.yaml
57+
wait_conditions:
58+
- >-
59+
oc wait -n openstack secret neutron-switch-config
60+
--for jsonpath='{.metadata.name}'=neutron-switch-config
61+
--timeout=30s
62+
63+
- name: OpenstackControlPlane
64+
manifest: manifests/control-plane.yaml
65+
wait_conditions:
66+
- >-
67+
oc -n openstack wait openstackcontrolplanes.core.openstack.org controlplane
68+
--for condition=OpenStackControlPlaneDNSReadyCondition --timeout=600s
69+
70+
- name: Extra DNS LoadBalancer on Ironic network
71+
manifest: manifests/dnsmasq-dns-ironic.yaml
72+
wait_conditions:
73+
- >-
74+
oc wait -n openstack service dnsmasq-dns-ironic
75+
--for jsonpath='.status.loadBalancer' --timeout=60s
76+
77+
- name: Wait for OpenstackControlPlane
78+
wait_conditions:
79+
- >-
80+
oc wait -n openstack openstackcontrolplane controlplane
81+
--for condition=Ready --timeout=30m
82+
83+
- name: Update openstack-operators OLM
84+
stages: >-
85+
{{
86+
lookup('ansible.builtin.template',
87+
'common/stages/openstack-olm-update.yaml.j2')
88+
}}
89+
run_conditions:
90+
- >-
91+
{{
92+
openstack_operators_update is defined and
93+
openstack_operators_update | bool
94+
}}
95+
96+
- name: Wait for condition MinorUpdateAvailable True
97+
wait_conditions:
98+
- >-
99+
oc -n openstack wait openstackversions.core.openstack.org controlplane
100+
--for=condition=MinorUpdateAvailable=True --timeout=10m
101+
run_conditions:
102+
- "{{ openstack_update is defined and openstack_update | bool }}"
103+
104+
- name: "Minor update :: Create OpenStackVersion patch"
105+
documentation: |
106+
This creates a patch file `{{ manifests_dir }}/patches/openstack_version_patch.yaml`
107+
If `openstack_update_custom_images` is defined it will populate the customContainerImages
108+
in the OpenstackVersion YAML patch.
109+
shell: >-
110+
{{
111+
lookup('ansible.builtin.template',
112+
'common/scripts/create_openstack_version_patch.sh.j2')
113+
}}
114+
run_conditions:
115+
- "{{ openstack_update is defined and openstack_update | bool }}"
116+
117+
- name: "Minor update :: Update the target version in the OpenStackVersion custom resource (CR)"
118+
documentation: |
119+
The `hotstack-openstack-version-patch` script will get the `availableVersion`
120+
and us it to replace the string `__TARGET_VERSION__` in the patch file and
121+
apply the patch using `oc patch` command.
122+
command: >-
123+
hotstack-openstack-version-patch --namespace openstack --name controlplane
124+
--file {{ manifests_dir }}/patches/openstack_version_patch.yaml
125+
wait_conditions:
126+
- oc -n openstack wait openstackversions.core.openstack.org controlplane
127+
--for=condition=Ready --timeout=10m
128+
run_conditions:
129+
- "{{ openstack_update is defined and openstack_update | bool }}"

0 commit comments

Comments
 (0)