Skip to main content

Netplan Configuration

Overview

OmniCore can automatically configure network interfaces on deployed VMs using netplan. This is useful for:

  • Setting up the primary management interface (eth0)
  • Adding secondary interfaces for public IPs, peering connections, or dedicated traffic
  • Configuring static routes for specific destinations

Enabling Netplan Configuration

To enable automatic netplan configuration for a host, add the netplan_config variable pointing to a Jinja2 template in your group_vars folder:

dra:
hosts:
<hostname>:
ansible_host: 10.0.1.100
gateway: 10.0.1.1
netplan_config: netplan.yaml.j2

The template will be sourced from hosts/<customer>/group_vars/netplan.yaml.j2.

Template Reference

Here is the complete netplan.yaml.j2 template with comments explaining each section:

network:
version: 2
ethernets:
# Primary interface - uses ansible_host and gateway from inventory
eth0:
addresses:
- "{{ ansible_host }}/{{ mask_cidr | default(24) }}"
nameservers:
addresses:
{% if 'dns' in group_names %}
# If this host IS a DNS server, use external DNS to avoid circular dependency
- 8.8.8.8
{% else %}
# Otherwise, use DNS servers from the 'dns' group in inventory
{% for dns_host in groups['dns'] | default([]) %}
- {{ hostvars[dns_host]['ansible_host'] }}
{% endfor %}
{% endif %}
search:
- slice
routes:
- to: "default"
via: "{{ gateway }}"

{% if secondary_ips is defined %}
# Secondary interfaces - loop through secondary_ips dict from inventory
# Interface naming: ens19, ens20, ens21... (18 + loop.index)
{% for nic_name, nic_config in secondary_ips.items() %}
ens{{ 18 + loop.index }}:
addresses:
- "{{ nic_config.ip_address }}/{{ mask_cidr | default(24) }}"
{% if nic_config.routes is defined %}
# Static routes for this interface - each route uses this interface's gateway
routes:
{% for route in nic_config.routes %}
- to: "{{ route }}"
via: "{{ nic_config.gateway }}"
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}

Key points:

  • ansible_host and gateway come from the host's inventory entry
  • DNS servers are dynamically pulled from hosts in the dns group
  • Secondary interfaces are named ens19, ens20, etc. to match Proxmox NIC naming
  • Each secondary IP can have its own gateway and static routes

Primary Interface Configuration

The primary interface (eth0) is configured automatically using:

  • ansible_host - The IP address
  • gateway - The default gateway
  • mask_cidr - Network mask (defaults to 24)

DNS servers are automatically set to:

  • Hosts in the dns group (uses their ansible_host IPs)
  • Falls back to 8.8.8.8 if the host is itself a DNS server

Secondary Interfaces

For hosts requiring additional network interfaces (public IPs, peering, etc.), use the secondary_ips configuration.

Schema

secondary_ips:
<logical_name>:
ip_address: <ip_address>
gateway: <gateway_ip>
host_vm_network: <proxmox_bridge>
vlanid: <vlan_id>
routes: # Optional - static routes via this interface
- '<destination_cidr>'
- '<destination_cidr>'

Interface Naming

Secondary interfaces are automatically named using Ubuntu's predictable naming scheme:

  • First secondary interface: ens19
  • Second secondary interface: ens20
  • Third secondary interface: ens21
  • And so on...

This matches the interface names assigned by Proxmox when adding additional NICs to a VM.

Example Configuration

dra:
hosts:
<hostname>:
ansible_host: 10.0.1.100
gateway: 10.0.1.1
host_vm_network: "ovsbr1"
vlanid: "100"
netplan_config: netplan.yaml.j2
secondary_ips:
public_ip:
ip_address: 192.0.2.50
gateway: 192.0.2.1
host_vm_network: "vmbr0"
vlanid: "200"
routes:
- '198.51.100.0/24'
- '203.0.113.0/24'
peering_ip:
ip_address: 172.16.50.10
gateway: 172.16.50.1
host_vm_network: "ovsbr2"
vlanid: "300"
routes:
- '172.17.0.0/16'

Generated Netplan Output

The above configuration generates:

network:
version: 2
ethernets:
eth0:
addresses:
- "10.0.1.100/24"
nameservers:
addresses:
- 10.0.1.53
search:
- slice
routes:
- to: "default"
via: "10.0.1.1"
ens19:
addresses:
- "192.0.2.50/24"
routes:
- to: "198.51.100.0/24"
via: "192.0.2.1"
- to: "203.0.113.0/24"
via: "192.0.2.1"
ens20:
addresses:
- "172.16.50.10/24"
routes:
- to: "172.17.0.0/16"
via: "172.16.50.1"

Proxmox Integration

When using the proxmox.yml playbook, secondary NICs are automatically created on the VM:

  1. New VMs: Secondary NICs are added during initial provisioning
  2. Existing VMs: Secondary NICs are added and the VM is rebooted to apply changes

The Proxmox configuration uses:

  • host_vm_network - The bridge to attach the NIC to
  • vlanid - VLAN tag for the interface

How It Works

  1. Variables from hosts file are passed to the Jinja2 template
  2. Template renders to /etc/netplan/01-netcfg.yaml
  3. Any existing netplan configs are removed to prevent conflicts
  4. netplan apply activates the configuration
  5. IP addresses are verified with ip addr show

Common Use Cases

Diameter Edge Agent (DEA) with Public IP

<hostname>:
ansible_host: 10.0.1.100 # Internal management IP
gateway: 10.0.1.1
netplan_config: netplan.yaml.j2
secondary_ips:
diameter_roaming:
ip_address: 192.0.2.50 # Public IP for roaming partners
gateway: 192.0.2.1
host_vm_network: "vmbr0"
vlanid: "200"
routes:
- '198.51.100.0/24' # Roaming partner network

PGW with S5/S8 Interface

<hostname>:
ansible_host: 10.0.2.20 # Internal IP
gateway: 10.0.2.1
netplan_config: netplan.yaml.j2
secondary_ips:
s5s8_interface:
ip_address: 203.0.113.17 # Public S5/S8 IP
gateway: 203.0.113.1
host_vm_network: "vmbr0"
vlanid: "50"

Multi-homed Server with Separate Management and Data Networks

<hostname>:
ansible_host: 10.0.1.100 # Management network
gateway: 10.0.1.1
netplan_config: netplan.yaml.j2
secondary_ips:
data_network:
ip_address: 10.0.2.100 # Data network
gateway: 10.0.2.1
host_vm_network: "ovsbr2"
vlanid: "200"
backup_network:
ip_address: 10.0.3.100 # Backup network
gateway: 10.0.3.1
host_vm_network: "ovsbr3"
vlanid: "300"

Referencing Secondary IPs in Templates

You can reference secondary IP addresses in other Jinja2 templates and configuration files.

On the Same Host

When configuring a service on the same host that has secondary IPs, you can reference directly or use inventory_hostname:

# Reference directly (simplest)
{{ secondary_ips.diameter_public_ip.ip_address }}

# Or explicitly via inventory_hostname (same result)
{{ hostvars[inventory_hostname]['secondary_ips']['diameter_public_ip']['ip_address'] }}

# Access other properties
{{ secondary_ips.diameter_public_ip.gateway }}
{{ secondary_ips.diameter_public_ip.vlanid }}

From Another Host

When you need to reference a different host's secondary IP (e.g., configuring a peer connection), use hostvars with the target hostname:

# Reference first host in dra group
{{ hostvars[groups['dra'][0]]['secondary_ips']['diameter_public_ip']['ip_address'] }}

# Loop through all DRA hosts and get their public IPs
{% for host in groups['dra'] %}
{% if hostvars[host]['secondary_ips'] is defined %}
- {{ hostvars[host]['secondary_ips']['diameter_public_ip']['ip_address'] }}
{% endif %}
{% endfor %}

Example: DRA Peer Configuration

Configure a diameter peer to bind to its own public IP:

# In dra_config.yaml.j2 - use inventory_hostname for the current host
peers:
- name: external_peer
# Bind to this host's public diameter IP
local_ip: {{ hostvars[inventory_hostname]['secondary_ips']['diameter_public_ip']['ip_address'] }}
remote_ip: 198.51.100.50
port: 3868

Checking if Secondary IPs Exist

Always check if the variable exists before using it:

{% if secondary_ips is defined and secondary_ips.diameter_public_ip is defined %}
public_ip: {{ secondary_ips.diameter_public_ip.ip_address }}
{% else %}
public_ip: {{ ansible_host }}
{% endif %}

Troubleshooting

Verify Interface Names

SSH to the VM and check interface names:

ip link show

Expected output for a VM with two secondary interfaces:

1: lo: <LOOPBACK,UP,LOWER_UP> ...
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
3: ens19: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
4: ens20: <BROADCAST,MULTICAST,UP,LOWER_UP> ...

Check Netplan Configuration

cat /etc/netplan/01-netcfg.yaml

Apply Netplan Manually

netplan apply

Debug Netplan

netplan --debug apply

Verify Routes

ip route show