slackhq/nebula · error

unable to discover link_addr for tun interface

Error message

unable to discover link_addr for tun interface

What it means

Activate() looks up the link-layer address (MAC/link_addr) of the tun interface by device name before assigning IPs. If getLinkAddr succeeds but returns no entry, the interface does not exist in the system interface list, and this error is returned. It is not wrapped because the plain-text cause is the whole story: no link_addr could be discovered for t.Device.

Source

Thrown at overlay/tun_freebsd.go:486

		return nil
	}

	return fmt.Errorf("unknown address type %v", cidr)
}

func (t *tun) Activate() error {
	// Setup our default MTU
	err := t.setMTU()
	if err != nil {
		return err
	}

	linkAddr, err := getLinkAddr(t.Device)
	if err != nil {
		return err
	}
	if linkAddr == nil {
		return fmt.Errorf("unable to discover link_addr for tun interface")
	}
	t.linkAddr = linkAddr

	for i := range t.vpnNetworks {
		err := t.addIp(t.vpnNetworks[i])
		if err != nil {
			return err
		}
	}

	return t.addRoutes(false)
}

func (t *tun) setMTU() error {
	// Set the MTU on the device
	s, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
	if err != nil {
		return err

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Verify the interface exists: run `ifconfig` and match the configured device name exactly
  2. Don't hardcode the tun name in config; let the library open the next free device and use its reported Device
  3. Check jail/vnet confinement — the interface may exist on the host but not in the jail's network stack
  4. Re-run device creation if the interface was torn down; ensure Activate is called right after newTun

Example fix

// before
# config
tun: tun9   # device may not exist
// after
# omit explicit device name or verify with:
_, err := net.InterfaceByName("tun9")
if err != nil { /* recreate device or clear config */ }
Defensive patterns

Strategy: validation

Validate before calling

if _, err := net.InterfaceByName(deviceName); err != nil {
    return fmt.Errorf("tun device %q does not exist before Activate: %w", deviceName, err)
}

Try / catch

if err := dev.Activate(); err != nil {
    if strings.Contains(err.Error(), "unable to discover link_addr") {
        return fmt.Errorf("tun interface missing (name mismatch or destroyed): %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: getLinkAddr(t.Device) returns (nil, nil) — the interface name configured for the tun (e.g. from config 'dev' / 'tun') does not correspond to any existing interface at the time Activate runs.

Common situations: Config points at a device name that was never created (e.g. 'tun0' when the kernel allocated 'tun1'); the device was destroyed between open and Activate; running in a jail/vnet without the tun interface visible; name mismatch after OS upgrade.

Related errors


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