mirror of
https://github.com/qdm12/gluetun.git
synced 2026-08-05 03:43:24 +02:00
feat(wireguard): WIREGUARD_GSO option to disable TUN vnet hdr batching (#3424)
This commit is contained in:
@@ -112,6 +112,7 @@ ENV VPN_SERVICE_PROVIDER=pia \
|
||||
WIREGUARD_ADDRESSES_SECRETFILE=/run/secrets/wireguard_addresses \
|
||||
WIREGUARD_MTU= \
|
||||
WIREGUARD_IMPLEMENTATION=auto \
|
||||
WIREGUARD_GSO=on \
|
||||
# Amnezia
|
||||
AMNEZIAWG_ENDPOINT_IP= \
|
||||
AMNEZIAWG_ENDPOINT_PORT= \
|
||||
|
||||
@@ -62,6 +62,7 @@ func Test_New(t *testing.T) {
|
||||
MTU: device.DefaultMTU,
|
||||
IPv6: ptrTo(false),
|
||||
Implementation: "auto",
|
||||
GSO: ptrTo(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -6,6 +6,7 @@ type Logger interface {
|
||||
Debug(s string)
|
||||
Debugf(format string, args ...interface{})
|
||||
Info(s string)
|
||||
Warn(s string)
|
||||
Error(s string)
|
||||
Errorf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
@@ -108,3 +108,15 @@ func (mr *MockLoggerMockRecorder) Info(s any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockLogger)(nil).Info), s)
|
||||
}
|
||||
|
||||
// Warn mocks base method.
|
||||
func (m *MockLogger) Warn(s string) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Warn", s)
|
||||
}
|
||||
|
||||
// Warn indicates an expected call of Warn.
|
||||
func (mr *MockLoggerMockRecorder) Warn(s any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockLogger)(nil).Warn), s)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package amneziawg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
amneziatun "github.com/amnezia-vpn/amneziawg-go/tun"
|
||||
"github.com/qdm12/gluetun/internal/wireguard"
|
||||
)
|
||||
|
||||
// createTUN creates a TUN device. When gso is false, IFF_VNET_HDR is
|
||||
// omitted so amneziawg-go's initFromFlags sees no vnet header support and
|
||||
// keeps tun.vnetHdr=false, falling back to simple single-packet writes instead
|
||||
// of the GRO/GSO batch path that causes EINVAL on some vendor kernels.
|
||||
func createTUN(name string, mtu int, gso bool) (amneziatun.Device, error) { //nolint:ireturn
|
||||
if gso {
|
||||
return amneziatun.CreateTUN(name, mtu)
|
||||
}
|
||||
tunFile, err := wireguard.OpenTUNFile(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating tun fd file: %w", err)
|
||||
}
|
||||
tunDevice, err := amneziatun.CreateTUNFromFile(tunFile, mtu)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating TUN device from file: %w", err)
|
||||
}
|
||||
return tunDevice, nil
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
//go:build !linux
|
||||
|
||||
package amneziawg
|
||||
|
||||
import (
|
||||
amneziatun "github.com/amnezia-vpn/amneziawg-go/tun"
|
||||
)
|
||||
|
||||
func createTUN(name string, mtu int, _ bool) (amneziatun.Device, error) { //nolint:ireturn
|
||||
return amneziatun.CreateTUN(name, mtu)
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
amneziaconn "github.com/amnezia-vpn/amneziawg-go/conn"
|
||||
amneziadevice "github.com/amnezia-vpn/amneziawg-go/device"
|
||||
amneziatun "github.com/amnezia-vpn/amneziawg-go/tun"
|
||||
"github.com/qdm12/gluetun/internal/cleanup"
|
||||
"github.com/qdm12/gluetun/internal/wireguard"
|
||||
)
|
||||
@@ -36,7 +35,7 @@ func setupUserspace(ctx context.Context,
|
||||
) (
|
||||
linkIndex uint32, waitAndCleanup func() error, err error,
|
||||
) {
|
||||
tun, err := amneziatun.CreateTUN(interfaceName, int(mtu))
|
||||
tun, err := createTUN(interfaceName, int(mtu), *settings.Wireguard.GSO)
|
||||
if err != nil {
|
||||
return 0, nil, fmt.Errorf("creating TUN device: %w", err)
|
||||
}
|
||||
|
||||
@@ -46,6 +46,13 @@ type Wireguard struct {
|
||||
// It defaults to "auto" and cannot be the empty string
|
||||
// in the internal state.
|
||||
Implementation string `json:"implementation"`
|
||||
// GSO enables wireguard-go's GRO/GSO batched TUN I/O by creating
|
||||
// the WireGuard TUN device with IFF_VNET_HDR. It should be disabled
|
||||
// on kernels (e.g. certain NAS devices) that claim IFF_VNET_HDR
|
||||
// support but return EINVAL when wireguard-go writes GRO-coalesced
|
||||
// packets with virtio_net_hdr structs under load.
|
||||
// It defaults to true and cannot be nil in the internal state.
|
||||
GSO *bool `json:"gso"`
|
||||
}
|
||||
|
||||
var regexpInterfaceName = regexp.MustCompile(`^[a-zA-Z0-9_]+$`)
|
||||
@@ -136,6 +143,7 @@ func (w *Wireguard) copy() (copied Wireguard) {
|
||||
Interface: w.Interface,
|
||||
MTU: w.MTU,
|
||||
Implementation: w.Implementation,
|
||||
GSO: gosettings.CopyPointer(w.GSO),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +157,7 @@ func (w *Wireguard) overrideWith(other Wireguard) {
|
||||
w.Interface = gosettings.OverrideWithComparable(w.Interface, other.Interface)
|
||||
w.MTU = gosettings.OverrideWithComparable(w.MTU, other.MTU)
|
||||
w.Implementation = gosettings.OverrideWithComparable(w.Implementation, other.Implementation)
|
||||
w.GSO = gosettings.OverrideWithPointer(w.GSO, other.GSO)
|
||||
}
|
||||
|
||||
func (w *Wireguard) setDefaults(vpnProvider string) {
|
||||
@@ -173,6 +182,7 @@ func (w *Wireguard) setDefaults(vpnProvider string) {
|
||||
w.Interface = gosettings.DefaultComparable(w.Interface, "wg0")
|
||||
w.MTU = gosettings.DefaultPointer(w.MTU, 0)
|
||||
w.Implementation = gosettings.DefaultComparable(w.Implementation, "auto")
|
||||
w.GSO = gosettings.DefaultPointer(w.GSO, true)
|
||||
}
|
||||
|
||||
func (w Wireguard) String() string {
|
||||
@@ -217,6 +227,10 @@ func (w Wireguard) toLinesNode() (node *gotree.Node) {
|
||||
node.Appendf("Implementation: %s", w.Implementation)
|
||||
}
|
||||
|
||||
if !*w.GSO {
|
||||
node.Append("GSO disabled")
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
@@ -265,5 +279,11 @@ func (w *Wireguard) read(r *reader.Reader, amneziaWG bool) (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.GSO, err = r.BoolPtr("WIREGUARD_GSO")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -89,6 +89,8 @@ func buildWireguardSettings(connection models.Connection,
|
||||
}
|
||||
|
||||
settings.PersistentKeepaliveInterval = *userSettings.PersistentKeepaliveInterval
|
||||
gso := *userSettings.GSO
|
||||
settings.GSO = &gso
|
||||
|
||||
return settings
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ func Test_buildWireguardSettings(t *testing.T) {
|
||||
PersistentKeepaliveInterval: ptrTo(time.Hour),
|
||||
Interface: "wg1",
|
||||
MTU: ptrTo(uint32(1000)),
|
||||
GSO: ptrTo(true),
|
||||
},
|
||||
ipv6Supported: false,
|
||||
settings: wireguard.Settings{
|
||||
@@ -58,6 +59,35 @@ func Test_buildWireguardSettings(t *testing.T) {
|
||||
RulePriority: 101,
|
||||
IPv6: ptrTo(false),
|
||||
MTU: 1000,
|
||||
GSO: ptrTo(true),
|
||||
},
|
||||
},
|
||||
"gso_disabled": {
|
||||
connection: models.Connection{
|
||||
IP: netip.AddrFrom4([4]byte{5, 6, 7, 8}),
|
||||
Port: 58820,
|
||||
PubKey: "public",
|
||||
},
|
||||
userSettings: settings.Wireguard{
|
||||
PrivateKey: ptrTo("private"),
|
||||
PreSharedKey: ptrTo(""),
|
||||
PersistentKeepaliveInterval: ptrTo(time.Duration(0)),
|
||||
Interface: "wg0",
|
||||
MTU: ptrTo(uint32(0)),
|
||||
GSO: ptrTo(false),
|
||||
},
|
||||
ipv6Supported: false,
|
||||
settings: wireguard.Settings{
|
||||
InterfaceName: "wg0",
|
||||
PrivateKey: "private",
|
||||
PublicKey: "public",
|
||||
Endpoint: netip.AddrPortFrom(netip.AddrFrom4([4]byte{5, 6, 7, 8}), 58820),
|
||||
Addresses: []netip.Prefix{},
|
||||
AllowedIPs: []netip.Prefix{},
|
||||
RulePriority: 101,
|
||||
IPv6: ptrTo(false),
|
||||
MTU: 1320,
|
||||
GSO: ptrTo(false),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ func Test_New(t *testing.T) {
|
||||
MTU: device.DefaultMTU,
|
||||
IPv6: ptr(false),
|
||||
Implementation: "auto",
|
||||
GSO: ptr(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.zx2c4.com/wireguard/device"
|
||||
)
|
||||
|
||||
@@ -10,6 +14,7 @@ type Logger interface {
|
||||
Debug(s string)
|
||||
Debugf(format string, args ...interface{})
|
||||
Info(s string)
|
||||
Warn(s string)
|
||||
Error(s string)
|
||||
Erroer
|
||||
}
|
||||
@@ -18,9 +23,28 @@ type Erroer interface {
|
||||
Errorf(format string, args ...any)
|
||||
}
|
||||
|
||||
func makeDeviceLogger(logger Logger) (deviceLogger *device.Logger) {
|
||||
func makeDeviceLogger(logger Logger, gso bool) (deviceLogger *device.Logger) {
|
||||
errorf := logger.Errorf
|
||||
if gso {
|
||||
// Kernels advertising IFF_VNET_HDR support but rejecting
|
||||
// GRO-coalesced writes make wireguard-go log this error for
|
||||
// each failed write batch, see
|
||||
// https://github.com/tailscale/tailscale/issues/13041
|
||||
var suggestOnce sync.Once
|
||||
errorf = func(format string, args ...any) {
|
||||
logger.Errorf(format, args...)
|
||||
message := fmt.Sprintf(format, args...)
|
||||
if strings.Contains(message, "Failed to write packets to TUN device") &&
|
||||
strings.Contains(message, "invalid argument") {
|
||||
suggestOnce.Do(func() {
|
||||
logger.Warn("The kernel seems to reject GRO-coalesced writes to " +
|
||||
"the TUN device; consider setting WIREGUARD_GSO=off")
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return &device.Logger{
|
||||
Verbosef: logger.Debugf,
|
||||
Errorf: logger.Errorf,
|
||||
Errorf: errorf,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,3 +108,15 @@ func (mr *MockLoggerMockRecorder) Info(s any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockLogger)(nil).Info), s)
|
||||
}
|
||||
|
||||
// Warn mocks base method.
|
||||
func (m *MockLogger) Warn(s string) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Warn", s)
|
||||
}
|
||||
|
||||
// Warn indicates an expected call of Warn.
|
||||
func (mr *MockLoggerMockRecorder) Warn(s any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockLogger)(nil).Warn), s)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"go.uber.org/mock/gomock"
|
||||
@@ -13,7 +14,7 @@ func Test_makeDeviceLogger(t *testing.T) {
|
||||
|
||||
logger := NewMockLogger(ctrl)
|
||||
|
||||
deviceLogger := makeDeviceLogger(logger)
|
||||
deviceLogger := makeDeviceLogger(logger, false)
|
||||
|
||||
logger.EXPECT().Debugf("test %d", 1)
|
||||
deviceLogger.Verbosef("test %d", 1)
|
||||
@@ -21,3 +22,23 @@ func Test_makeDeviceLogger(t *testing.T) {
|
||||
logger.EXPECT().Errorf("test %d", 2)
|
||||
deviceLogger.Errorf("test %d", 2)
|
||||
}
|
||||
|
||||
func Test_makeDeviceLogger_gso_suggestion(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
logger := NewMockLogger(ctrl)
|
||||
|
||||
deviceLogger := makeDeviceLogger(logger, true)
|
||||
|
||||
const format = "Failed to write packets to TUN device: %v"
|
||||
writeError := errors.New("write /dev/net/tun: invalid argument")
|
||||
logger.EXPECT().Errorf(format, writeError).Times(2)
|
||||
logger.EXPECT().Warn("The kernel seems to reject GRO-coalesced writes to " +
|
||||
"the TUN device; consider setting WIREGUARD_GSO=off").Times(1)
|
||||
|
||||
deviceLogger.Errorf(format, writeError)
|
||||
// The suggestion is only logged once for repeated errors.
|
||||
deviceLogger.Errorf(format, writeError)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ type noopDebugLogger struct{}
|
||||
func (n noopDebugLogger) Debug(_ string) {}
|
||||
func (n noopDebugLogger) Debugf(_ string, _ ...any) {}
|
||||
func (n noopDebugLogger) Info(_ string) {}
|
||||
func (n noopDebugLogger) Warn(_ string) {}
|
||||
func (n noopDebugLogger) Error(_ string) {}
|
||||
func (n noopDebugLogger) Errorf(_ string, _ ...any) {}
|
||||
func (n noopDebugLogger) Patch(_ ...log.Option) {}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
)
|
||||
|
||||
// createTUN creates a TUN device. When gso is false, IFF_VNET_HDR is
|
||||
// omitted so wireguard-go's initFromFlags sees no vnet header support and
|
||||
// keeps tun.vnetHdr=false, falling back to simple single-packet writes instead
|
||||
// of the GRO/GSO batch path that causes EINVAL on some vendor kernels.
|
||||
func createTUN(name string, mtu int, gso bool) (tun.Device, error) { //nolint:ireturn
|
||||
if gso {
|
||||
return tun.CreateTUN(name, mtu)
|
||||
}
|
||||
tunFile, err := OpenTUNFile(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating tun fd file: %w", err)
|
||||
}
|
||||
tunDevice, err := tun.CreateTUNFromFile(tunFile, mtu)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating TUN device from file: %w", err)
|
||||
}
|
||||
return tunDevice, nil
|
||||
}
|
||||
|
||||
// OpenTUNFile opens /dev/net/tun with IFF_TUN|IFF_NO_PI but without
|
||||
// IFF_VNET_HDR. It is exported so that the amneziawg package can use the same
|
||||
// file with amneziatun.CreateTUNFromFile.
|
||||
func OpenTUNFile(name string) (*os.File, error) {
|
||||
tunFD, err := unix.Open("/dev/net/tun", unix.O_RDWR|unix.O_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening /dev/net/tun: %w", err)
|
||||
}
|
||||
ifr, err := unix.NewIfreq(name)
|
||||
if err != nil {
|
||||
unix.Close(tunFD)
|
||||
return nil, fmt.Errorf("creating ifreq: %w", err)
|
||||
}
|
||||
ifr.SetUint16(unix.IFF_TUN | unix.IFF_NO_PI) // intentionally omit IFF_VNET_HDR
|
||||
if err := unix.IoctlIfreq(tunFD, unix.TUNSETIFF, ifr); err != nil {
|
||||
unix.Close(tunFD)
|
||||
return nil, fmt.Errorf("setting TUN flags: %w", err)
|
||||
}
|
||||
if err := unix.SetNonblock(tunFD, true); err != nil {
|
||||
unix.Close(tunFD)
|
||||
return nil, fmt.Errorf("setting nonblock: %w", err)
|
||||
}
|
||||
return os.NewFile(uintptr(tunFD), "/dev/net/tun"), nil
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//go:build !linux
|
||||
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
)
|
||||
|
||||
func createTUN(name string, mtu int, _ bool) (tun.Device, error) { //nolint:ireturn
|
||||
return tun.CreateTUN(name, mtu)
|
||||
}
|
||||
|
||||
func OpenTUNFile(_ string) (*os.File, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
gtun "github.com/qdm12/gluetun/internal/tun"
|
||||
"golang.zx2c4.com/wireguard/conn"
|
||||
"golang.zx2c4.com/wireguard/device"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
)
|
||||
|
||||
@@ -62,7 +61,8 @@ func (w *Wireguard) Run(ctx context.Context, waitError chan<- error, ready chan<
|
||||
linkIndex uint32, waitAndCleanup func() error, err error,
|
||||
) {
|
||||
return setupFunction(ctx,
|
||||
w.settings.InterfaceName, w.netlink, w.settings.MTU, cleanups, w.logger)
|
||||
w.settings.InterfaceName, w.netlink, w.settings.MTU,
|
||||
*w.settings.GSO, cleanups, w.logger)
|
||||
}
|
||||
|
||||
Run(ctx, waitError, ready, setup, w.settings, w.netlink, w.logger)
|
||||
@@ -147,7 +147,7 @@ func Run(ctx context.Context, waitError chan<- error, ready chan<- struct{},
|
||||
|
||||
func setupKernelSpace(ctx context.Context,
|
||||
interfaceName string, netLinker NetLinker, mtu uint32,
|
||||
cleanups *cleanup.Cleanups, logger Logger) (
|
||||
_ bool, cleanups *cleanup.Cleanups, logger Logger) (
|
||||
linkIndex uint32, waitAndCleanup func() error, err error,
|
||||
) {
|
||||
links, err := netLinker.LinkList()
|
||||
@@ -191,10 +191,10 @@ func setupKernelSpace(ctx context.Context,
|
||||
|
||||
func setupUserSpace(ctx context.Context,
|
||||
interfaceName string, netLinker NetLinker, mtu uint32,
|
||||
cleanups *cleanup.Cleanups, logger Logger) (
|
||||
gso bool, cleanups *cleanup.Cleanups, logger Logger) (
|
||||
linkIndex uint32, waitAndCleanup func() error, err error,
|
||||
) {
|
||||
tun, err := tun.CreateTUN(interfaceName, int(mtu))
|
||||
tun, err := createTUN(interfaceName, int(mtu), gso)
|
||||
if err != nil {
|
||||
return 0, nil, fmt.Errorf("creating TUN device: %w", err)
|
||||
}
|
||||
@@ -220,7 +220,7 @@ func setupUserSpace(ctx context.Context,
|
||||
|
||||
cleanups.Add("closing bind", 7, bind.Close)
|
||||
|
||||
deviceLogger := makeDeviceLogger(logger)
|
||||
deviceLogger := makeDeviceLogger(logger, gso)
|
||||
device := device.NewDevice(tun, bind, deviceLogger)
|
||||
|
||||
cleanups.Add("closing Wireguard device", 6, func() error {
|
||||
|
||||
@@ -48,6 +48,13 @@ type Settings struct {
|
||||
// Implementation is the implementation to use.
|
||||
// It can be auto, kernelspace or userspace, and defaults to auto.
|
||||
Implementation string
|
||||
// GSO enables wireguard-go's GRO/GSO batch I/O path by creating
|
||||
// the TUN device with IFF_VNET_HDR. When set to false, the TUN
|
||||
// device is created without IFF_VNET_HDR so that wireguard-go
|
||||
// falls back to single-packet reads and writes.
|
||||
// It defaults to true and cannot be nil in the internal state.
|
||||
// See WIREGUARD_GSO for details.
|
||||
GSO *bool
|
||||
}
|
||||
|
||||
func (s *Settings) SetDefaults() {
|
||||
@@ -86,6 +93,11 @@ func (s *Settings) SetDefaults() {
|
||||
const defaultImplementation = "auto"
|
||||
s.Implementation = defaultImplementation
|
||||
}
|
||||
|
||||
if s.GSO == nil {
|
||||
gso := true
|
||||
s.GSO = &gso
|
||||
}
|
||||
}
|
||||
|
||||
var interfaceNameRegexp = regexp.MustCompile(`^[a-zA-Z0-9_]+$`)
|
||||
|
||||
@@ -25,6 +25,7 @@ func Test_Settings_SetDefaults(t *testing.T) {
|
||||
MTU: device.DefaultMTU,
|
||||
IPv6: ptr(false),
|
||||
Implementation: "auto",
|
||||
GSO: ptr(true),
|
||||
},
|
||||
},
|
||||
"default endpoint port": {
|
||||
@@ -39,6 +40,7 @@ func Test_Settings_SetDefaults(t *testing.T) {
|
||||
MTU: device.DefaultMTU,
|
||||
IPv6: ptr(false),
|
||||
Implementation: "auto",
|
||||
GSO: ptr(true),
|
||||
},
|
||||
},
|
||||
"not empty settings": {
|
||||
@@ -50,6 +52,7 @@ func Test_Settings_SetDefaults(t *testing.T) {
|
||||
MTU: device.DefaultMTU,
|
||||
IPv6: ptr(true),
|
||||
Implementation: "userspace",
|
||||
GSO: ptr(false),
|
||||
},
|
||||
expected: Settings{
|
||||
InterfaceName: "wg1",
|
||||
@@ -59,6 +62,7 @@ func Test_Settings_SetDefaults(t *testing.T) {
|
||||
MTU: device.DefaultMTU,
|
||||
IPv6: ptr(true),
|
||||
Implementation: "userspace",
|
||||
GSO: ptr(false),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user