tailscale/net/tstun/tun.go
David Crawshaw 66efa10134 net/tstun: veth+AF_XDP WIP
Instead of using a tun device, use AF_XDP to read/write a veth device.

Works, but currently slower than tun. :(
2022-07-26 07:56:50 -07:00

105 lines
2.8 KiB
Go

// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !js
// +build !js
// Package tun creates a tuntap device, working around OS-specific
// quirks if necessary.
package tstun
import (
"errors"
"runtime"
"strings"
"time"
"golang.zx2c4.com/wireguard/tun"
"tailscale.com/envknob"
"tailscale.com/types/logger"
)
var tunMTU = DefaultMTU
func init() {
if mtu, ok := envknob.LookupInt("TS_DEBUG_MTU"); ok {
tunMTU = mtu
}
}
// createTAP is non-nil on Linux.
var createTAP func(tapName, bridgeName string) (tun.Device, error)
// createVETH is non-nil on Linux.
var createVETH func(tapName string) (tun.Device, error)
// New returns a tun.Device for the requested device name, along with
// the OS-dependent name that was allocated to the device.
func New(logf logger.Logf, tunName string) (tun.Device, string, error) {
var dev tun.Device
var err error
if strings.HasPrefix(tunName, "tap:") {
if runtime.GOOS != "linux" {
return nil, "", errors.New("tap only works on Linux")
}
f := strings.Split(tunName, ":")
var tapName, bridgeName string
switch len(f) {
case 2:
tapName = f[1]
case 3:
tapName, bridgeName = f[1], f[2]
default:
return nil, "", errors.New("bogus tap argument")
}
dev, err = createTAP(tapName, bridgeName)
} else if strings.HasPrefix(tunName, "veth:") {
if runtime.GOOS != "linux" {
return nil, "", errors.New("veth/xdp only works on Linux")
}
f := strings.Split(tunName, ":")
if len(f) != 2 {
return nil, "", errors.New("bogus veth argument")
}
dev, err = createVETH(f[1])
} else {
dev, err = tun.CreateTUN(tunName, tunMTU)
}
if err != nil {
return nil, "", err
}
if err := waitInterfaceUp(dev, 90*time.Second, logf); err != nil {
dev.Close()
return nil, "", err
}
if err := setLinkAttrs(dev); err != nil {
logf("setting link attributes: %v", err)
}
name, err := interfaceName(dev)
if err != nil {
dev.Close()
return nil, "", err
}
return dev, name, nil
}
// tunDiagnoseFailure, if non-nil, does OS-specific diagnostics of why
// TUN failed to work.
var tunDiagnoseFailure func(tunName string, logf logger.Logf, err error)
// Diagnose tries to explain a tuntap device creation failure.
// It pokes around the system and logs some diagnostic info that might
// help debug why tun creation failed. Because device creation has
// already failed and the program's about to end, log a lot.
//
// The tunName is the name of the tun device that was requested but failed.
// The err error is how the tun creation failed.
func Diagnose(logf logger.Logf, tunName string, err error) {
if tunDiagnoseFailure != nil {
tunDiagnoseFailure(tunName, logf, err)
} else {
logf("no TUN failure diagnostics for OS %q", runtime.GOOS)
}
}