Cumulus – VXLAN statique

Cumulus Linux permet de construire des architectures traditionnelles avec des agrégations de liens appelées « Bonds » et la fonction MLAG (Multi-chassis Link Aggregation), mais son terrain de prédilection est la réalisation d’architectures IP Fabric (Clos Network) avec le concept Underlay/Overlay et le protocole VXLAN (Virtual Extensible LAN).

Traditionnellement, la virtualisation réseau est assurée par la notion de VLAN sur un réseau de niveau 2, mais les limitations de ce modèle ont ouvert la voie à la virtualisation de réseau VXLAN (RFC 7348 – A Framework for Overlaying Virtualized Layer 2 Networks over Layer 3 Networks) assurant la connectivité des réseaux logiques de niveau 2 par dessus un underlay en niveau 3. VXLAN utilise une identification de 24 bits appelée VNI (VXLAN Network Identifier) qui a une signification globale sur l’infrastructure et qui permet de réaliser 16.777.216 réseaux virtuels différents. VXLAN encapsule la trame (adresse MAC) dans un paquet IP/UDP et la correspondance VLAN/VNI n’a de valeur que locale à l’équipement qui supporte VXLAN et qui assure l’encapsulation et la désencapsulation. Cet équipement est appelé un VTEP (Virtual Tunnel Endpoint). En outre, le VTEP supprime le tag de VLAN en entrée et le remplace par l’entête VXLAN qui contient le VNI. Le VTEP d’arrivée effectue la manipulation inverse, sachant que le tag de VLAN de sortie n’est pas obligatoirement le même que celui d’entrée.

Dans une approche de VXLAN statique sans « Control Plane », l’utilisation de BGP pour l’underlay n’est pas obligatoire, mais autant commencer à l’implémenter pour un usage ultérieur. C’est le protocole eBGP (external BGP) qui est utilisé. Il a la particularité d’échanger des informations entre les AS (Autonomous Systems) qui doivent être directement connectés. Dans cette approche, les tunnels entre les VTEP sont créés manuellement pour mettre en relation les équipements en niveau 2. Pour router entre les VXLANs, il est possible d’utiliser le routage asymétrique ou le routage symétrique.

Le modèle symétrique route et bridge à la fois sur les Leafs d’entrée et de sortie. Il en résulte que le trafic bidirectionnel peut transiter sur le même VNI, d’où le nom symétrique. Cependant, un nouveau VNI de transit spécialisé, appelé L3VNI, est utilisé pour tout le trafic VXLAN routé. Tout le trafic qui doit être acheminé, le sera sur le L3VNI, tunnelisé à travers l’infrastructure de niveau 3, acheminé du L3VNI vers le VLAN approprié et finalement bridgé vers la destination.

Le routage asymétrique, appelé « Asymmetric IRB (Integrated Routing and Bridging) », consiste à effectuer le routage entre les VXLAN/VNI sur chacun des Leafs, dans le cadre d’une architecture « Leaf-Spine ». Cette approche ressemble fortement au processus de routage inter-vlans tel qu’il est généralement implémenté. Par soucis de simplicité, il est tout à fait possible de définir la même passerelle sur chacun des Leafs plutôt que de mettre en place un protocole de redondance de type VRR avec une adresse IP virtuelle. Ce mode de routage est adapté à cette simulation car tous les VNIs sont déployés sur l’ensemble des commutateurs Leafs et il y a un petit nombre de VNIs.

L’utilisation de l’automatisation Ansible est l’occasion de mettre en place la version 2.10 qui amène une rupture avec la version précédente. Dans cette version, de nombreux plugins et modules ont été retirés de façon à proposer un produit de base avec un ensemble de « collections » externalisées.

L’automatisation Ansible avec Cumulus fait appel au « network module nclu » disponible après l’installation de la collection « community.network » : ansible-galaxy collection install community.network.

Le module nclu peut être utilisé pour configurer les équipements en lui donnant une liste de commandes à appliquer ou une syntaxe de template Jinja2 à utiliser pour générer la liste des commandes. Il est possible de demander l’application de la configuration (commit: yes), l’abandon de modifications précédentes, toujours en attente et qui n’auraient pas été appliquées (abort: yes) ou les deux (atomic: yes).

La simulation est mise en place sur EVE-NG Pro avec Cumulus VX 4.2.1 et des serveurs Alpine Linux en tant que machines de test.

Cumulus Static VXLAN
Simulation EVE-NG Pro
[defaults]
inventory = ./hosts
host_key_checking = False
interpreter_python=auto
roles_path = roles.galaxy:roles
collections_paths = collections.galaxy:collections
[all:children]
fabric

[fabric:children]
spines
leafs

[fabric:vars]
ansible_user=cumulus

[spines]
spine1 ansible_host=192.168.105.15
spine2 ansible_host=192.168.105.16

[leafs]
leaf1 ansible_host=192.168.105.17
leaf2 ansible_host=192.168.105.18
---
# group_vars/spines.yml
as: 65100
---
# host_vars/spine1.yml
loopback: 172.16.100.3
---
# host_vars/spine2.yml
loopback: 172.16.100.4
---
# host_vars/leaf1.yml
loopback: 172.16.100.1
as: 65101
vxlans:
  - name: VNI-10
    id: 10
    local_ip: 172.16.100.1
    remote_ip: 172.16.100.2
    vlan: 10
    vlan_gw: 192.168.10.254
    interface: swp3
  - name: VNI-20
    id: 20
    local_ip: 172.16.100.1
    remote_ip: 172.16.100.2
    vlan: 20
    vlan_gw: 192.168.20.254
    interface: swp4
---
# host_vars/leaf2.yml
loopback: 172.16.100.2
as: 65102
vxlans:
  - name: VNI-10
    id: 10
    local_ip: 172.16.100.2
    remote_ip: 172.16.100.1
    vlan: 100
    vlan_gw: 192.168.10.254
    interface: swp3
  - name: VNI-20
    id: 20
    local_ip: 172.16.100.2
    remote_ip: 172.16.100.1
    vlan: 200
    vlan_gw: 192.168.20.254
    interface: swp4
---
- name: Create demo lab Cumulus
  hosts: all
  gather_facts: no
  roles:
    - role: underlay_ebgp
      tags: [ underlay ]
    - role: overlay_static
      tags: [ static ]
---
# roles/underlay_ebpg/tasks/main.yml
- name: Configure eBGP underlay
  community.network.nclu:
    commands:
      - add loopback lo ip address {{ loopback }}/32
      - add bgp autonomous-system {{ as }}
      - add bgp neighbor swp1 interface remote-as external
      - add bgp neighbor swp2 interface remote-as external
      - add bgp network {{ loopback }}/32
    atomic: true
  when: "'fabric' in group_names"
---
# roles/overlay_static/tasks/main.yml
- name: Configure static VXLANs
  community.network.nclu:
    template: |
      {% for vxlan in vxlans %}
      add interface {{ vxlan.interface }} bridge access {{ vxlan.vlan }}
      add vxlan {{ vxlan.name }} vxlan id {{ vxlan.id }}
      add vxlan {{ vxlan.name }} vxlan local-tunnelip {{ vxlan.local_ip }}
      add vxlan {{ vxlan.name }} vxlan remoteip {{ vxlan.remote_ip }}
      add vxlan {{ vxlan.name }} bridge access {{ vxlan.vlan }}
      add vlan {{ vxlan.vlan }} ip address {{ vxlan.vlan_gw }}/24
      {% endfor %}
    atomic: true
  when: "'leafs' in group_names"
Ansible Playbook Static VXLAN
ansible-playbook site.yml
Cumulus Underlay eBGP
Underlay eBGP

On peut noter la simplicité de configuration du VXLAN statique et du routage asymétrique avec le Network Module nclu d’Ansible. Il est possible d’effectuer un ping depuis chaque serveur vers tous les autres, le routage étant réalisé au plus proche du serveur sur les Leafs respectifs (ingress VTEP).