diff --git a/ansible/physical-network.yml b/ansible/physical-network.yml
index 8891a62c5..c9e411f11 100644
--- a/ansible/physical-network.yml
+++ b/ansible/physical-network.yml
@@ -29,6 +29,7 @@
# List of supported values for the 'switch_type' variable.
supported_switch_types:
- arista
+ - cisco-nxos
- dellos6
- dellos9
- dellos10
@@ -126,6 +127,22 @@
arista_switch_config: "{{ switch_config }}"
arista_switch_interface_config: "{{ switch_interface_config }}"
+- name: Ensure Cisco NX-OS physical switches are configured
+ hosts: switches_of_type_cisco-nxos:&switches_in_display_mode_False
+ gather_facts: no
+ max_fail_percentage: >-
+ {{ physical_network_max_fail_percentage |
+ default(kayobe_max_fail_percentage) |
+ default(100) }}
+ roles:
+ - role: ssh-known-host
+ when: not switch_skip_keyscan | bool
+
+ - role: cisco-nxos-switch
+ cisco_nxos_switch_config: "{{ switch_config }}"
+ cisco_nxos_switch_interface_config: "{{ switch_interface_config }}"
+ cisco_nxos_switch_save: "{{ switch_config_save }}"
+
- name: Ensure DellOS physical switches are configured
hosts: switches_of_type_dellos6:switches_of_type_dellos9:switches_of_type_dellos10:&switches_in_display_mode_False
gather_facts: no
diff --git a/ansible/roles/cisco-nxos-switch/README.md b/ansible/roles/cisco-nxos-switch/README.md
new file mode 100644
index 000000000..e51f59cdd
--- /dev/null
+++ b/ansible/roles/cisco-nxos-switch/README.md
@@ -0,0 +1,59 @@
+Cisco NX-OS Switch
+==================
+
+This role configures Cisco NX-OS switches using the `cisco.nxos.nxos_config`
+Ansible module. It allows global and per-interface configuration commands to
+be applied to the switch.
+
+Requirements
+------------
+
+The switches should be configured to allow SSH access.
+
+The `cisco.nxos` Ansible collection must be installed.
+
+Role Variables
+--------------
+
+`cisco_nxos_switch_config` is a list of configuration lines to apply to the
+switch, and defaults to an empty list.
+
+`cisco_nxos_switch_interface_config` is a dict mapping switch interface names
+to configuration dicts, and defaults to an empty dict. Each dict contains:
+
+- `description` - an optional description to apply to the interface.
+- `config` - a list of per-interface configuration commands.
+
+`cisco_nxos_switch_save` controls whether the running configuration is saved
+to the startup configuration when they differ, including any previously unsaved
+changes. Defaults to `false`.
+
+Dependencies
+------------
+
+None
+
+Example Playbook
+----------------
+
+The following playbook configures hosts in the `cisco-nxos-switches` group.
+It assumes host variables for each switch holding the host and SSH credentials.
+It enables LLDP and configures an Ethernet interface as a switchport.
+
+ ---
+ - name: Ensure Cisco NX-OS switches are configured
+ hosts: cisco-nxos-switches
+ gather_facts: no
+ vars:
+ ansible_connection: ansible.netcommon.network_cli
+ ansible_network_os: cisco.nxos.nxos
+ roles:
+ - role: cisco-nxos-switch
+ cisco_nxos_switch_config:
+ - "feature lldp"
+ cisco_nxos_switch_interface_config:
+ Ethernet1/1:
+ description: server-1
+ config:
+ - "switchport"
+ - "switchport mode access"
diff --git a/ansible/roles/cisco-nxos-switch/defaults/main.yml b/ansible/roles/cisco-nxos-switch/defaults/main.yml
new file mode 100644
index 000000000..8356cac5a
--- /dev/null
+++ b/ansible/roles/cisco-nxos-switch/defaults/main.yml
@@ -0,0 +1,11 @@
+---
+# List of configuration lines to apply to the switch.
+cisco_nxos_switch_config: []
+
+# Interface configuration. Dict mapping switch interface names to configuration
+# dicts. Each dict contains an optional 'description' item and a 'config' item
+# which should contain a list of per-interface configuration.
+cisco_nxos_switch_interface_config: {}
+
+# Whether to save the configuration.
+cisco_nxos_switch_save: false
diff --git a/ansible/roles/cisco-nxos-switch/tasks/main.yml b/ansible/roles/cisco-nxos-switch/tasks/main.yml
new file mode 100644
index 000000000..beb5cd07b
--- /dev/null
+++ b/ansible/roles/cisco-nxos-switch/tasks/main.yml
@@ -0,0 +1,6 @@
+---
+- name: Ensure Cisco NX-OS switches are configured
+ cisco.nxos.nxos_config:
+ content: "{{ lookup('template', 'cisco-nxos-config.j2') }}"
+ save_when: >-
+ {{ cisco_nxos_switch_save | bool | ternary('modified', 'never') }}
diff --git a/ansible/roles/cisco-nxos-switch/templates/cisco-nxos-config.j2 b/ansible/roles/cisco-nxos-switch/templates/cisco-nxos-config.j2
new file mode 100644
index 000000000..d219991f9
--- /dev/null
+++ b/ansible/roles/cisco-nxos-switch/templates/cisco-nxos-config.j2
@@ -0,0 +1,16 @@
+#jinja2: trim_blocks: True,lstrip_blocks: True
+
+{% for line in cisco_nxos_switch_config %}
+{{ line }}
+{% endfor %}
+
+{% for interface, config in cisco_nxos_switch_interface_config.items() %}
+interface {{ interface }}
+{% if config.description is defined %}
+ description {{ config.description }}
+{% endif %}
+{% for line in config.config %}
+ {{ line }}
+{% endfor %}
+!
+{% endfor %}
diff --git a/ansible/roles/dell-switch/templates/dellos10-config.j2 b/ansible/roles/dell-switch/templates/dellos10-config.j2
index 7904f89c6..0fcbec176 100644
--- a/ansible/roles/dell-switch/templates/dellos10-config.j2
+++ b/ansible/roles/dell-switch/templates/dellos10-config.j2
@@ -4,13 +4,28 @@
{{ line }}
{% endfor %}
+{# Configure VLAN interfaces first as others might depend on them. #}
+
{% for interface, config in dell_switch_interface_config.items() %}
+{% if 'vlan' in interface %}
interface {{ interface }}
{% if config.description is defined %}
-description "{{ config.description }}"
+ description "{{ config.description }}"
{% endif %}
{% for line in config.config %}
-{{ line }}
+ {{ line }}
+{% endfor %}
+{% endif %}
+{% endfor %}
+
+{% for interface, config in dell_switch_interface_config.items() %}
+{% if 'vlan' not in interface %}
+interface {{ interface }}
+{% if config.description is defined %}
+ description "{{ config.description }}"
+{% endif %}
+{% for line in config.config %}
+ {{ line }}
{% endfor %}
-exit
+{% endif %}
{% endfor %}
diff --git a/doc/source/configuration/reference/physical-network.rst b/doc/source/configuration/reference/physical-network.rst
index ff00a60c8..2cd3815bf 100644
--- a/doc/source/configuration/reference/physical-network.rst
+++ b/doc/source/configuration/reference/physical-network.rst
@@ -15,6 +15,7 @@ configure`` command. See :ref:`physical-network` for details.
The following switch operating systems are currently supported:
* Arista EOS
+* Cisco NX-OS
* Cumulus Linux (via `Network Command Line Utility (NCLU)
`__)
* Cumulus Linux (via `NVIDIA User Experience command line utility (NVUE)
@@ -213,6 +214,44 @@ modules.
* ``ansible_become`` should be ``true``.
* ``ansible_become_method`` should be ``enable``.
+Cisco NX-OS
+-----------
+
+Configuration for these devices is applied using the ``cisco-nxos-switch``
+Ansible role in Kayobe. The role configures Cisco NX-OS switches using the
+``cisco.nxos.nxos_config`` Ansible module.
+
+``switch_type`` should be set to ``cisco-nxos``.
+
+``switch_config_save`` may be set to ``true`` to save the running configuration
+to the startup configuration when they differ, including any previously unsaved
+changes.
+
+* ``ansible_host`` is the hostname or IP address. Optional.
+* ``ansible_user`` is the SSH username.
+* ``ansible_ssh_pass`` is the SSH password, if using password authentication.
+* ``ansible_connection`` should be ``ansible.netcommon.network_cli``.
+* ``ansible_network_os`` should be ``cisco.nxos.nxos``.
+
+The SSH user must have permission to configure the switch.
+
+For example, the following host variables enable LLDP and configure a
+switchport:
+
+.. code-block:: yaml
+
+ switch_type: cisco-nxos
+ ansible_connection: ansible.netcommon.network_cli
+ ansible_network_os: cisco.nxos.nxos
+ switch_config:
+ - "feature lldp"
+ switch_interface_config:
+ Ethernet1/1:
+ description: server-1
+ config:
+ - "switchport"
+ - "switchport mode access"
+
Cumulus Linux (with NCLU)
-------------------------
diff --git a/releasenotes/notes/add-cisco-nxos-switch-support-6ef2c747d24e5197.yaml b/releasenotes/notes/add-cisco-nxos-switch-support-6ef2c747d24e5197.yaml
new file mode 100644
index 000000000..7886998b7
--- /dev/null
+++ b/releasenotes/notes/add-cisco-nxos-switch-support-6ef2c747d24e5197.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Adds support for configuring Cisco NX-OS switches with
+ ``kayobe physical network configure``. Set ``switch_type`` to
+ ``cisco-nxos`` to use this support.
diff --git a/releasenotes/notes/bug-2168529-b206bb5ace7090b3.yaml b/releasenotes/notes/bug-2168529-b206bb5ace7090b3.yaml
new file mode 100644
index 000000000..d06aaa964
--- /dev/null
+++ b/releasenotes/notes/bug-2168529-b206bb5ace7090b3.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+ - |
+ Fixes Dell OS10 switch config. Also makes sure that VLAN interfaces are
+ defined first as others might depend on them.
+ `LP#2168529 `__
diff --git a/requirements.yml b/requirements.yml
index 801dc361d..27430ac0d 100644
--- a/requirements.yml
+++ b/requirements.yml
@@ -3,6 +3,8 @@ collections:
- name: https://opendev.org/openstack/ansible-collection-kolla
type: git
version: stable/2025.1
+ - name: cisco.nxos
+ version: 13.0.0
- name: community.docker
version: 3.11.0
- name: community.network