A Linux virtual network interface is a network device whose packet input and output are supplied by software rather than by a dedicated hardware port. It still has the same Linux identity as a physical interface: an interface index, a name, link state, statistics, and, when the device type permits them, MAC and IP addresses. What changes between virtual-interface types is the object at the other end and whether they exchange Ethernet frames or IP packets.

Prerequisites

Linux Networking defines network namespaces, network devices, interface addresses, routes, and the rtnetlink API used by ip.

Choose by the other endpoint

Classify a virtual interface by the object that receives data transmitted through it. The following table identifies that endpoint and the unit passed across the boundary:

Interface typeOther endpointUnit transferredMain use
veth pairThe peer network interface, often in another network namespaceEthernet frameConnect two Linux network stacks
bridgeOne or more member interfaces plus the host’s own attachmentEthernet frameJoin interfaces into one Layer-2 segment
dummyNo peer or forwarding engineNo useful external transmission pathHold host-side addresses and interface-scoped state
TUNA file descriptor owned by a userspace processIP packetUserspace routing and VPN software
TAPA file descriptor owned by a userspace processEthernet frameVirtual machines and userspace Ethernet processing

All five appear as network devices, but they are related rather than interchangeable. A veth is a two-ended cable, a bridge is a forwarding object with member ports, and TUN/TAP hands packets or frames to a process.

veth pairs connect network namespaces

A veth pair is two connected virtual Ethernet interfaces. Linux always creates both endpoints together. A frame transmitted on one endpoint is received on the other; if either endpoint is down, the pair’s link state is down.

This example creates a namespace named red, then creates veth-host in the initial namespace and its peer eth0 directly inside red:

sudo ip netns add red
sudo ip link add veth-host type veth peer name eth0 netns red
 
sudo ip link set dev veth-host up
sudo ip -n red link set dev lo up
sudo ip -n red link set dev eth0 up

veth-host and eth0 are separate network devices with separate interface indices. The peer relation carries frames between them; it does not merge the two namespaces’ addresses or routes. A process in red sees eth0 and lo, while a process in the initial namespace sees veth-host.

Linux bridges join Ethernet interfaces

A Linux bridge is a kernel implementation of an Ethernet bridge, the Layer-2 device defined by IEEE 802.1Q. It learns which source MAC addresses arrive on each member port and records them in a forwarding database (FDB). For a unicast frame whose destination MAC is in the FDB, the bridge transmits the frame through the recorded port. Unknown unicast, broadcast, and relevant multicast traffic is flooded to the eligible ports.

Attach a veth endpoint to a bridge

The diagram shows the two different objects in a container-style topology. The veth pair carries a frame across the namespace boundary; cni0 chooses which bridge port or host attachment receives that frame.

The following commands add a bridge and make the existing veth-host interface one of its member ports:

sudo ip link add name cni0 type bridge
sudo ip link set dev veth-host master cni0
sudo ip link set dev cni0 up

dev veth-host selects the interface being changed. master cni0 stores its membership in the bridge. The operation does not turn the veth into a bridge: frames still cross the veth pair first and are then submitted to the bridge through the host-side member port.

The bridge device is also the host attachment

Linux exposes cni0 itself as a network interface as well as maintaining its member-port set and FDB. Assigning an address to cni0 attaches the host IP stack to that bridged Ethernet segment:

sudo ip address add 192.0.2.1/24 dev cni0
sudo ip -n red address add 192.0.2.2/24 dev eth0

For a connection from 192.0.2.2 to 192.0.2.1, the namespace emits an Ethernet frame through eth0; the peer veth-host receives it and submits it to the bridge; the destination MAC identifies the bridge’s host attachment; the host IP stack then performs local IP and socket delivery. For a destination behind another member port, the FDB selects that port instead.

The address on cni0 does not make the bridge an IP router. Bridging chooses an output port from Ethernet state. Routing is a later host-IP operation used when the host accepts a frame addressed to itself and must forward the enclosed IP packet to another network; that requires appropriate routes and IP forwarding to be enabled.

Dummy interfaces hold host-side state without a peer

A dummy interface is a network device with no peer, member ports, hardware queue, or userspace file descriptor. It can own interface addresses and interface-scoped configuration, but it does not connect those addresses to an Ethernet segment or another namespace.

sudo ip link add name service0 type dummy
sudo ip address add 192.0.2.10/32 dev service0
sudo ip link set dev service0 up

This is the smaller device type when the requirement is only a host-owned address with a lifetime independent of a physical NIC. An empty bridge can also own an address, but with no member ports its FDB has nothing to forward. Choose a bridge when Ethernet-like ports may join the segment; choose dummy when no Layer-2 segment exists.

TAP and TUN interfaces

TUN/TAP is a Linux driver that connects a kernel network interface to file descriptors opened by a userspace process. TUN and TAP share the same creation API but expose different units to the process:

DeviceKernel presentsUserspace reads and writesCan be a bridge port
TUNA Layer-3 point-to-point-style interfaceIP packetsNo
TAPAn Ethernet interface with a MAC addressEthernet framesYes

Create the interface through /dev/net/tun

The caller opens the TUN/TAP character device and uses TUNSETIFF to create or attach to a network interface. This abridged function creates vpn0; its caller owns the returned descriptor and must keep reading and writing it:

#include <fcntl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
 
int open_tun(void) {
    int fd = open("/dev/net/tun", O_RDWR);
    struct ifreq ifr = {0};
 
    ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
    strncpy(ifr.ifr_name, "vpn0", IFNAMSIZ - 1);
    ioctl(fd, TUNSETIFF, &ifr);
    return fd;
}

IFF_TUN selects IP packets; replacing it with IFF_TAP selects Ethernet frames. IFF_NO_PI removes the driver’s four-byte packet-information prefix, so each read or write buffer begins with the IP or Ethernet header described in the table. Production code must check failures from open and ioctl. Creating or attaching the interface requires CAP_NET_ADMIN unless ownership and persistence have been configured by a privileged process.

The descriptor directions are defined from the userspace process’s point of view:

Process operationKernel interpretationNext step
read(fd, buffer, size)Take a packet or frame that Linux transmitted through the TUN/TAP interfaceThe process tunnels, emulates, filters, or otherwise handles it
write(fd, buffer, size)Inject a packet or frame as input received on the TUN/TAP interfaceLinux performs ingress processing, routing, bridging, or local delivery

By default, closing the last descriptor removes the interface and its routes. TUNSETPERSIST changes that lifetime so the interface remains without an open descriptor; another privileged operation must then remove it.

TUN in a userspace VPN

The upper row follows a plaintext IP packet selected by a route through tun0. The lower row follows the reverse direction after the VPN process receives and decrypts an encrypted transport packet.

On outbound traffic, Linux queues the IP packet on tun0; the VPN process reads it, encrypts it, and sends the ciphertext through a separate TCP or UDP socket. On inbound traffic, the process receives ciphertext through that transport socket, decrypts it, and writes the recovered IP packet to the TUN descriptor. Linux then treats it as input received on tun0. The TUN packet and the encrypted transport packet are different buffers at different layers.

TAP in a virtual machine

The virtual NIC presented to a guest and the backend used to enter the host network are separate parts of a virtual-machine network path. The frontend may look like virtio-net or an emulated Ethernet card to the guest. After the guest driver submits a frame to that frontend, QEMU must pass the frame to a host backend.

A TAP backend gives QEMU a file descriptor whose other endpoint is one host Ethernet interface, such as tap0. The two directions have complementary meanings:

DirectionQEMU operationLinux operation
Guest to hostQEMU obtains an Ethernet frame from the virtual NIC and calls write(tap_fd, frame, size)The TAP driver submits the frame as input received on tap0; a bridge can then forward it from that member port
Host to guestLinux transmits a frame through tap0 and queues it on the TAP descriptorQEMU calls read(tap_fd, frame, size) and presents the frame as input received by the guest’s virtual NIC

TAP is a direct fit because the descriptor is a dedicated Ethernet-frame queue. The driver also supports multiple queues, while QEMU can combine TAP with vnet_hdr metadata for checksum and segmentation offload. QEMU can also use vhost, which moves much of the virtio packet-processing path from QEMU into the host kernel.

A veth backend requires a packet-socket adapter

TAP is not the only possible host backend. An emulator could bind an AF_PACKET socket—a Linux socket that sends and receives raw Layer-2 frames—to veth-qemu, one endpoint of a veth pair. Its peer, veth-bridge, would be the bridge member port.

For guest-to-host traffic, the emulator sends the frame through the packet socket on veth-qemu. That is transmission on veth-qemu, so the veth driver delivers it as input on its peer, veth-bridge; the bridge sees the frame arrive through the veth-bridge member port. In the reverse direction, a frame transmitted by the bridge through veth-bridge arrives as input on veth-qemu, where the packet socket can deliver it to the emulator.

This design adds a second network device and a general-purpose packet socket. Packet sockets can observe traffic also processed by the host network stack and can receive copies of locally generated outgoing frames, so the emulator must isolate the endpoint and distinguish the traffic it owns. TAP instead defines one network device whose frame queue terminates directly at the emulator’s file descriptor. This API shape, together with multiqueue and vhost integration, explains why TAP is QEMU’s standard Linux Ethernet backend; it is not a kernel restriction that prevents an emulator from using veth. QEMU also supports other backends, including AF_XDP, a Linux API for userspace packet I/O through queues attached to a network interface.

Why containers normally use veth instead of TUN or TAP

A container and its host share one Linux kernel, even when their processes occupy different network namespaces. A veth pair can therefore transfer frames between their two kernel network stacks directly. No userspace process is needed in the middle.

A virtual machine has a separate guest kernel. Its emulator must therefore join the guest-facing virtual NIC to some host-side backend: TAP is the direct Linux backend, while a packet-socket design can adapt a host interface such as veth. A userspace VPN uses TUN when its process needs to read, encrypt, transport, and reinject IP packets. The endpoints that must exchange packets, and whether one endpoint is a userspace process, determine the interface and API.

Sources

See also

  • Linux Networking for the network-device, address, route, and rtnetlink model shared by physical and virtual interfaces.
  • Linux Namespaces for creation, membership, and lifetime of the isolation boundary that veth pairs commonly connect.
  • QEMU and Virtio for the guest side of the TAP frame handoff.