Table of Contents

EVE-KVM: Deploying a VM and configuring its network

This page documents how a VM (edge app instance) attaches to the network on EVE-OS in KVM (hypervisor) mode, and describes every interface binding option available when deploying the instance (ZedControl UI or Terraform).

Scope. This is the per-instance interface binding — how a VM's adapters
map onto Network Instances. It complements the NI lifecycle page (how Local and
Switch NIs are built). Field semantics below are from the zedcloud appInterface
API model; runtime behaviour is from EVE pkg/pillar (zedrouter / nireconciler).

Two ways an interface attaches

Each VM adapter attaches in one of two modes, selected by the directattach flag:

What is a VIF

VIF = virtual interface — the host-side tap/virtio netdev EVE creates for an NI-backed adapter. Two ends exist:

domainmgr hands the VIF to QEMU/KVM as the backend for the guest's virtio-net device. (EVE-K analogue: the Multus pod-side VIF; same concept, different plumbing — tap-into-Linux-bridge here vs. CNI there.) A direct-attach adapter has no VIF.

Interface binding — parameter reference

Fields of one interfaces { } block (Terraform) = one appInterface (API) = one row in the Adapters & Networks step (UI):

access_vlan_id in depth

API model doc (appInterface.accessVlanId): VLAN id of zero is treated as a trunk port; VLAN id 1 is implicitly used by Linux bridges; min 2, max 4093. EVE implements exactly this in nireconciler/linux_config.go:

if ul.AccessVlanID <= 1 {
    vlanConfig.TrunkPort = &linux.TrunkPort{AllVIDs: true}   // 0 or 1 -> trunk, all VLANs
} else {
    vlanConfig.AccessPort = &linux.AccessPort{VID: uint16(ul.AccessVlanID)}  // >=2 -> access port
}

Three regimes:

Two non-obvious behaviours:

Terraform example (NI-backed VM)

A standalone Ubuntu VM with a single virtio adapter on a Switch NI, trunk mode (access_vlan_id = 0):

resource "zedcloud_application_instance" "tf_stndlone_vm_1" {
  name       = "TF-STND-ATL-VM-1"
  title      = "TF-STND-ATL-VM-1"
  project_id = zedcloud_project.demo_zededa_project_1.id
  app_id     = zedcloud_application.tf_atl_ub_app_1.id
  activate   = true
  device_id  = zedcloud_edgenode.demo_en_advantech_1.id

  custom_config {
    add                  = true
    allow_storage_resize = true
    field_delimiter      = "@@@"
    name                 = "cloud-config"
    override             = true
    template             = base64encode(templatefile("./c-init/vm-1-enp1s0.txt", { hostname = var.vm1_hostname }))
  }

  drives {
    imagename   = zedcloud_image.demo_atl_ub_image_1.name
    cleartext   = false
    ignorepurge = false
    maxsize     = 20971520
    preserve    = false
    target      = "Disk"
    drvtype     = "HDD"
    readonly    = false
  }

  interfaces {
    intfname             = "enp1s0"                                       # adapter the app expects
    intforder            = 1                                              # NIC enumeration order in guest
    directattach         = false                                         # virtio VIF on an NI bridge
    netinstname          = zedcloud_network_instance.tf_lan_switch_1.name # which NI to attach to
    access_vlan_id       = 0                                             # 0 = trunk on the Switch NI
    default_net_instance = false                                        # use the named NI, not default
    ipaddr               = ""                                           # DHCP-assigned
    macaddr              = var.vm1_macaddr                              # pinned MAC
    privateip            = false                                        # DHCP (not static-required)
  }

  logs { access = true }
}

UI mapping (Adapters & Networks step)

ZedControl field Terraform / API field Notes
Network Adapter Name intfname the app's declared interface (e.g. enp3s0)
Network Instance netinstname / netinstid the NI to bind (e.g. TF-CL250-NI-1)
Firewall Rules acls “Edge App Configured” = ACLs from the manifest
Kind / Port / Addressing (from the NI, read-only) e.g. Switch / eth0 / None
DHCP (from the NI) e.g. Default
IP Address ipaddr static /32 when the NI is reserved-DHCP
MAC Address macaddr empty = EVE auto-generates
Access VLAN Id [2-4093] access_vlan_id empty box == 0 == trunk; ≥2 = access port

An empty Access VLAN Id box is equivalent to access_vlan_id = 0 (trunk), identical in effect to the Terraform sample above.

Inspecting on a live EVE-KVM node

Via EdgeView / device debug shell:

# VIFs of running apps and their bridge membership
ip -br link show | grep nbu
bridge link show | grep nbu                 # nbu1x3 master bn1 (or the port bridge)
 
# Is the bridge VLAN-aware, and what VIDs are programmed?
bridge vlan show                            # access PVID per VIF, trunk VIDs on the uplink
 
# App network status as zedrouter sees it
cat /run/zedrouter/AppNetworkStatus/*.json | jq '{app:.DisplayName, vifs:.UnderlayNetworkList[]?|{name:.Name, vif:.Vif, bridge:.Bridge, mac:.Mac, vlan:.AccessVlanID, ip:.AllocatedIPv4Addr}}'

Source references