diff --git a/scenarios/networking-lab/devstack-ceos-vlan-netconf/README.md b/scenarios/networking-lab/devstack-ceos-vlan-netconf/README.md new file mode 100644 index 00000000..6be26c04 --- /dev/null +++ b/scenarios/networking-lab/devstack-ceos-vlan-netconf/README.md @@ -0,0 +1,30 @@ +# Devstack with Arista cEOS VLAN Trunking (NETCONF OpenConfig) + +Single-switch topology with 1 Arista cEOS switch, 1 Devstack node, 2 Ironic nodes, and 1 controller. +Uses networking-generic-switch with the `netconf_openconfig` driver for NETCONF-based switch management. + +## Topology + +![Topology Diagram](topology-diagram.svg) + +Management: `192.168.32.0/24` | VLANs: 100-105 | MTU: 1500 + +## Deployment + +Deploy the scenario: + +```bash +ansible-playbook -e @scenarios/networking-lab/devstack-ceos-vlan-netconf/bootstrap_vars.yml -e os_cloud= bootstrap_devstack.yml +``` + +## Accessing + +Access the switch and devstack nodes via SSH from the controller. + +```bash +# Switch +ssh admin@switch.stack.lab + +# Devstack +ssh stack@devstack.stack.lab +``` diff --git a/scenarios/networking-lab/devstack-ceos-vlan-netconf/TROUBLESHOOTING.md b/scenarios/networking-lab/devstack-ceos-vlan-netconf/TROUBLESHOOTING.md new file mode 100644 index 00000000..1ff85b6b --- /dev/null +++ b/scenarios/networking-lab/devstack-ceos-vlan-netconf/TROUBLESHOOTING.md @@ -0,0 +1,189 @@ +# Troubleshooting Network Connectivity + +## Access Methods + +- **Arista cEOS Switch**: `ssh admin@switch.stack.lab` (password: `admin`) +- **Switch Container Host**: `ssh zuul@switch-host.stack.lab` +- **Devstack**: `ssh stack@devstack.stack.lab` + +## Verify Network Topology + +### Arista cEOS Switch VLAN Configuration +```bash +# Check VLAN configuration +show vlan + +# Check interface status +show interfaces status + +# Check interface switchport configuration +show interfaces switchport + +# Check trunk port configuration +show interfaces Ethernet1 switchport + +# Check specific interface details +show interfaces Ethernet1 +show interfaces Ethernet2 +show interfaces Ethernet3 +``` + +### Devstack VLAN Interfaces +```bash +# Check trunk and bridge interfaces +ip link show | grep -E "trunk0|br-ex" +``` + +## Check Interface Statistics + +### On Arista cEOS Switch +```bash +# Check all interface counters +show interfaces counters + +# Check specific interface counters +show interfaces Ethernet1 counters +show interfaces Ethernet2 counters +show interfaces Ethernet3 counters + +# Check for errors +show interfaces counters errors + +# Check interface status and statistics +show interfaces Ethernet1 +show interfaces Ethernet2 +show interfaces Ethernet3 + +# Look for: +# - RX/TX errors +# - RX/TX dropped packets +# - CRC errors +# - Collisions +``` + +### On Devstack +```bash +# Check trunk interface +ip -s link show trunk0 + +# Check bridge interfaces +ip -s link show br-ex +ip -s link show br-ex.103 + +# Look for dropped or error counters +``` + +## Verify VLAN Configuration + +### Check VLANs on Arista Switch +```bash +# Show all VLANs +show vlan + +# Show VLAN brief summary +show vlan brief + +# Show which interfaces are in which VLANs +show vlan id 100 +show vlan id 103 +show vlan id 104 +show vlan id 105 +``` + +### Check Trunk Configuration +```bash +# Verify trunk allowed VLANs +show interfaces Ethernet1 trunk + +# Check spanning-tree status (should show portfast enabled) +show spanning-tree interface Ethernet1 +``` + +## NETCONF Troubleshooting + +### Verify NETCONF Connectivity +```bash +# Test NETCONF from devstack to switch (port 830) +ssh -s -p 830 admin@switch.stack.lab netconf + +# Check NETCONF management API on switch +show management api netconf +``` + +### Check networking-generic-switch Logs +```bash +# On devstack, check neutron-server logs for NGS activity +sudo journalctl -u devstack@q-svc -f | grep -i generic +``` + +## Capture Network Traffic + +### Basic Packet Capture + +**On Devstack:** +```bash +# Watch traffic on VLAN 103 +sudo tcpdump -i trunk0 -evnn vlan 103 + +# Filter by port (e.g., Ironic API on port 80) +sudo tcpdump -i trunk0 -evnn vlan 103 and port 80 + +# More verbose output with packet contents +sudo tcpdump -i trunk0 -evvvnXX vlan 103 +``` + +**On Arista cEOS Switch (using bash from EOS):** +```bash +# Enter bash shell from EOS +bash + +# Capture on baremetal-facing port +sudo tcpdump -i eth3 -evnn # Ethernet2 (ironic0) +sudo tcpdump -i eth4 -evnn # Ethernet3 (ironic1) + +# Capture on trunk to devstack +sudo tcpdump -i eth2 -evnn vlan 103 # Ethernet1 (trunk) + +# Exit bash when done +exit +``` + +## Common Issues + +### VLANs Not Configured on Switch +If networking-generic-switch is not configuring VLANs: +```bash +# Verify NGS can connect +ssh admin@switch.stack.lab "show version" + +# Check that management API is enabled +show management api http-commands + +# Verify VLANs exist +show vlan + +# Check interface configuration +show running-config interfaces +``` + +### Interface Not Passing Traffic +```bash +# Verify interface is up +show interfaces status | include Ethernet + +# Check for errors +show interfaces counters errors + +# Verify spanning-tree is not blocking +show spanning-tree +``` + +### Access Port Not in Correct VLAN +```bash +# Check access VLAN assignment +show interfaces Ethernet2 switchport +show interfaces Ethernet3 switchport + +# Verify the port is in access mode +show running-config interfaces Ethernet2 +``` diff --git a/scenarios/networking-lab/devstack-ceos-vlan-netconf/automation-vars.yml b/scenarios/networking-lab/devstack-ceos-vlan-netconf/automation-vars.yml new file mode 100644 index 00000000..e6f8866a --- /dev/null +++ b/scenarios/networking-lab/devstack-ceos-vlan-netconf/automation-vars.yml @@ -0,0 +1,65 @@ +--- +stages: + - name: Enroll nodes in devstack ironic + documentation: >- + Registers physical baremetal nodes with the Ironic service in the DevStack + deployment using the node definitions from ironic_nodes.yaml. This creates + Ironic node records with BMC access credentials, hardware profiles, and port + configurations for networking-generic-switch integration. + shell: | + set -xe -o pipefail + + NODES_FILE=/home/zuul/data/ironic_nodes.yaml + + # Enroll the nodes + openstack --os-cloud devstack-admin baremetal create "$NODES_FILE" + + echo "Nodes enrolled successfully" + openstack --os-cloud devstack-admin baremetal node list + + - name: Wait for ironic nodes to reach enroll state + documentation: >- + Monitors node state transition to 'enroll' status, indicating that Ironic + has successfully registered the nodes and validated basic BMC connectivity. + This is the first state in the baremetal provisioning lifecycle. + shell: | + set -xe -o pipefail + + counter=0 + max_retries=60 + sleep_interval=5 + + echo "Waiting for all nodes to reach 'enroll' state..." + + until ! openstack --os-cloud devstack-admin baremetal node list -f value -c "Provisioning State" | grep -v "enroll"; do + ((counter++)) + if (( counter > max_retries )); then + echo "ERROR: Timeout waiting for nodes to reach enroll state" + openstack --os-cloud devstack-admin baremetal node list + exit 1 + fi + echo "Attempt $counter/$max_retries - waiting ${sleep_interval}s..." + sleep ${sleep_interval} + done + + echo "All nodes successfully reached enroll state" + openstack --os-cloud devstack-admin baremetal node list + + - name: Manage nodes + documentation: >- + Transitions nodes from 'enroll' to 'manageable' state. This validates + basic hardware connectivity and prepares nodes for further operations. + shell: | + set -x -o pipefail + + # Get list of node UUIDs + node_uuids=$(openstack --os-cloud devstack-admin baremetal node list -f value -c UUID) + + # Manage each node with --wait (300 second timeout) + for uuid in $node_uuids; do + echo "Managing node: $uuid" + openstack --os-cloud devstack-admin baremetal node manage --wait 300 $uuid + done + + echo "All nodes successfully reached manageable state" + openstack --os-cloud devstack-admin baremetal node list diff --git a/scenarios/networking-lab/devstack-ceos-vlan-netconf/bootstrap_vars.yml b/scenarios/networking-lab/devstack-ceos-vlan-netconf/bootstrap_vars.yml new file mode 100644 index 00000000..4ac886ca --- /dev/null +++ b/scenarios/networking-lab/devstack-ceos-vlan-netconf/bootstrap_vars.yml @@ -0,0 +1,46 @@ +--- +# Bootstrap configuration for devstack-ceos-vlan-netconf scenario + +# OpenStack cloud configuration +os_cloud: default +os_floating_network: public +os_router_external_network: public + +# Scenario configuration +scenario: devstack-ceos-vlan-netconf +scenario_dir: scenarios/networking-lab +stack_template_path: "{{ scenario_dir }}/{{ scenario }}/heat_template.yaml" +automation_vars_file: "{{ scenario_dir }}/{{ scenario }}/automation-vars.yml" + +# DNS and NTP +ntp_servers: [] +dns_servers: + - 8.8.8.8 + - 8.8.4.4 + +# Stack naming +stack_name: "hs-{{ scenario | replace('/', '-') }}-{{ zuul.build[:8] | default('no-zuul') }}" + +# Stack parameters +stack_parameters: + dns_servers: "{{ dns_servers }}" + ntp_servers: "{{ ntp_servers }}" + controller_ssh_pub_key: "{{ controller_ssh_pub_key | default('') }}" + dataplane_ssh_pub_key: "{{ dataplane_ssh_pub_key | default('') }}" + router_external_network: "{{ os_router_external_network | default('public') }}" + floating_ip_network: "{{ os_floating_network | default('public') }}" + controller_params: + image: hotstack-controller + flavor: hotstack.small + devstack_params: + image: ubuntu-noble-server + flavor: hotstack.large + switch_params: + image: hotstack-ceos + flavor: hotstack.medium + ironic_params: + image: CentOS-Stream-GenericCloud-9 + flavor: hotstack.medium + +# Controller role configuration +controller_install_openstack_client: true diff --git a/scenarios/networking-lab/devstack-ceos-vlan-netconf/heat_template.yaml b/scenarios/networking-lab/devstack-ceos-vlan-netconf/heat_template.yaml new file mode 100644 index 00000000..1c92ee45 --- /dev/null +++ b/scenarios/networking-lab/devstack-ceos-vlan-netconf/heat_template.yaml @@ -0,0 +1,736 @@ +--- +heat_template_version: rocky + +description: > + Heat template for networking lab with single Arista cEOS switch using VLAN trunking and NETCONF OpenConfig. + Includes 1 switch, 1 devstack node, and 2 ironic nodes. + +parameters: + dns_servers: + type: comma_delimited_list + default: + - 8.8.8.8 + - 8.8.4.4 + ntp_servers: + type: comma_delimited_list + default: [] + controller_ssh_pub_key: + type: string + dataplane_ssh_pub_key: + type: string + router_external_network: + type: string + default: public + floating_ip_network: + type: string + default: public + net_value_specs: + type: json + default: {} + + controller_params: + type: json + default: + image: hotstack-controller + flavor: hotstack.small + devstack_params: + type: json + default: + image: ubuntu-noble-server + flavor: hotstack.large + ironic_params: + type: json + default: + image: CentOS-Stream-GenericCloud-9 + flavor: hotstack.medium + switch_params: + type: json + default: + image: hotstack-ceos + flavor: hotstack.medium + cdrom_disk_bus: + type: string + description: > + Disk bus type for CDROM device. 'sata' may be required for older versions + of OpenStack. Heat patch https://review.opendev.org/c/openstack/heat/+/966688 + is needed for 'sata' support. + default: scsi + constraints: + - allowed_values: + - sata + - scsi + +resources: + # + # Networks + # + machine-net: + type: OS::Neutron::Net + properties: + port_security_enabled: false + value_specs: {get_param: net_value_specs} + + # Simple bridge networks for server attachments + devstack-br-net: + type: OS::Neutron::Net + properties: + port_security_enabled: false + value_specs: {get_param: net_value_specs} + + ironic0-br-net: + type: OS::Neutron::Net + properties: + port_security_enabled: false + value_specs: {get_param: net_value_specs} + + ironic1-br-net: + type: OS::Neutron::Net + properties: + port_security_enabled: false + value_specs: {get_param: net_value_specs} + + trunk-net: + type: OS::Neutron::Net + properties: + port_security_enabled: false + value_specs: {get_param: net_value_specs} + + tenant-vlan103: + type: OS::Neutron::Net + properties: + port_security_enabled: false + value_specs: {get_param: net_value_specs} + + tenant-vlan104: + type: OS::Neutron::Net + properties: + port_security_enabled: false + value_specs: {get_param: net_value_specs} + + tenant-vlan105: + type: OS::Neutron::Net + properties: + port_security_enabled: false + value_specs: {get_param: net_value_specs} + + # + # Subnets + # + machine-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: machine-net} + ip_version: 4 + cidr: 192.168.32.0/24 + enable_dhcp: true + dns_nameservers: + - 192.168.32.254 + + devstack-br-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: devstack-br-net} + ip_version: 4 + cidr: 172.20.10.0/29 + enable_dhcp: false + gateway_ip: null + + ironic0-br-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: ironic0-br-net} + ip_version: 4 + cidr: 172.20.11.0/29 + enable_dhcp: false + gateway_ip: null + + ironic1-br-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: ironic1-br-net} + ip_version: 4 + cidr: 172.20.12.0/29 + enable_dhcp: false + gateway_ip: null + + trunk-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: trunk-net} + ip_version: 4 + cidr: 172.20.2.0/24 + enable_dhcp: false + gateway_ip: null + + tenant-vlan103-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: tenant-vlan103} + ip_version: 4 + cidr: 172.20.3.0/24 + enable_dhcp: false + gateway_ip: null + + tenant-vlan104-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: tenant-vlan104} + ip_version: 4 + cidr: 172.20.4.0/24 + enable_dhcp: false + gateway_ip: null + + tenant-vlan105-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: tenant-vlan105} + ip_version: 4 + cidr: 172.20.5.0/24 + enable_dhcp: false + gateway_ip: null + + # + # Routers + # + router: + type: OS::Neutron::Router + properties: + admin_state_up: true + external_gateway_info: + network: {get_param: router_external_network} + + machine-net-router-interface: + type: OS::Neutron::RouterInterface + properties: + router: {get_resource: router} + subnet: {get_resource: machine-subnet} + + # + # Controller Instance + # + controller_users: + type: OS::Heat::CloudConfig + properties: + cloud_config: + users: + - default + - name: zuul + gecos: "Zuul user" + sudo: ALL=(ALL) NOPASSWD:ALL + ssh_authorized_keys: + - {get_param: controller_ssh_pub_key} + + controller-write-files: + type: OS::Heat::CloudConfig + properties: + cloud_config: + write_files: + - path: /etc/dnsmasq.conf + content: | + # dnsmasq service config + # Include all files in /etc/dnsmasq.d except RPM backup files + conf-dir=/etc/dnsmasq.d,.rpmnew,.rpmsave,.rpmorig + no-resolv + owner: root:dnsmasq + - path: /etc/dnsmasq.d/forwarders.conf + content: + str_replace: + template: | + # DNS forwarders records + server=$dns1 + server=$dns2 + params: + $dns1: {get_param: [dns_servers, 0]} + $dns2: {get_param: [dns_servers, 1]} + owner: root:dnsmasq + - path: /etc/dnsmasq.d/host_records.conf + content: + str_replace: + template: | + # Host records + host-record=controller-0.stack.lab,$controller0 + host-record=switch-host.stack.lab,$switch_host + host-record=switch.stack.lab,$switch + host-record=devstack.stack.lab,$devstack + params: + $controller0: {get_attr: [controller-machine-port, fixed_ips, 0, ip_address]} + $switch_host: {get_attr: [switch-machine-port, fixed_ips, 0, ip_address]} + $switch: {get_attr: [switch-switch-mgmt-port, fixed_ips, 0, ip_address]} + $devstack: {get_attr: [devstack-machine-port, fixed_ips, 0, ip_address]} + owner: root:dnsmasq + - path: /etc/resolv.conf + content: | + nameserver: 127.0.0.1 + owner: root:root + - path: /etc/NetworkManager/conf.d/98-rc-manager.conf + content: | + [main] + rc-manager=unmanaged + owner: root:root + + controller-runcmd: + type: OS::Heat::CloudConfig + properties: + cloud_config: + runcmd: + - ['setenforce', 'permissive'] + - ['sed', '-i', 's/Listen 80/Listen 8081/g', '/etc/httpd/conf/httpd.conf'] + - ['systemctl', 'enable', 'httpd.service'] + - ['systemctl', 'start', 'httpd.service'] + - ['systemctl', 'enable', 'dnsmasq.service'] + - ['systemctl', 'start', 'dnsmasq.service'] + + controller-init: + type: OS::Heat::MultipartMime + properties: + parts: + - config: {get_resource: controller_users} + - config: {get_resource: controller-write-files} + - config: {get_resource: controller-runcmd} + + controller-machine-port: + type: OS::Neutron::Port + properties: + network: {get_resource: machine-net} + mac_address: "fa:16:9e:81:f6:05" + fixed_ips: + - ip_address: 192.168.32.254 + + controller-floating-ip: + depends_on: machine-net-router-interface + type: OS::Neutron::FloatingIP + properties: + floating_network: {get_param: floating_ip_network} + port_id: {get_resource: controller-machine-port} + + controller: + type: OS::Nova::Server + properties: + image: {get_param: [controller_params, image]} + flavor: {get_param: [controller_params, flavor]} + networks: + - port: {get_resource: controller-machine-port} + user_data_format: RAW + user_data: {get_resource: controller-init} + + # + # SONiC Switch + # + switch-init: + type: OS::Heat::CloudConfig + properties: + cloud_config: + hostname: switch + fqdn: switch.stack.lab + users: + - default + - name: zuul + gecos: "Zuul user" + sudo: ALL=(ALL) NOPASSWD:ALL + ssh_authorized_keys: + - {get_param: controller_ssh_pub_key} + - {get_param: dataplane_ssh_pub_key} + write_files: + - path: /etc/hotstack-ceos/config + content: | + MGMT_INTERFACE=eth0 + SWITCH_INTERFACE_START=eth1 + SWITCH_INTERFACE_COUNT=4 + SWITCH_HOSTNAME=switch + CEOS_IMAGE=localhost/ceos:latest + ENABLE_SWITCH_PORT_PROMISC=true + owner: root:root + permissions: '0644' + - path: /etc/hotstack-ceos/startup-config + content: {get_file: switch-startup.cfg} + owner: root:root + permissions: '0644' + runcmd: + - systemctl start ceos.service + + switch-machine-port: + type: OS::Neutron::Port + properties: + network: {get_resource: machine-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:01:01" + fixed_ips: + - ip_address: 192.168.32.11 + + switch-switch-mgmt-port: + type: OS::Neutron::Port + properties: + network: {get_resource: machine-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:01:10" + fixed_ips: + - ip_address: 192.168.32.111 + + switch-trunk-parent-port: + type: OS::Neutron::Port + properties: + network: {get_resource: trunk-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:01:02" + + switch-trunk-tenant-vlan103-port: + type: OS::Neutron::Port + properties: + network: {get_resource: tenant-vlan103} + port_security_enabled: false + mac_address: "22:57:f8:dd:01:03" + + switch-trunk-tenant-vlan104-port: + type: OS::Neutron::Port + properties: + network: {get_resource: tenant-vlan104} + port_security_enabled: false + mac_address: "22:57:f8:dd:01:04" + + switch-trunk-tenant-vlan105-port: + type: OS::Neutron::Port + properties: + network: {get_resource: tenant-vlan105} + port_security_enabled: false + mac_address: "22:57:f8:dd:01:05" + + switch-trunk: + type: OS::Neutron::Trunk + properties: + port: {get_resource: switch-trunk-parent-port} + sub_ports: + - port: {get_resource: switch-trunk-tenant-vlan103-port} + segmentation_id: 103 + segmentation_type: vlan + - port: {get_resource: switch-trunk-tenant-vlan104-port} + segmentation_id: 104 + segmentation_type: vlan + - port: {get_resource: switch-trunk-tenant-vlan105-port} + segmentation_id: 105 + segmentation_type: vlan + + switch-ironic0-br-port: + type: OS::Neutron::Port + properties: + network: {get_resource: ironic0-br-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:01:06" + + switch-ironic1-br-port: + type: OS::Neutron::Port + properties: + network: {get_resource: ironic1-br-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:01:07" + + switch: + type: OS::Nova::Server + depends_on: switch-trunk + properties: + image: {get_param: [switch_params, image]} + flavor: {get_param: [switch_params, flavor]} + config_drive: false + networks: + - port: {get_resource: switch-machine-port} + - port: {get_resource: switch-switch-mgmt-port} + - port: {get_attr: [switch-trunk, port_id]} + - port: {get_resource: switch-ironic0-br-port} + - port: {get_resource: switch-ironic1-br-port} + user_data_format: RAW + user_data: {get_resource: switch-init} + + # + # Devstack Instance + # + devstack_users: + type: OS::Heat::CloudConfig + properties: + cloud_config: + users: + - default + - name: stack + gecos: "Stack user" + sudo: ALL=(ALL) NOPASSWD:ALL + homedir: /opt/stack + shell: /bin/bash + ssh_authorized_keys: + - {get_param: controller_ssh_pub_key} + - {get_param: dataplane_ssh_pub_key} + + devstack-network-config: + type: OS::Heat::CloudConfig + properties: + cloud_config: + hostname: devstack + fqdn: devstack.stack.lab + + devstack-write-files: + type: OS::Heat::CloudConfig + properties: + cloud_config: + write_files: + - path: /etc/hotstack/local.conf.j2 + content: + get_file: local.conf.j2 + owner: root:root + permissions: '0644' + + devstack-init: + type: OS::Heat::MultipartMime + properties: + parts: + - config: {get_resource: devstack_users} + - config: {get_resource: devstack-network-config} + - config: {get_resource: devstack-write-files} + + devstack-machine-port: + type: OS::Neutron::Port + properties: + network: {get_resource: machine-net} + port_security_enabled: false + mac_address: "fa:16:9e:81:f6:20" + fixed_ips: + - ip_address: 192.168.32.20 + + devstack-trunk-parent-port: + type: OS::Neutron::Port + properties: + network: {get_resource: trunk-net} + port_security_enabled: false + mac_address: "fa:16:9e:81:f6:21" + + devstack-tenant-vlan103-subport: + type: OS::Neutron::Port + properties: + network: {get_resource: tenant-vlan103} + port_security_enabled: false + + devstack-tenant-vlan104-subport: + type: OS::Neutron::Port + properties: + network: {get_resource: tenant-vlan104} + port_security_enabled: false + + devstack-tenant-vlan105-subport: + type: OS::Neutron::Port + properties: + network: {get_resource: tenant-vlan105} + port_security_enabled: false + + devstack-trunk: + type: OS::Neutron::Trunk + properties: + port: {get_resource: devstack-trunk-parent-port} + sub_ports: + - port: {get_resource: devstack-tenant-vlan103-subport} + segmentation_id: 103 + segmentation_type: vlan + - port: {get_resource: devstack-tenant-vlan104-subport} + segmentation_id: 104 + segmentation_type: vlan + - port: {get_resource: devstack-tenant-vlan105-subport} + segmentation_id: 105 + segmentation_type: vlan + + devstack: + type: OS::Nova::Server + depends_on: devstack-trunk + properties: + image: {get_param: [devstack_params, image]} + flavor: {get_param: [devstack_params, flavor]} + networks: + - port: {get_resource: devstack-machine-port} + - port: {get_attr: [devstack-trunk, port_id]} + user_data_format: RAW + user_data: {get_resource: devstack-init} + + # + # Ironic Nodes + # + ironic0-port: + type: OS::Neutron::Port + properties: + network: {get_resource: ironic0-br-net} + port_security_enabled: false + + ironic0: + type: OS::Nova::Server + properties: + flavor: {get_param: [ironic_params, flavor]} + image: {get_param: [ironic_params, image]} + networks: + - port: {get_resource: ironic0-port} + + ironic1-port: + type: OS::Neutron::Port + properties: + network: {get_resource: ironic1-br-net} + port_security_enabled: false + + ironic1: + type: OS::Nova::Server + properties: + flavor: {get_param: [ironic_params, flavor]} + image: {get_param: [ironic_params, image]} + networks: + - port: {get_resource: ironic1-port} + +outputs: + controller_floating_ip: + description: Controller Floating IP + value: {get_attr: [controller-floating-ip, floating_ip_address]} + + controller_ansible_host: + description: > + Controller ansible host, this struct can be passed to the ansible.builtin.add_host module + value: + name: controller-0 + ansible_ssh_user: zuul + ansible_host: {get_attr: [controller-floating-ip, floating_ip_address]} + ansible_port: 22 + ansible_ssh_common_args: '-o StrictHostKeyChecking=no' + groups: controllers + + devstack_ansible_host: + description: > + Devstack ansible host, this struct can be passed to the ansible.builtin.add_host module. + Uses ProxyJump through the controller for SSH access. + value: + name: devstack + ansible_user: stack + ansible_host: {get_attr: [devstack-machine-port, fixed_ips, 0, ip_address]} + ansible_port: 22 + ansible_ssh_common_args: + str_replace: + template: '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ProxyJump=zuul@$controller_ip' + params: + $controller_ip: {get_attr: [controller-floating-ip, floating_ip_address]} + ansible_ssh_private_key_file: '~/.ssh/id_rsa' + groups: devstack_nodes + + devstack_netplan_config: + description: > + Complete netplan configuration for devstack node to be written by Ansible + value: + network: + version: 2 + ethernets: + enp3s0: + match: + macaddress: "fa:16:9e:81:f6:20" + dhcp4: true + set-name: "enp3s0" + mtu: 1500 + enp4s0: + match: + macaddress: "fa:16:9e:81:f6:21" + dhcp4: false + dhcp6: false + set-name: trunk0 + mtu: 1500 + + sushy_emulator_uuids: + description: UUIDs of instances to manage with sushy-tools - RedFish virtual BMC + value: + ironic0: {get_resource: ironic0} + ironic1: {get_resource: ironic1} + + sushy_tools_vmedia_type: + description: Virtual media implementation type for sushy-tools (rescue or volumeRebuild) + value: rescue + + ironic_nodes: + description: Ironic nodes YAML, used with openstack baremetal create to enroll nodes in Openstack Ironic + value: + nodes: + - name: ironic0 + driver: redfish + bios_interface: no-bios + boot_interface: redfish-virtual-media + network_interface: neutron + driver_info: + redfish_address: http://controller-0.stack.lab:8000 + redfish_system_id: + str_replace: + template: "/redfish/v1/Systems/$SYS_ID" + params: + $SYS_ID: {get_resource: ironic0} + redfish_username: admin + redfish_password: password + properties: + cpu_arch: x86_64 + cpus: 1 + memory_mb: 1024 + local_gb: 15 + capabilities: boot_mode:uefi + ports: + - address: {get_attr: [ironic0-port, mac_address]} + physical_network: public + local_link_connection: + switch_info: switch.stack.lab + switch_id: "22:57:f8:dd:01:01" + port_id: "Ethernet2" + - name: ironic1 + driver: redfish + bios_interface: no-bios + boot_interface: redfish-virtual-media + network_interface: neutron + driver_info: + redfish_address: http://controller-0.stack.lab:8000 + redfish_system_id: + str_replace: + template: "/redfish/v1/Systems/$SYS_ID" + params: + $SYS_ID: {get_resource: ironic1} + redfish_username: admin + redfish_password: password + properties: + cpu_arch: x86_64 + cpus: 1 + memory_mb: 1024 + local_gb: 15 + capabilities: boot_mode:uefi + ports: + - address: {get_attr: [ironic1-port, mac_address]} + physical_network: public + local_link_connection: + switch_info: switch.stack.lab + switch_id: "22:57:f8:dd:01:01" + port_id: "Ethernet3" + + ansible_inventory: + description: Ansible inventory + value: + all: + children: + controllers: + vars: + switches: + vars: + devstack_nodes: + vars: + localhosts: + hosts: + localhost: + ansible_connection: local + controllers: + hosts: + controller0: + ansible_host: {get_attr: [controller-machine-port, fixed_ips, 0, ip_address]} + ansible_user: zuul + ansible_ssh_common_args: '-o StrictHostKeyChecking=no' + ansible_ssh_private_key_file: '~/.ssh/id_rsa' + switches: + hosts: + switch: + ansible_host: {get_attr: [switch-machine-port, fixed_ips, 0, ip_address]} + ansible_user: admin + ansible_ssh_common_args: '-o StrictHostKeyChecking=no' + ansible_ssh_private_key_file: '~/.ssh/id_rsa' + devstack_nodes: + hosts: + devstack: + ansible_host: {get_attr: [devstack-machine-port, fixed_ips, 0, ip_address]} + ansible_user: stack + ansible_ssh_common_args: '-o StrictHostKeyChecking=no' + ansible_ssh_private_key_file: '~/.ssh/id_rsa' diff --git a/scenarios/networking-lab/devstack-ceos-vlan-netconf/local.conf.j2 b/scenarios/networking-lab/devstack-ceos-vlan-netconf/local.conf.j2 new file mode 100644 index 00000000..742a3e32 --- /dev/null +++ b/scenarios/networking-lab/devstack-ceos-vlan-netconf/local.conf.j2 @@ -0,0 +1,142 @@ +[[local|localrc]] +# Credentials +ADMIN_PASSWORD=secret +DATABASE_PASSWORD=$ADMIN_PASSWORD +RABBIT_PASSWORD=$ADMIN_PASSWORD +SERVICE_PASSWORD=$ADMIN_PASSWORD + +# Service timeouts +SERVICE_TIMEOUT=120 + +# MTU - running inside an encapsulated environment, restrict to 1442 on the +# physical network so VXLAN tenant networks get 1442 - 50 = 1392 effective MTU. +PUBLIC_BRIDGE_MTU=1442 + +# Networking +HOST_IP=192.168.32.20 +SERVICE_HOST=$HOST_IP +MYSQL_HOST=$HOST_IP +RABBIT_HOST=$HOST_IP +GLANCE_HOSTPORT=$HOST_IP:9292 + +# Network ranges (avoiding Heat template allocations) +FIXED_RANGE=172.20.100.0/24 +IPV4_ADDRS_SAFE_TO_USE=172.20.100.0/24 +FLOATING_RANGE=172.20.200.0/24 +PUBLIC_NETWORK_GATEWAY=172.20.200.1 + +# Disable IPv6 - use IPv4 only +IP_VERSION=4 + +# Enable Neutron with OVN +disable_service n-net +enable_service q-svc +# Disable traditional neutron agents +disable_service q-agt +disable_service q-dhcp +disable_service q-l3 +disable_service q-meta +# Enable OVN services +enable_service ovn-northd +enable_service ovn-controller +enable_service q-ovn-metadata-agent +# Enable Neutron trunk service +enable_service neutron-trunk +# Enable Neutron segments service +enable_service neutron-segments + +enable_service ir-api +enable_service ir-cond +enable_service ir-neutronagt + +# Ironic configuration +VIRT_DRIVER=ironic +DEFAULT_INSTANCE_TYPE=baremetal +IRONIC_BAREMETAL_BASIC_OPS=True +IRONIC_IS_HARDWARE=True +IRONIC_VM_COUNT=0 +IRONIC_NETWORK_SIMULATOR=none +IRONIC_BUILD_DEPLOY_RAMDISK=False +IRONIC_DEPLOY_DRIVER=redfish +IRONIC_ENABLED_HARDWARE_TYPES=redfish +IRONIC_ENABLED_BOOT_INTERFACES=ipxe,redfish-virtual-media,http-ipxe +IRONIC_ENABLED_POWER_INTERFACES=redfish +IRONIC_ENABLED_MANAGEMENT_INTERFACES=redfish +IRONIC_ENABLED_DEPLOY_INTERFACES=direct,ramdisk +IRONIC_NETWORK_INTERFACE=neutron +IRONIC_ENABLED_NETWORK_INTERFACES=neutron +IRONIC_AUTOMATED_CLEAN_ENABLED=True +FORCE_CONFIG_DRIVE=True + +# Ironic network configuration - use provisioning vlan network for all operations +IRONIC_PROVISION_NETWORK_NAME=provisioning +IRONIC_PROVISION_PROVIDER_NETWORK_TYPE=vlan +IRONIC_PROVISION_SUBNET_PREFIX=10.0.5.0/24 +IRONIC_PROVISION_SUBNET_GATEWAY=10.0.5.1 +IRONIC_CLEAN_NET_NAME=provisioning +IRONIC_RESCUE_NET_NAME=provisioning +IRONIC_INSPECTION_NET_NAME=provisioning + +# Networking configuration for ML2 with OVN and Generic Switch +Q_PLUGIN=ml2 +Q_ML2_TENANT_NETWORK_TYPE=vlan +Q_ML2_PLUGIN_MECHANISM_DRIVERS=ovn,genericswitch,baremetal +Q_ML2_PLUGIN_TYPE_DRIVERS=vxlan,geneve,vlan,flat +ENABLE_TENANT_VLANS=True +TENANT_VLAN_RANGE=103:105 +PHYSICAL_NETWORK=public + +# Physical interface mapping +# The second interface (trunk port) will be added to br-ex +# trunk0 is matched by MAC address fa:16:9e:81:f6:21 and renamed by netplan +PUBLIC_INTERFACE=trunk0 +OVS_PHYSICAL_BRIDGE=br-ex +PUBLIC_BRIDGE=br-ex + +# OVN Configuration +Q_USE_PROVIDERNET_FOR_PUBLIC=True +OVN_L3_CREATE_PUBLIC_NETWORK=True +OVN_BRIDGE_MAPPINGS=public:br-ex + +# Enable Ironic +enable_plugin ironic https://opendev.org/openstack/ironic + +# Enable networking-generic-switch plugin +enable_plugin networking-generic-switch https://opendev.org/openstack/networking-generic-switch refs/changes/62/990062/2 + +# Enable networking-baremetal plugin +enable_plugin networking-baremetal https://opendev.org/openstack/networking-baremetal + +# Disable Swift (optional, not needed for this setup) +disable_service s-proxy s-object s-container s-account + +# Disable Horizon dashboard +disable_service horizon + +[[post-config|/etc/ironic/ironic.conf]] +[conductor] +power_state_change_timeout = 90 + +[[post-config|$NEUTRON_CONF]] +[DEFAULT] +global_physnet_mtu = 1500 + +[l2vni] +enable_l2vni_trunk_reconciliation = False +enable_l2vni_trunk_reconciliation_events = False + +[baremetal_agent] +enable_ha_chassis_group_alignment = False +enable_router_ha_binding_events = False + +[[post-config|/etc/neutron/plugins/ml2/ml2_conf_genericswitch.ini]] +[genericswitch:switch] +device_type = netconf_openconfig +host = switch.stack.lab +port = 830 +username = admin +password = admin +hostkey_verify = false +ngs_mac_address = 22:57:f8:dd:01:01 +ngs_physical_networks = public +ngs_trunk_ports = Ethernet1 diff --git a/scenarios/networking-lab/devstack-ceos-vlan-netconf/switch-startup.cfg b/scenarios/networking-lab/devstack-ceos-vlan-netconf/switch-startup.cfg new file mode 100644 index 00000000..07ef4743 --- /dev/null +++ b/scenarios/networking-lab/devstack-ceos-vlan-netconf/switch-startup.cfg @@ -0,0 +1,61 @@ +hostname switch.stack.lab +username admin privilege 15 secret admin +vrf instance MGMT +ip routing vrf MGMT +ip name-server vrf MGMT 192.168.32.254 +ip route vrf MGMT 0.0.0.0/0 192.168.32.1 + +interface Management0 + description Management interface + vrf MGMT + ip address 192.168.32.111/24 + +interface Ethernet1 + description Trunk port to devstack - managed by ML2 + switchport mode trunk + switchport trunk allowed vlan none + mtu 1500 + spanning-tree portfast + +interface Ethernet2 + description Ironic node 0 - managed by ML2 + switchport mode access + mtu 1500 + spanning-tree portfast + +interface Ethernet3 + description Ironic node 1 - managed by ML2 + switchport mode access + mtu 1500 + spanning-tree portfast + +vlan 100 + name provisioning + +vlan 103 + name tenant-vlan-103 + +vlan 104 + name tenant-vlan-104 + +vlan 105 + name tenant-vlan-105 + +management api http-commands + no shutdown + vrf MGMT + no shutdown + +management api gnmi + transport grpc default + vrf MGMT + +management api netconf + transport ssh default + vrf MGMT + +management ssh + vrf MGMT + no shutdown + +end diff --git a/scenarios/networking-lab/devstack-ceos-vlan-netconf/topology-diagram.svg b/scenarios/networking-lab/devstack-ceos-vlan-netconf/topology-diagram.svg new file mode 100644 index 00000000..c0885c2a --- /dev/null +++ b/scenarios/networking-lab/devstack-ceos-vlan-netconf/topology-diagram.svg @@ -0,0 +1,89 @@ + + + + + + + + + VLAN Trunking Topology + + + + + Management Network (192.168.32.0/24) + + + + controller + 192.168.32.254 + + + + switch + VLANs 100-105 + 192.168.32.11 + + + + + devstack + 192.168.32.20 + + + + ironic0 + BM Node + + + + ironic1 + BM Node + + + + + Ethernet8 (trunk) + + + + Ethernet12 + + + + Ethernet16 + + + + Legend + + Switch + + Server + + Controller + + Link + + Management + + + + + Ethernet8: Trunk port with VLANs 100-105 | Ethernet12, Ethernet16: Access ports for Ironic nodes + + + networking-generic-switch manages VLAN membership dynamically + +