slackhq/nebula · error

failed to bring the tun device up: %s

Error message

failed to bring the tun device up: %s

What it means

Raised in tun.Activate when the SIOCSIFFLAGS ioctl that sets IFF_UP on the tun interface fails. The device exists and its flags were read successfully, but the kernel refused to bring the interface administratively up.

Source

Thrown at overlay/tun_linux.go:490

	ifrq := ifreqQLEN{Name: devName, Value: int32(t.TXQueueLen)}
	if err = ioctl(t.ioctlFd, unix.SIOCSIFTXQLEN, uintptr(unsafe.Pointer(&ifrq))); err != nil {
		// If we can't set the queue length nebula will still work but it may lead to packet loss
		t.l.Error("Failed to set tun tx queue length", "error", err)
	}

	const modeNone = 1
	if err = netlink.LinkSetIP6AddrGenMode(link, modeNone); err != nil {
		t.l.Warn("Failed to disable link local address generation", "error", err)
	}

	if err = t.addIPs(link); err != nil {
		return err
	}

	// Bring up the interface
	ifrf.Flags = ifrf.Flags | unix.IFF_UP
	if err = ioctl(t.ioctlFd, unix.SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifrf))); err != nil {
		return fmt.Errorf("failed to bring the tun device up: %s", err)
	}

	//set route MTU
	for i := range t.vpnNetworks {
		if err = t.setDefaultRoute(t.vpnNetworks[i]); err != nil {
			return fmt.Errorf("failed to set default route MTU: %w", err)
		}
	}

	// Set the routes
	if err = t.addRoutes(false); err != nil {
		return err
	}

	// Run the interface
	ifrf.Flags = ifrf.Flags | unix.IFF_UP | unix.IFF_RUNNING
	if err = ioctl(t.ioctlFd, unix.SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifrf))); err != nil {
		return fmt.Errorf("failed to run tun device: %s", err)

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Run with sufficient privileges (root or CAP_NET_ADMIN) so interface flags can be changed.
  2. Check the %s errno: EPERM = permissions, ENODEV = interface gone.
  3. Ensure the device isn't being torn down concurrently (unmanaged in NetworkManager/systemd-networkd).
  4. Manually verify with `ip link set <dev> up` to confirm it's a privilege vs device issue.

Example fix

// before
$ ./nebula -config config.yml  # EPERM
// after
$ sudo setcap cap_net_admin=ep ./nebula
$ ./nebula -config config.yml
Defensive patterns

Strategy: validation

Validate before calling

// require privileges before attempting to bring the interface up
if os.Geteuid() != 0 && !hasCapNetAdmin() {
    return errors.New("bringing tun up requires root or CAP_NET_ADMIN")
}

Try / catch

if err := t.Activate(netstack); err != nil {
    if strings.Contains(err.Error(), "failed to bring the tun device up") {
        if errors.Is(err, os.ErrPermission) || strings.Contains(err.Error(), "operation not permitted") {
            log.Error("grant CAP_NET_ADMIN: setcap cap_net_admin=ep <binary>")
        }
    }
}

Prevention

When it happens

Trigger: Activate() calls ioctl(t.ioctlFd, SIOCSIFFLAGS, ...) with Flags|IFF_UP and the kernel returns an error — typically EPERM from missing privileges or ENODEV if the link vanished.

Common situations: Running nebula without root/CAP_NET_ADMIN; interface removed concurrently by a network manager; containers where SIOCSIFFLAGS on the host-owned device is denied.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/dfb26e48fe7c2092. Report an issue: GitHub.