Roles
Ansible

Ansible Overlay Role

The overlay role is responsible for configuring the VXLAN EVPN overlay on leaf devices. This includes VLAN-to-VNI mappings, L3VNI VRF configuration, anycast gateway SVIs, VXLAN VTEP NVE interface configuration, L2VNI and L3VNI NVE mappings, EVPN VNI route targets, BGP VRF address-families, and Layer 2/Layer 3 interface configuration. Like the other roles, the overlay role leverages the pre-staged Jinja2 templates to generate configuration payloads using ansible.builtin.template lookups with set_fact, which are then passed to the corresponding NXOS collection modules.

The overlay role makes use of the following NXOS collection modules:

  • cisco.nxos.nxos_overlay_global
  • cisco.nxos.nxos_vlans
  • cisco.nxos.vrf_global
  • cisco.nxos.nxos_vrf_interfaces
  • cisco.nxos.nxos_interfaces
  • cisco.nxos.nxos_l3_interfaces
  • cisco.nxos.nxos_l2_interfaces
  • cisco.nxos.nxos_vxlan_vtep
  • cisco.nxos.nxos_vxlan_vtep_vni
  • cisco.nxos.nxos_evpn_vni
  • cisco.nxos.nxos_bgp_address_family

Generates

      
  fabric forwarding anycast-gateway-mac 1234.5678.9000
  vlan 101
      vn-segment 10101
  vlan 102
      vn-segment 10102
  vlan 500
      vn-segment 50000
  vrf context AnsibleVRF
      vni 50000
      rd auto
      address-family ipv4 unicast
          route-target both auto evpn
  interface Vlan500
      vrf member AnsibleVRF
      ip forward
  interface Vlan101
      vrf member AnsibleVRF
      ip address 192.168.1.1/24
      fabric forwarding mode anycast-gateway
  interface nve1
      source-interface loopback1
      host-reachability protocol bgp
      member vni 50000 associate-vrf
      member vni 10101
          mcast-group 239.1.1.1
  evpn
      vni 10101 l2
          rd auto
          route-target import auto
          route-target export auto
  router bgp 65001
      vrf AnsibleVRF
          address-family ipv4 unicast
              advertise l2vpn evpn
      
    

The overlay role is organized into the following logical sections:

  • Anycast gateway & VLAN configuration — sets the anycast gateway MAC address on leaf switches and configures VLAN-to-VNI mappings using Jinja2 templates rendered via set_fact.
  • VRF configuration — configures L3VNI VRFs and associates anycast gateway SVIs with their respective VRFs using Jinja2-generated payloads with state: overridden.
  • Interface configuration — configures Layer 3, Layer 2, and loopback interfaces along with IP addressing. Also handles cleanup of interfaces that should no longer be configured.
  • VXLAN VTEP configuration — configures the NVE interface, L3VNI and L2VNI NVE mappings with multicast groups, and L2VNI EVPN route targets.
  • BGP VRF configuration — configures BGP VRF address-families for advertising L2VPN EVPN routes using Jinja2-generated payloads with state: overridden.

Step 1 - Open Overlay Role Tasks File

Return to your VSCode Terminal to open and build-out the main.yml file found in roles/overlay/tasks/.


code-server -r /home/pod06/workspace/nxapilab/ansible-nxos/roles/overlay/tasks/main.yml


Step 2 - Update Overlay Role Tasks File

Copy the below YAML into the roles/overlay/tasks/main.yml file that is opened in VSCode. These tasks use the variables you defined in your group_vars and host_vars along with the pre-staged Jinja2 templates to generate each configuration payload before applying it to the devices.

The first section sets the anycast gateway MAC address on leaf switches and configures the VLAN-to-VNI mappings. It then configures the L3VNI VRFs and associates the anycast gateway SVIs with their respective VRFs.



- name: Generate VLAN(s) Payload
  ansible.builtin.set_fact:
    nxos_vlans: "{{ lookup('ansible.builtin.template', playbook_dir ~ '/templates/config/nxos_vlans.j2') }}"
  when: inventory_hostname in groups['leafs']

- name: Configure VLAN-to-VNI Mappings
  cisco.nxos.nxos_vlans:
    config: "{{ (nxos_vlans | ansible.builtin.from_yaml) }}"
    state: overridden
  when: inventory_hostname in groups['leafs']

- name: Generate L3VNI VRF(s) Payload
  ansible.builtin.set_fact:
    nxos_vrfs: "{{ lookup('ansible.builtin.template', playbook_dir ~ '/templates/config/nxos_vrfs.j2') }}"
  when: inventory_hostname in groups['leafs']

- name: Configure L3VNI VRF(s)
  cisco.nxos.vrf_global:
    config: "{{ nxos_vrfs | ansible.builtin.from_yaml }}"
    state: overridden
  when: inventory_hostname in groups['leafs']

- name: Generate Anycast Gateways VRF Payload
  ansible.builtin.set_fact:
    nxos_vrf_interfaces: "{{ lookup('ansible.builtin.template', playbook_dir ~ '/templates/config/nxos_vrf_interfaces.j2') }}"
  when: inventory_hostname in groups['leafs']

- name: Configure Anycast Gateways VRF Association
  cisco.nxos.nxos_vrf_interfaces:
    config: "{{ nxos_vrf_interfaces | ansible.builtin.from_yaml }}"
    state: overridden
  when: inventory_hostname in groups['leafs']

The next section configures Layer 3 interfaces, Layer 2 interfaces, and loopback interfaces with their IP addresses. It also gathers the current interface state and removes any interfaces that are no longer defined in the variables. The VXLAN VTEP NVE interface is configured on leaf switches.



- name: Generate L3 Interface(s) Payload
  ansible.builtin.set_fact:
    nxos_interfaces: "{{ lookup('ansible.builtin.template', playbook_dir ~ '/templates/config/nxos_interfaces.j2') }}"

- name: Configure L3 Interface(s)
  cisco.nxos.nxos_interfaces:
    config: "{{ nxos_interfaces | ansible.builtin.from_yaml }}"
    state: overridden

- name: Generate L3 Interface(s) IPv4 Payload
  ansible.builtin.set_fact:
    nxos_l3_interfaces: "{{ lookup('ansible.builtin.template', playbook_dir ~ '/templates/config/nxos_l3_interfaces.j2') }}"

- name: Configure IP Address on L3 Interfaces
  cisco.nxos.nxos_l3_interfaces:
    config: "{{ nxos_l3_interfaces | ansible.builtin.from_yaml }}"
    state: replaced

- name: Generate Loopback Interface(s) IPv4 Payload
  ansible.builtin.set_fact:
    nxos_loopback_interfaces_ipv4: "{{ lookup('ansible.builtin.template', playbook_dir ~ '/templates/config/nxos_loopback_interfaces_ipv4.j2') }}"

- name: Configure IP Address on Loopback Interfaces
  cisco.nxos.nxos_l3_interfaces:
    config: "{{ nxos_loopback_interfaces_ipv4 | ansible.builtin.from_yaml }}"
    state: merged

- name: Generate L2 Interface(s) Payload
  ansible.builtin.set_fact:
    nxos_l2_interfaces: "{{ lookup('ansible.builtin.template', playbook_dir ~ '/templates/config/nxos_l2_interfaces.j2') }}"

- name: Configure L2 Interfaces
  cisco.nxos.nxos_l2_interfaces:
    config: "{{ nxos_l2_interfaces | ansible.builtin.from_yaml }}"
    state: replaced
  when:
    - layer2_physical_interfaces is defined
    - layer2_physical_interfaces is iterable

- name: Configure VXLAN VTEP NVE Interface
  cisco.nxos.nxos_vxlan_vtep:
    interface: nve1
    host_reachability: true
    source_interface: Loopback1
    shutdown: false
    state: present
  when: inventory_hostname in groups['leafs']

- name: Get Interface(s)
  cisco.nxos.nxos_interfaces:
    state: gathered
  register: current_nxos_interfaces

- name: Generate L3 Interface(s) to Remove Payload
  ansible.builtin.set_fact:
    nxos_interfaces_to_remove: "{{ lookup('ansible.builtin.template', playbook_dir ~ '/templates/config/nxos_interfaces_to_remove.j2') }}"

- name: Remove L3 Interface(s)
  cisco.nxos.nxos_interfaces:
    config: "{{ nxos_interfaces_to_remove | ansible.builtin.from_yaml }}"
    state: purged
  when: nxos_interfaces_to_remove | ansible.builtin.from_yaml | length > 0

The final section configures the VXLAN VTEP NVE interface L3VNI and L2VNI mappings, L2VNI EVPN route targets, and BGP VRF address-families for advertising L2VPN EVPN routes on leaf switches.



- name: Configure VXLAN VTEP NVE Interface L3VNI & L2VNI Mapping(s)
  cisco.nxos.nxos_vxlan_vtep_vni:
    interface: nve1
    vni: "{{ item.vni_id }}"
    assoc_vrf: "{{ true if 'vrf' not in item else omit }}"
    multicast_group: "{{ item.mcast_grp if 'mcast_grp' in item else omit }}"
    state: present
  when: >
    (item.name is defined and item.name != 'management') or
    (item.vlan_id is defined and item.vlan_id != 1)
  loop: "{{ vrfs + networks }}"

- name: Get NVE VNIs
  ansible.utils.cli_parse:
    command: show nve vni | json
    parser:
      name: ansible.utils.json
    set_fact: parsed_output

- name: Normalize VNI Data From Switch
  ansible.builtin.set_fact:
    switch_vni_list: "{{ [parsed_output.TABLE_nve_vni.ROW_nve_vni] if parsed_output.TABLE_nve_vni.ROW_nve_vni is mapping else parsed_output.TABLE_nve_vni.ROW_nve_vni }}"

- name: Parsed Defined VRFs and Networks VNIs From Switch
  ansible.builtin.set_fact:
    switch_vnis: "{{ switch_vni_list | map(attribute='vni') | map('int') | list }}"

- name: Parsed Defined VRFs and Networks VNIs From Data
  ansible.builtin.set_fact:
    defined_vnis: "{{ (vrfs + networks) | selectattr('vni_id', 'defined') | map(attribute='vni_id') | list | unique | default([]) }}"

- name: Determine VNIs to Unconfigure
  ansible.builtin.set_fact:
    vnis_to_unconfigure: "{{ switch_vnis | difference(defined_vnis) | list }}"

- name: Remove NVE Interface L3VNI & L2VNI Mapping(s)
  cisco.nxos.nxos_vxlan_vtep_vni:
    interface: nve1
    vni: "{{ item }}"
    state: absent
  when: vnis_to_unconfigure | length > 0
  loop: "{{ vnis_to_unconfigure }}"

- name: Configure L2VNI Under EVPN
  cisco.nxos.nxos_evpn_vni:
    vni: "{{ item.vni_id }}"
    route_distinguisher: auto
    route_target_both: auto
    state: present
  when: item.vlan_id != 1
  loop: "{{ networks }}"

- name: Remove L2VNI Under EVPN
  cisco.nxos.nxos_evpn_vni:
    vni: "{{ item }}"
    state: absent
  when: vnis_to_unconfigure | length > 0
  loop: "{{ vnis_to_unconfigure }}"

- name: Generate BGP VRF Address-Family(ies) Payload
  ansible.builtin.set_fact:
    nxos_bgp_vrf_af: "{{ lookup('ansible.builtin.template', playbook_dir ~ '/templates/config/nxos_bgp_vrf_af.j2') }}"
  when: inventory_hostname in groups['leafs']

- name: Configure BGP VRF Address-Family(ies)
  cisco.nxos.nxos_bgp_address_family:
    config: "{{ nxos_bgp_vrf_af | ansible.builtin.from_yaml }}"
    state: overridden
  when: inventory_hostname in groups['leafs']


Continue on to the next section for the final pieces needed to execute your Ansible playbook to finish configuring the VXLAN EVPN fabric.