diff --git a/scenarios/networking-lab/devstack-sonic-vxlan/README.md b/scenarios/networking-lab/devstack-sonic-vxlan/README.md new file mode 100644 index 00000000..887bda17 --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/README.md @@ -0,0 +1,46 @@ +# Devstack with SONiC VXLAN Spine-and-Leaf + +Spine-and-leaf topology with 4 SONiC switches, 1 Devstack node, 2 Ironic nodes, and 1 controller. + +## Topology + +![Topology Diagram](topology-diagram.svg) + +## Networks + +### Management (`192.168.32.0/24`) +- Controller: `192.168.32.254` +- Spine01 (host): `192.168.32.11`, (switch): `192.168.32.111` +- Spine02 (host): `192.168.32.12`, (switch): `192.168.32.112` +- Leaf01 (host): `192.168.32.13`, (switch): `192.168.32.113` +- Leaf02 (host): `192.168.32.14`, (switch): `192.168.32.114` +- Devstack: `192.168.32.20` + +### Inter-Switch Links (`10.1.1.0/24`) +- Spine01 ↔ Spine02: `10.1.1.0/30` +- Leaf01 ↔ Spine01: `10.1.1.4/30` +- Leaf01 ↔ Spine02: `10.1.1.8/30` +- Leaf02 ↔ Spine01: `10.1.1.12/30` +- Leaf02 ↔ Spine02: `10.1.1.16/30` + +### Loopback/VTEP Addresses +- Spine01: `10.255.255.1/32` +- Spine02: `10.255.255.2/32` +- Leaf01: `10.255.255.3/32` (VTEP) +- Leaf02: `10.255.255.4/32` (VTEP) + +### BGP EVPN +- AS 65001 iBGP +- Spines: Route reflectors +- Leafs: Route reflector clients, vtep VTEP (source Loopback0) +- ML2 dynamically manages VLANs/VNIs + +## Deployment + +```bash +ansible-playbook -e @scenarios/networking-lab/devstack-sonic-vxlan/bootstrap_vars.yml -e os_cloud= bootstrap_devstack.yml +``` + +## Troubleshooting + +See [TROUBLESHOOTING.md](TROUBLESHOOTING.md). diff --git a/scenarios/networking-lab/devstack-sonic-vxlan/TROUBLESHOOTING.md b/scenarios/networking-lab/devstack-sonic-vxlan/TROUBLESHOOTING.md new file mode 100644 index 00000000..41cfadc3 --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/TROUBLESHOOTING.md @@ -0,0 +1,47 @@ +# Troubleshooting + +## Switches Not Booting +- Check OpenStack console logs for the switch instances +- Verify the `hotstack-sonic` image is properly configured +- Check cloud-init logs: `sudo journalctl -u cloud-init` +- Verify the SONiC container is running: `sudo systemctl status sonic.service` + +## Switches Not Reachable +- Verify management interface configuration on switches: `show interface Management0` or `ip addr show eth0` +- Check DNS resolution from controller: `dig spine01.stack.lab @192.168.32.254` +- Ensure routes are configured in management VRF: `show ip route vrf mgmt` +- Check that eth0 has the correct IP: `ip addr show eth0` + +## OSPF Not Working +- Access FRR shell: `podman exec sonic vtysh` +- Verify OSPF is running: `show ip ospf` +- Check OSPF neighbors: `show ip ospf neighbor` +- Verify interface MTU matches (1442): `show interface Ethernet0` +- Check OSPF interface configuration: `show ip ospf interface` + +## BGP EVPN Not Working +- Access FRR shell: `podman exec sonic vtysh` +- Verify BGP is running: `show bgp summary` +- Check BGP EVPN neighbors: `show bgp l2vpn evpn summary` +- Verify loopback reachability: `ping 10.255.255.1 -I 10.255.255.3` +- Check BGP configuration: `show running-config` + +## Devstack Deployment Issues +- Check network connectivity on trunk0: `ip link show trunk0` +- Verify trunk0 is added to br-ex: `sudo ovs-vsctl show` +- Review devstack logs: `/opt/stack/logs/stack.sh.log` +- Check neutron-server logs: `sudo journalctl -u devstack@q-svc` + +## ML2 Not Configuring Switches +- Verify networking-generic-switch credentials in `/etc/neutron/plugins/ml2/ml2_conf_genericswitch.ini` +- Check neutron-server can reach switches: `ping 192.168.32.13` from devstack +- Review neutron-server logs for genericswitch errors: `sudo journalctl -u devstack@q-svc | grep genericswitch` +- Test SSH connectivity manually: `ssh admin@192.168.32.13` from devstack +- Test SSH connectivity manually: `ssh admin@192.168.32.13` from devstack + +## Container-Specific Issues +- Check SONiC container status: `sudo podman ps` +- View container logs: `sudo podman logs sonic` +- Restart SONiC service: `sudo systemctl restart sonic.service` +- Verify SONiC image is loaded: `sudo podman images | grep sonic` +- Access SONiC CLI: `sudo podman exec -it sonic bash` diff --git a/scenarios/networking-lab/devstack-sonic-vxlan/automation-vars.yml b/scenarios/networking-lab/devstack-sonic-vxlan/automation-vars.yml new file mode 100644 index 00000000..042a098e --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/automation-vars.yml @@ -0,0 +1,117 @@ +--- +# Networking lab automation stages + +stages: + - name: Configure provisioning network route + documentation: >- + Configures a static route on the devstack node to enable communication + between the ironic-conductor and the provisioning network (where + ironic-python-agent runs during node deployment/cleaning). This retrieves + the router gateway IP from Neutron and adds a route via that gateway. + The provisioning network subnet is configured in local.conf.j2 via + IRONIC_PROVISION_SUBNET_PREFIX (default: 10.0.5.0/24). + shell: | + set -xe -o pipefail + + IRONIC_PROVISION_SUBNET_PREFIX="10.0.5.0/24" + + EXTERNAL_GW_INFO=$(openstack --os-cloud devstack-admin router show router1 -c external_gateway_info -f json) + + ROUTER_GW_IP=$(echo "$EXTERNAL_GW_INFO" | python3 -c ' + import sys, json, ipaddress + data = json.load(sys.stdin) + for ip_info in data["external_gateway_info"]["external_fixed_ips"]: + addr = ipaddress.ip_address(ip_info["ip_address"]) + if addr.version == 4: + print(ip_info["ip_address"]) + break + ') + + if [ -z "$ROUTER_GW_IP" ]; then + echo "ERROR: Could not determine router gateway IP" + exit 1 + fi + + ssh -o StrictHostKeyChecking=no stack@devstack.stack.lab " + ROUTES=\$(ip -j r) + ROUTE_EXISTS=\$(echo \"\$ROUTES\" | python3 -c ' + import sys, json + routes = json.load(sys.stdin) + target_dst = \"$IRONIC_PROVISION_SUBNET_PREFIX\" + target_gw = \"$ROUTER_GW_IP\" + for route in routes: + if route.get(\"dst\") == target_dst and route.get(\"gateway\") == target_gw: + print(\"exists\") + break + ') + if [ -z \"\$ROUTE_EXISTS\" ]; then + echo \"Adding route: $IRONIC_PROVISION_SUBNET_PREFIX via $ROUTER_GW_IP\" + sudo ip route add $IRONIC_PROVISION_SUBNET_PREFIX via $ROUTER_GW_IP + else + echo \"Route already exists: $IRONIC_PROVISION_SUBNET_PREFIX via $ROUTER_GW_IP\" + fi + " + + - 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-sonic-vxlan/bootstrap_vars.yml b/scenarios/networking-lab/devstack-sonic-vxlan/bootstrap_vars.yml new file mode 100644 index 00000000..79b7f279 --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/bootstrap_vars.yml @@ -0,0 +1,50 @@ +--- +# Bootstrap configuration for networking lab scenario with SONiC + +# OpenStack cloud configuration +os_cloud: default +os_floating_network: public +os_router_external_network: public + +# Scenario configuration +scenario: devstack-sonic-vxlan +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 + +# Pull secret for container images (if needed) +# pull_secret_file: ~/pull-secret.txt + +# 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.xxlarge + switch_params: + image: hotstack-sonic + flavor: hotstack.small + ironic_params: + image: CentOS-Stream-GenericCloud-9 + cd_image: sushy-tools-blank-image + flavor: hotstack.medium + +# Controller role configuration +controller_install_openstack_client: true diff --git a/scenarios/networking-lab/devstack-sonic-vxlan/heat_template.yaml b/scenarios/networking-lab/devstack-sonic-vxlan/heat_template.yaml new file mode 100644 index 00000000..087f50bd --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/heat_template.yaml @@ -0,0 +1,1202 @@ +--- +heat_template_version: rocky + +description: > + Heat template for networking lab with spine-and-leaf SONiC setup. + Includes 4 switches (spine01, spine02, leaf01, leaf02), 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 + cd_image: sushy-tools-blank-image + flavor: hotstack.medium + switch_params: + type: json + default: + image: hotstack-sonic + flavor: hotstack.small + 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} + + # Spine switch interconnect + spine-link-net: + type: OS::Neutron::Net + properties: + port_security_enabled: false + value_specs: {get_param: net_value_specs} + + # Leaf to spine links + leaf01-spine01-net: + type: OS::Neutron::Net + properties: + port_security_enabled: false + value_specs: {get_param: net_value_specs} + + leaf01-spine02-net: + type: OS::Neutron::Net + properties: + port_security_enabled: false + value_specs: {get_param: net_value_specs} + + leaf02-spine01-net: + type: OS::Neutron::Net + properties: + port_security_enabled: false + value_specs: {get_param: net_value_specs} + + leaf02-spine02-net: + type: OS::Neutron::Net + properties: + port_security_enabled: false + value_specs: {get_param: net_value_specs} + + # Simple bridge networks for server attachments + # These are just L2 connectivity - VLANs and configuration managed by ML2 + 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 network for leaf01 switch + leaf01-trunk-net: + type: OS::Neutron::Net + properties: + port_security_enabled: false + value_specs: {get_param: net_value_specs} + + # Shared VLAN networks for physical network connectivity + public-vlan100: + 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 + + spine-link-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: spine-link-net} + ip_version: 4 + cidr: 10.1.1.0/30 + enable_dhcp: false + gateway_ip: null + + leaf01-spine01-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: leaf01-spine01-net} + ip_version: 4 + cidr: 10.1.1.4/30 + enable_dhcp: false + gateway_ip: null + + leaf01-spine02-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: leaf01-spine02-net} + ip_version: 4 + cidr: 10.1.1.8/30 + enable_dhcp: false + gateway_ip: null + + leaf02-spine01-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: leaf02-spine01-net} + ip_version: 4 + cidr: 10.1.1.12/30 + enable_dhcp: false + gateway_ip: null + + leaf02-spine02-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: leaf02-spine02-net} + ip_version: 4 + cidr: 10.1.1.16/30 + enable_dhcp: false + gateway_ip: null + + 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 + + # Leaf01 trunk subnet + leaf01-trunk-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: leaf01-trunk-net} + ip_version: 4 + cidr: 172.20.20.0/24 + enable_dhcp: false + gateway_ip: null + + # Shared VLAN subnets + public-vlan100-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: public-vlan100} + ip_version: 4 + cidr: 172.20.0.0/24 + gateway_ip: 172.20.0.1 + enable_dhcp: false + + tenant-vlan103-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: tenant-vlan103} + ip_version: 4 + cidr: 172.20.3.0/24 + gateway_ip: null + enable_dhcp: false + + tenant-vlan104-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: tenant-vlan104} + ip_version: 4 + cidr: 172.20.4.0/24 + gateway_ip: null + enable_dhcp: false + + tenant-vlan105-subnet: + type: OS::Neutron::Subnet + properties: + network: {get_resource: tenant-vlan105} + ip_version: 4 + cidr: 172.20.5.0/24 + gateway_ip: null + enable_dhcp: false + + # + # 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=spine01-host.stack.lab,$spine01_host + host-record=spine01.stack.lab,$spine01 + host-record=spine02-host.stack.lab,$spine02_host + host-record=spine02.stack.lab,$spine02 + host-record=leaf01-host.stack.lab,$leaf01_host + host-record=leaf01.stack.lab,$leaf01 + host-record=leaf02-host.stack.lab,$leaf02_host + host-record=leaf02.stack.lab,$leaf02 + host-record=devstack.stack.lab,$devstack + params: + $controller0: {get_attr: [controller-machine-port, fixed_ips, 0, ip_address]} + $spine01_host: {get_attr: [spine01-machine-port, fixed_ips, 0, ip_address]} + $spine01: {get_attr: [spine01-switch-mgmt-port, fixed_ips, 0, ip_address]} + $spine02_host: {get_attr: [spine02-machine-port, fixed_ips, 0, ip_address]} + $spine02: {get_attr: [spine02-switch-mgmt-port, fixed_ips, 0, ip_address]} + $leaf01_host: {get_attr: [leaf01-machine-port, fixed_ips, 0, ip_address]} + $leaf01: {get_attr: [leaf01-switch-mgmt-port, fixed_ips, 0, ip_address]} + $leaf02_host: {get_attr: [leaf02-machine-port, fixed_ips, 0, ip_address]} + $leaf02: {get_attr: [leaf02-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'] + - ['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} + + # + # Spine Switches + # + + # Spine01 Switch + spine01-init: + type: OS::Heat::CloudConfig + properties: + cloud_config: + hostname: spine01 + fqdn: spine01.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-sonic/config + content: | + MGMT_INTERFACE=eth0 + SWITCH_INTERFACE_START=eth1 + SWITCH_INTERFACE_COUNT=4 + SWITCH_HOSTNAME=spine01 + SONIC_IMAGE=localhost/sonic:latest + owner: root:root + permissions: '0644' + - path: /etc/hotstack-sonic/config_db.json + content: {get_file: spine01-config_db.json} + owner: root:root + permissions: '0644' + - path: /etc/hotstack-sonic/frr.conf + content: {get_file: spine01-frr.conf} + owner: root:root + permissions: '0644' + runcmd: + - systemctl start sonic.service + + spine01-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 + + spine01-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 + + spine01-spine-link-port: + type: OS::Neutron::Port + properties: + network: {get_resource: spine-link-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:01:02" + + spine01-leaf01-port: + type: OS::Neutron::Port + properties: + network: {get_resource: leaf01-spine01-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:01:04" + + spine01-leaf02-port: + type: OS::Neutron::Port + properties: + network: {get_resource: leaf02-spine01-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:01:05" + + spine01: + type: OS::Nova::Server + properties: + image: {get_param: [switch_params, image]} + flavor: {get_param: [switch_params, flavor]} + config_drive: false + diskConfig: MANUAL + networks: + - port: {get_resource: spine01-machine-port} + - port: {get_resource: spine01-switch-mgmt-port} + - port: {get_resource: spine01-spine-link-port} + - port: {get_resource: spine01-leaf01-port} + - port: {get_resource: spine01-leaf02-port} + user_data_format: RAW + user_data: {get_resource: spine01-init} + + # Spine02 Switch + spine02-init: + type: OS::Heat::CloudConfig + properties: + cloud_config: + hostname: spine02 + fqdn: spine02.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-sonic/config + content: | + MGMT_INTERFACE=eth0 + SWITCH_INTERFACE_START=eth1 + SWITCH_INTERFACE_COUNT=4 + SWITCH_HOSTNAME=spine02 + SONIC_IMAGE=localhost/sonic:latest + owner: root:root + permissions: '0644' + - path: /etc/hotstack-sonic/config_db.json + content: {get_file: spine02-config_db.json} + owner: root:root + permissions: '0644' + - path: /etc/hotstack-sonic/frr.conf + content: {get_file: spine02-frr.conf} + owner: root:root + permissions: '0644' + runcmd: + - systemctl start sonic.service + + spine02-machine-port: + type: OS::Neutron::Port + properties: + network: {get_resource: machine-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:02:01" + fixed_ips: + - ip_address: 192.168.32.12 + + spine02-switch-mgmt-port: + type: OS::Neutron::Port + properties: + network: {get_resource: machine-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:02:10" + fixed_ips: + - ip_address: 192.168.32.112 + + spine02-spine-link-port: + type: OS::Neutron::Port + properties: + network: {get_resource: spine-link-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:02:02" + + spine02-leaf01-port: + type: OS::Neutron::Port + properties: + network: {get_resource: leaf01-spine02-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:02:04" + + spine02-leaf02-port: + type: OS::Neutron::Port + properties: + network: {get_resource: leaf02-spine02-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:02:05" + + spine02: + type: OS::Nova::Server + properties: + image: {get_param: [switch_params, image]} + flavor: {get_param: [switch_params, flavor]} + config_drive: false + diskConfig: MANUAL + networks: + - port: {get_resource: spine02-machine-port} + - port: {get_resource: spine02-switch-mgmt-port} + - port: {get_resource: spine02-spine-link-port} + - port: {get_resource: spine02-leaf01-port} + - port: {get_resource: spine02-leaf02-port} + user_data_format: RAW + user_data: {get_resource: spine02-init} + + # + # Leaf Switches + # + + # Leaf01 Switch + leaf01-init: + type: OS::Heat::CloudConfig + properties: + cloud_config: + hostname: leaf01 + fqdn: leaf01.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-sonic/config + content: | + MGMT_INTERFACE=eth0 + SWITCH_INTERFACE_START=eth1 + SWITCH_INTERFACE_COUNT=5 + SWITCH_HOSTNAME=leaf01 + SONIC_IMAGE=localhost/sonic:latest + owner: root:root + permissions: '0644' + - path: /etc/hotstack-sonic/config_db.json + content: {get_file: leaf01-config_db.json} + owner: root:root + permissions: '0644' + - path: /etc/hotstack-sonic/frr.conf + content: {get_file: leaf01-frr.conf} + owner: root:root + permissions: '0644' + runcmd: + - systemctl start sonic.service + + leaf01-machine-port: + type: OS::Neutron::Port + properties: + network: {get_resource: machine-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:03:01" + fixed_ips: + - ip_address: 192.168.32.13 + + leaf01-switch-mgmt-port: + type: OS::Neutron::Port + properties: + network: {get_resource: machine-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:03:10" + fixed_ips: + - ip_address: 192.168.32.113 + + leaf01-spine01-port: + type: OS::Neutron::Port + properties: + network: {get_resource: leaf01-spine01-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:03:02" + + leaf01-spine02-port: + type: OS::Neutron::Port + properties: + network: {get_resource: leaf01-spine02-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:03:04" + + leaf01-devstack-br-port: + type: OS::Neutron::Port + properties: + network: {get_resource: devstack-br-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:03:06" + + leaf01-trunk-parent-port: + type: OS::Neutron::Port + properties: + network: {get_resource: leaf01-trunk-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:03:05" + + leaf01-trunk-public-vlan100-port: + type: OS::Neutron::Port + properties: + network: {get_resource: public-vlan100} + port_security_enabled: false + mac_address: "22:57:f8:dd:03:07" + + leaf01-trunk-tenant-vlan103-port: + type: OS::Neutron::Port + properties: + network: {get_resource: tenant-vlan103} + port_security_enabled: false + mac_address: "22:57:f8:dd:03:08" + + leaf01-trunk-tenant-vlan104-port: + type: OS::Neutron::Port + properties: + network: {get_resource: tenant-vlan104} + port_security_enabled: false + mac_address: "22:57:f8:dd:03:09" + + leaf01-trunk-tenant-vlan105-port: + type: OS::Neutron::Port + properties: + network: {get_resource: tenant-vlan105} + port_security_enabled: false + mac_address: "22:57:f8:dd:03:0a" + + leaf01-trunk: + type: OS::Neutron::Trunk + properties: + port: {get_resource: leaf01-trunk-parent-port} + sub_ports: + - port: {get_resource: leaf01-trunk-public-vlan100-port} + segmentation_id: 100 + segmentation_type: vlan + - port: {get_resource: leaf01-trunk-tenant-vlan103-port} + segmentation_id: 103 + segmentation_type: vlan + - port: {get_resource: leaf01-trunk-tenant-vlan104-port} + segmentation_id: 104 + segmentation_type: vlan + - port: {get_resource: leaf01-trunk-tenant-vlan105-port} + segmentation_id: 105 + segmentation_type: vlan + + leaf02-ironic0-br-port: + type: OS::Neutron::Port + properties: + network: {get_resource: ironic0-br-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:04:05" + + leaf01: + type: OS::Nova::Server + depends_on: leaf01-trunk + properties: + image: {get_param: [switch_params, image]} + flavor: {get_param: [switch_params, flavor]} + config_drive: false + diskConfig: MANUAL + networks: + - port: {get_resource: leaf01-machine-port} + - port: {get_resource: leaf01-switch-mgmt-port} + - port: {get_resource: leaf01-spine01-port} + - port: {get_resource: leaf01-spine02-port} + - port: {get_attr: [leaf01-trunk, port_id]} + - port: {get_resource: leaf01-devstack-br-port} + user_data_format: RAW + user_data: {get_resource: leaf01-init} + + # Leaf02 Switch + leaf02-init: + type: OS::Heat::CloudConfig + properties: + cloud_config: + hostname: leaf02 + fqdn: leaf02.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-sonic/config + content: | + MGMT_INTERFACE=eth0 + SWITCH_INTERFACE_START=eth1 + SWITCH_INTERFACE_COUNT=5 + SWITCH_HOSTNAME=leaf02 + SONIC_IMAGE=localhost/sonic:latest + owner: root:root + permissions: '0644' + - path: /etc/hotstack-sonic/config_db.json + content: {get_file: leaf02-config_db.json} + owner: root:root + permissions: '0644' + - path: /etc/hotstack-sonic/frr.conf + content: {get_file: leaf02-frr.conf} + owner: root:root + permissions: '0644' + runcmd: + - systemctl start sonic.service + + leaf02-machine-port: + type: OS::Neutron::Port + properties: + network: {get_resource: machine-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:04:01" + fixed_ips: + - ip_address: 192.168.32.14 + + leaf02-switch-mgmt-port: + type: OS::Neutron::Port + properties: + network: {get_resource: machine-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:04:10" + fixed_ips: + - ip_address: 192.168.32.114 + + leaf02-spine01-port: + type: OS::Neutron::Port + properties: + network: {get_resource: leaf02-spine01-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:04:02" + + leaf02-spine02-port: + type: OS::Neutron::Port + properties: + network: {get_resource: leaf02-spine02-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:04:04" + + leaf02-ironic1-br-port: + type: OS::Neutron::Port + properties: + network: {get_resource: ironic1-br-net} + port_security_enabled: false + mac_address: "22:57:f8:dd:04:06" + + leaf02: + type: OS::Nova::Server + properties: + image: {get_param: [switch_params, image]} + flavor: {get_param: [switch_params, flavor]} + config_drive: false + diskConfig: MANUAL + networks: + - port: {get_resource: leaf02-machine-port} + - port: {get_resource: leaf02-switch-mgmt-port} + - port: {get_resource: leaf02-spine01-port} + - port: {get_resource: leaf02-spine02-port} + - port: {get_resource: leaf02-ironic0-br-port} + - port: {get_resource: leaf02-ironic1-br-port} + user_data_format: RAW + user_data: {get_resource: leaf02-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' + - path: /etc/neutron/l2vni_network_nodes.yaml + content: + get_file: l2vni_network_nodes.yaml + 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: devstack-br-net} + port_security_enabled: false + mac_address: "fa:16:9e:81:f6:21" + + devstack-public-vlan100-port: + type: OS::Neutron::Port + properties: + network: {get_resource: public-vlan100} + port_security_enabled: false + + devstack-tenant-vlan103-port: + type: OS::Neutron::Port + properties: + network: {get_resource: tenant-vlan103} + port_security_enabled: false + + devstack-tenant-vlan104-port: + type: OS::Neutron::Port + properties: + network: {get_resource: tenant-vlan104} + port_security_enabled: false + + devstack-tenant-vlan105-port: + 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-public-vlan100-port} + segmentation_id: 100 + segmentation_type: vlan + - port: {get_resource: devstack-tenant-vlan103-port} + segmentation_id: 103 + segmentation_type: vlan + - port: {get_resource: devstack-tenant-vlan104-port} + segmentation_id: 104 + segmentation_type: vlan + - port: {get_resource: devstack-tenant-vlan105-port} + 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]} + block_device_mapping_v2: + - device_type: disk + boot_index: 1 + image_id: {get_param: [ironic_params, image]} + volume_size: 40 + delete_on_termination: true + - device_type: cdrom + disk_bus: {get_param: cdrom_disk_bus} + boot_index: 0 + image_id: {get_param: [ironic_params, cd_image]} + volume_size: 5 + delete_on_termination: true + 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]} + block_device_mapping_v2: + - device_type: disk + boot_index: 1 + image_id: {get_param: [ironic_params, image]} + volume_size: 40 + delete_on_termination: true + - device_type: cdrom + disk_bus: {get_param: cdrom_disk_bus} + boot_index: 0 + image_id: {get_param: [ironic_params, cd_image]} + volume_size: 5 + delete_on_termination: true + 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: 1442 + trunk0: + match: + macaddress: "fa:16:9e:81:f6:21" + dhcp4: false + dhcp6: false + set-name: trunk0 + mtu: 1442 + + 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: leaf02 + port_id: "Ethernet8" + - 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: leaf02 + port_id: "Ethernet12" + + 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: + spine01: + ansible_host: {get_attr: [spine01-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' + spine02: + ansible_host: {get_attr: [spine02-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' + leaf01: + ansible_host: {get_attr: [leaf01-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' + leaf02: + ansible_host: {get_attr: [leaf02-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-sonic-vxlan/l2vni_network_nodes.yaml b/scenarios/networking-lab/devstack-sonic-vxlan/l2vni_network_nodes.yaml new file mode 100644 index 00000000..dab8c214 --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/l2vni_network_nodes.yaml @@ -0,0 +1,17 @@ +--- +# L2VNI Network Nodes Configuration +# This file provides fallback local_link_connection information for network nodes +# when LLDP data is not available from OVN and Ironic. +# +# The system_id must match the OVN chassis system-id (from external-ids:system-id in OVS). +# For this devstack deployment, the system-id is the hostname: devstack + +network_nodes: + - hostname: "devstack" + trunks: + - physical_network: public + local_link_information: + - switch_info: "leaf01" + port_id: "Ethernet8" + - switch_info: "leaf01" + port_id: "Ethernet12" diff --git a/scenarios/networking-lab/devstack-sonic-vxlan/leaf01-config_db.json b/scenarios/networking-lab/devstack-sonic-vxlan/leaf01-config_db.json new file mode 100644 index 00000000..51c02668 --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/leaf01-config_db.json @@ -0,0 +1,76 @@ +{ + "DEVICE_METADATA": { + "localhost": { + "hostname": "leaf01", + "type": "ToRRouter", + "bgp_asn": "65001", + "docker_routing_config_mode": "unified" + } + }, + "MGMT_INTERFACE": { + "eth0|192.168.32.113/24": { + "gwaddr": "192.168.32.1" + } + }, + "MGMT_PORT": { + "eth0": { + "alias": "eth0", + "admin_status": "up" + } + }, + "MGMT_VRF_CONFIG": { + "vrf_global": { + "mgmtVrfEnabled": "true" + } + }, + "LOOPBACK_INTERFACE": { + "Loopback0|10.255.255.3/32": {} + }, + "INTERFACE": { + "Ethernet0": { + "mtu": "1442" + }, + "Ethernet0|10.1.1.6/30": {}, + "Ethernet4": { + "mtu": "1442" + }, + "Ethernet4|10.1.1.10/30": {} + }, + "PORT": { + "Ethernet0": { + "alias": "Ethernet0", + "lanes": "0", + "speed": "10000", + "admin_status": "up" + }, + "Ethernet4": { + "alias": "Ethernet4", + "lanes": "4", + "speed": "10000", + "admin_status": "up" + }, + "Ethernet8": { + "alias": "Ethernet8", + "lanes": "8", + "speed": "10000", + "admin_status": "up", + "mtu": "1442" + }, + "Ethernet12": { + "alias": "Ethernet12", + "lanes": "12", + "speed": "10000", + "admin_status": "up", + "mtu": "1442" + } + }, + "VLAN": {}, + "VLAN_INTERFACE": {}, + "VLAN_MEMBER": {}, + "VXLAN_TUNNEL": { + "vtep": { + "src_ip": "10.255.255.3" + } + }, + "VXLAN_TUNNEL_MAP": {} +} diff --git a/scenarios/networking-lab/devstack-sonic-vxlan/leaf01-frr.conf b/scenarios/networking-lab/devstack-sonic-vxlan/leaf01-frr.conf new file mode 100644 index 00000000..557d2924 --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/leaf01-frr.conf @@ -0,0 +1,28 @@ +! +hostname leaf01 +! +router ospf + ospf router-id 10.255.255.3 + network 10.1.1.4/30 area 0.0.0.0 + network 10.1.1.8/30 area 0.0.0.0 + network 10.255.255.3/32 area 0.0.0.0 +! +router bgp 65001 + bgp router-id 10.255.255.3 + bgp log-neighbor-changes + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + neighbor 10.255.255.1 remote-as 65001 + neighbor 10.255.255.1 description spine01 + neighbor 10.255.255.1 update-source Loopback0 + neighbor 10.255.255.2 remote-as 65001 + neighbor 10.255.255.2 description spine02 + neighbor 10.255.255.2 update-source Loopback0 + ! + address-family l2vpn evpn + neighbor 10.255.255.1 activate + neighbor 10.255.255.2 activate + advertise-all-vni + exit-address-family +! +end diff --git a/scenarios/networking-lab/devstack-sonic-vxlan/leaf02-config_db.json b/scenarios/networking-lab/devstack-sonic-vxlan/leaf02-config_db.json new file mode 100644 index 00000000..ced91717 --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/leaf02-config_db.json @@ -0,0 +1,76 @@ +{ + "DEVICE_METADATA": { + "localhost": { + "hostname": "leaf02", + "type": "ToRRouter", + "bgp_asn": "65001", + "docker_routing_config_mode": "unified" + } + }, + "MGMT_INTERFACE": { + "eth0|192.168.32.114/24": { + "gwaddr": "192.168.32.1" + } + }, + "MGMT_PORT": { + "eth0": { + "alias": "eth0", + "admin_status": "up" + } + }, + "MGMT_VRF_CONFIG": { + "vrf_global": { + "mgmtVrfEnabled": "true" + } + }, + "LOOPBACK_INTERFACE": { + "Loopback0|10.255.255.4/32": {} + }, + "INTERFACE": { + "Ethernet0": { + "mtu": "1442" + }, + "Ethernet0|10.1.1.14/30": {}, + "Ethernet4": { + "mtu": "1442" + }, + "Ethernet4|10.1.1.18/30": {} + }, + "PORT": { + "Ethernet0": { + "alias": "Ethernet0", + "lanes": "0", + "speed": "10000", + "admin_status": "up" + }, + "Ethernet4": { + "alias": "Ethernet4", + "lanes": "4", + "speed": "10000", + "admin_status": "up" + }, + "Ethernet8": { + "alias": "Ethernet8", + "lanes": "8", + "speed": "10000", + "admin_status": "down", + "mtu": "1442" + }, + "Ethernet12": { + "alias": "Ethernet12", + "lanes": "12", + "speed": "10000", + "admin_status": "down", + "mtu": "1442" + } + }, + "VLAN": {}, + "VLAN_INTERFACE": {}, + "VLAN_MEMBER": {}, + "VXLAN_TUNNEL": { + "vtep": { + "src_ip": "10.255.255.4" + } + }, + "VXLAN_TUNNEL_MAP": {} +} diff --git a/scenarios/networking-lab/devstack-sonic-vxlan/leaf02-frr.conf b/scenarios/networking-lab/devstack-sonic-vxlan/leaf02-frr.conf new file mode 100644 index 00000000..70857a6f --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/leaf02-frr.conf @@ -0,0 +1,28 @@ +! +hostname leaf02 +! +router ospf + ospf router-id 10.255.255.4 + network 10.1.1.12/30 area 0.0.0.0 + network 10.1.1.16/30 area 0.0.0.0 + network 10.255.255.4/32 area 0.0.0.0 +! +router bgp 65001 + bgp router-id 10.255.255.4 + bgp log-neighbor-changes + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + neighbor 10.255.255.1 remote-as 65001 + neighbor 10.255.255.1 description spine01 + neighbor 10.255.255.1 update-source Loopback0 + neighbor 10.255.255.2 remote-as 65001 + neighbor 10.255.255.2 description spine02 + neighbor 10.255.255.2 update-source Loopback0 + ! + address-family l2vpn evpn + neighbor 10.255.255.1 activate + neighbor 10.255.255.2 activate + advertise-all-vni + exit-address-family +! +end diff --git a/scenarios/networking-lab/devstack-sonic-vxlan/local.conf.j2 b/scenarios/networking-lab/devstack-sonic-vxlan/local.conf.j2 new file mode 100644 index 00000000..df0cfa0b --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/local.conf.j2 @@ -0,0 +1,160 @@ +[[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 +NEUTRON_BRANCH=refs/changes/37/980637/1 +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 vxlan network for all operations +IRONIC_PROVISION_NETWORK_NAME=provisioning +IRONIC_PROVISION_PROVIDER_NETWORK_TYPE=vxlan +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=vxlan +Q_ML2_PLUGIN_MECHANISM_DRIVERS=ovn,baremetal-l2vni,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 + +# 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|$NEUTRON_CONF]] +[DEFAULT] +global_physnet_mtu = 1442 + +[baremetal_agent] +enable_ha_chassis_group_alignment = False +enable_router_ha_binding_events = True + +[baremetal_l2vni] +# Set to False for pure EVPN deployments where switches handle VXLAN via BGP +# Set to True if you need OVN localnet ports for overlay-to-physical bridging +create_localnet_ports = True +default_physical_network = public + +[l2vni] +# Enable L2VNI trunk reconciliation for network nodes +enable_l2vni_trunk_reconciliation = True +l2vni_reconciliation_interval = 300 +l2vni_auto_create_networks = True +l2vni_subport_anchor_network = l2vni-subport-anchor +l2vni_subport_anchor_network_type = vxlan +l2vni_startup_jitter_max = 60 +l2vni_network_nodes_config = /etc/neutron/l2vni_network_nodes.yaml + +[[post-config|/etc/neutron/plugins/ml2/ml2_conf_genericswitch.ini]] +[genericswitch:leaf01] +device_type = netmiko_sonic +ip = leaf01.stack.lab +username = admin +password = admin +ngs_disable_inactive_ports = true +ngs_physical_networks = public +ngs_nve_interface = vtep + +[genericswitch:leaf02] +device_type = netmiko_sonic +ip = leaf02.stack.lab +username = admin +password = admin +ngs_disable_inactive_ports = true +ngs_physical_networks = public +ngs_nve_interface = vtep diff --git a/scenarios/networking-lab/devstack-sonic-vxlan/spine01-config_db.json b/scenarios/networking-lab/devstack-sonic-vxlan/spine01-config_db.json new file mode 100644 index 00000000..bfada824 --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/spine01-config_db.json @@ -0,0 +1,68 @@ +{ + "DEVICE_METADATA": { + "localhost": { + "hostname": "spine01", + "type": "SpinRouter", + "bgp_asn": "65001", + "docker_routing_config_mode": "unified" + } + }, + "MGMT_INTERFACE": { + "eth0|192.168.32.111/24": { + "gwaddr": "192.168.32.1" + } + }, + "MGMT_PORT": { + "eth0": { + "alias": "eth0", + "admin_status": "up" + } + }, + "MGMT_VRF_CONFIG": { + "vrf_global": { + "mgmtVrfEnabled": "true" + } + }, + "LOOPBACK_INTERFACE": { + "Loopback0|10.255.255.1/32": {} + }, + "INTERFACE": { + "Ethernet0": { + "mtu": "1442" + }, + "Ethernet0|10.1.1.1/30": {}, + "Ethernet4": { + "mtu": "1442" + }, + "Ethernet4|10.1.1.5/30": {}, + "Ethernet8": { + "mtu": "1442" + }, + "Ethernet8|10.1.1.13/30": {} + }, + "PORT": { + "Ethernet0": { + "alias": "Ethernet0", + "lanes": "0", + "speed": "10000", + "admin_status": "up" + }, + "Ethernet4": { + "alias": "Ethernet4", + "lanes": "4", + "speed": "10000", + "admin_status": "up" + }, + "Ethernet8": { + "alias": "Ethernet8", + "lanes": "8", + "speed": "10000", + "admin_status": "up" + } + }, + "VXLAN_TUNNEL": { + "vtep": { + "src_ip": "10.255.255.1" + } + } +} diff --git a/scenarios/networking-lab/devstack-sonic-vxlan/spine01-frr.conf b/scenarios/networking-lab/devstack-sonic-vxlan/spine01-frr.conf new file mode 100644 index 00000000..bc1c992e --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/spine01-frr.conf @@ -0,0 +1,30 @@ +! +hostname spine01 +! +router ospf + ospf router-id 10.255.255.1 + network 10.1.1.0/30 area 0.0.0.0 + network 10.1.1.4/30 area 0.0.0.0 + network 10.1.1.12/30 area 0.0.0.0 + network 10.255.255.1/32 area 0.0.0.0 +! +router bgp 65001 + bgp router-id 10.255.255.1 + bgp log-neighbor-changes + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + neighbor 10.255.255.3 remote-as 65001 + neighbor 10.255.255.3 description leaf01 + neighbor 10.255.255.3 update-source Loopback0 + neighbor 10.255.255.4 remote-as 65001 + neighbor 10.255.255.4 description leaf02 + neighbor 10.255.255.4 update-source Loopback0 + ! + address-family l2vpn evpn + neighbor 10.255.255.3 activate + neighbor 10.255.255.3 route-reflector-client + neighbor 10.255.255.4 activate + neighbor 10.255.255.4 route-reflector-client + exit-address-family +! +end diff --git a/scenarios/networking-lab/devstack-sonic-vxlan/spine02-config_db.json b/scenarios/networking-lab/devstack-sonic-vxlan/spine02-config_db.json new file mode 100644 index 00000000..40635ba4 --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/spine02-config_db.json @@ -0,0 +1,68 @@ +{ + "DEVICE_METADATA": { + "localhost": { + "hostname": "spine02", + "type": "SpinRouter", + "bgp_asn": "65001", + "docker_routing_config_mode": "unified" + } + }, + "MGMT_INTERFACE": { + "eth0|192.168.32.112/24": { + "gwaddr": "192.168.32.1" + } + }, + "MGMT_PORT": { + "eth0": { + "alias": "eth0", + "admin_status": "up" + } + }, + "MGMT_VRF_CONFIG": { + "vrf_global": { + "mgmtVrfEnabled": "true" + } + }, + "LOOPBACK_INTERFACE": { + "Loopback0|10.255.255.2/32": {} + }, + "INTERFACE": { + "Ethernet0": { + "mtu": "1442" + }, + "Ethernet0|10.1.1.2/30": {}, + "Ethernet4": { + "mtu": "1442" + }, + "Ethernet4|10.1.1.9/30": {}, + "Ethernet8": { + "mtu": "1442" + }, + "Ethernet8|10.1.1.17/30": {} + }, + "PORT": { + "Ethernet0": { + "alias": "Ethernet0", + "lanes": "0", + "speed": "10000", + "admin_status": "up" + }, + "Ethernet4": { + "alias": "Ethernet4", + "lanes": "4", + "speed": "10000", + "admin_status": "up" + }, + "Ethernet8": { + "alias": "Ethernet8", + "lanes": "8", + "speed": "10000", + "admin_status": "up" + } + }, + "VXLAN_TUNNEL": { + "vtep": { + "src_ip": "10.255.255.2" + } + } +} diff --git a/scenarios/networking-lab/devstack-sonic-vxlan/spine02-frr.conf b/scenarios/networking-lab/devstack-sonic-vxlan/spine02-frr.conf new file mode 100644 index 00000000..df941d73 --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/spine02-frr.conf @@ -0,0 +1,30 @@ +! +hostname spine02 +! +router ospf + ospf router-id 10.255.255.2 + network 10.1.1.0/30 area 0.0.0.0 + network 10.1.1.8/30 area 0.0.0.0 + network 10.1.1.16/30 area 0.0.0.0 + network 10.255.255.2/32 area 0.0.0.0 +! +router bgp 65001 + bgp router-id 10.255.255.2 + bgp log-neighbor-changes + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + neighbor 10.255.255.3 remote-as 65001 + neighbor 10.255.255.3 description leaf01 + neighbor 10.255.255.3 update-source Loopback0 + neighbor 10.255.255.4 remote-as 65001 + neighbor 10.255.255.4 description leaf02 + neighbor 10.255.255.4 update-source Loopback0 + ! + address-family l2vpn evpn + neighbor 10.255.255.3 activate + neighbor 10.255.255.3 route-reflector-client + neighbor 10.255.255.4 activate + neighbor 10.255.255.4 route-reflector-client + exit-address-family +! +end diff --git a/scenarios/networking-lab/devstack-sonic-vxlan/topology-diagram.svg b/scenarios/networking-lab/devstack-sonic-vxlan/topology-diagram.svg new file mode 100644 index 00000000..669afc51 --- /dev/null +++ b/scenarios/networking-lab/devstack-sonic-vxlan/topology-diagram.svg @@ -0,0 +1,132 @@ + + + + + + + + + Spine-and-Leaf Topology (BGP AS 65001) + + + + + Management Network (192.168.32.0/24) + + + + controller + 192.168.32.254 + + + + + spine01 + (RR) + 10.255.255.1 + + + + spine02 + (RR) + 10.255.255.2 + + + + 10.1.1.0/30 + + + + + leaf01 + (RRC, vtep) + 10.255.255.3 + + + + leaf02 + (RRC, vtep) + 10.255.255.4 + + + + 10.1.1.4/30 + + + + 10.1.1.12/30 + + + + 10.1.1.8/30 + + + + 10.1.1.16/30 + + + + + devstack + 192.168.32.20 + + + + ironic0 + BM Node + + + + ironic1 + BM Node + + + + + Eth12 + + + + Eth8 + + + + Eth12 + + + + Legend + + Switch + + Server + + Controller + + P2P Link + + Management + + BGP EVPN + + + + + BGP EVPN: AS 65001 iBGP | RR=Route Reflector | RRC=Route Reflector Client | vtep=VXLAN VTEP + + + Leaf01: Ethernet8=Trunk, Ethernet12=Devstack | Leaf02: Ethernet8=Ironic0, Ethernet12=Ironic1 + +