mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
wgcfg: Switch to using mem.RO
As Brad suggested, mem.RO allows for a lot of easy perf gains. There were also some smaller changes outside of mem.RO, such as using hex.Decode instead of hex.DecodeString. ``` name old time/op new time/op delta FromUAPI-8 14.7µs ± 3% 12.3µs ± 4% -16.58% (p=0.008 n=5+5) name old alloc/op new alloc/op delta FromUAPI-8 9.52kB ± 0% 7.04kB ± 0% -26.05% (p=0.008 n=5+5) name old allocs/op new allocs/op delta FromUAPI-8 77.0 ± 0% 29.0 ± 0% -62.34% (p=0.008 n=5+5) ``` Signed-off-by: julianknodt <julianknodt@gmail.com>
This commit is contained in:
parent
d349a3231e
commit
fb06ad19e7
@ -14,6 +14,7 @@
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"go4.org/mem"
|
||||||
"inet.af/netaddr"
|
"inet.af/netaddr"
|
||||||
"tailscale.com/types/wgkey"
|
"tailscale.com/types/wgkey"
|
||||||
)
|
)
|
||||||
@ -56,25 +57,14 @@ func parseEndpoint(s string) (host string, port uint16, err error) {
|
|||||||
return host, uint16(uport), nil
|
return host, uint16(uport), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseKeyHex(s string) (*wgkey.Key, error) {
|
// memROCut separates a mem.RO at the separator if it exists, otherwise
|
||||||
k, err := hex.DecodeString(s)
|
// it returns two empty ROs and reports that it was not found.
|
||||||
if err != nil {
|
func memROCut(s mem.RO, sep byte) (before, after mem.RO, found bool) {
|
||||||
return nil, &ParseError{"Invalid key: " + err.Error(), s}
|
if i := mem.IndexByte(s, sep); i >= 0 {
|
||||||
|
return s.SliceTo(i), s.SliceFrom(i + 1), true
|
||||||
}
|
}
|
||||||
if len(k) != wgkey.Size {
|
found = false
|
||||||
return nil, &ParseError{"Keys must decode to exactly 32 bytes", s}
|
return
|
||||||
}
|
|
||||||
var key wgkey.Key
|
|
||||||
copy(key[:], k)
|
|
||||||
return &key, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// stringsCut is strings.Cut from proposed https://github.com/golang/go/issues/46336.
|
|
||||||
func stringsCut(s, sep string) (before, after string, found bool) {
|
|
||||||
if i := strings.Index(s, sep); i >= 0 {
|
|
||||||
return s[:i], s[i+len(sep):], true
|
|
||||||
}
|
|
||||||
return s, "", false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromUAPI generates a Config from r.
|
// FromUAPI generates a Config from r.
|
||||||
@ -87,23 +77,23 @@ func FromUAPI(r io.Reader) (*Config, error) {
|
|||||||
|
|
||||||
scanner := bufio.NewScanner(r)
|
scanner := bufio.NewScanner(r)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := scanner.Text()
|
line := mem.B(scanner.Bytes())
|
||||||
if line == "" {
|
if line.Len() == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
key, value, ok := stringsCut(line, "=")
|
key, value, ok := memROCut(line, '=')
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("failed to cut line %q on =", line)
|
return nil, fmt.Errorf("failed to cut line %q on =", line.StringCopy())
|
||||||
}
|
}
|
||||||
valueBytes := scanner.Bytes()[len(key)+1:]
|
valueBytes := scanner.Bytes()[key.Len()+1:]
|
||||||
|
|
||||||
if key == "public_key" {
|
if key.EqualString("public_key") {
|
||||||
if deviceConfig {
|
if deviceConfig {
|
||||||
deviceConfig = false
|
deviceConfig = false
|
||||||
}
|
}
|
||||||
// Load/create the peer we are now configuring.
|
// Load/create the peer we are now configuring.
|
||||||
var err error
|
var err error
|
||||||
peer, err = cfg.handlePublicKeyLine(value)
|
peer, err = cfg.handlePublicKeyLine(valueBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -112,7 +102,7 @@ func FromUAPI(r io.Reader) (*Config, error) {
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
if deviceConfig {
|
if deviceConfig {
|
||||||
err = cfg.handleDeviceLine(key, value)
|
err = cfg.handleDeviceLine(key, value, valueBytes)
|
||||||
} else {
|
} else {
|
||||||
err = cfg.handlePeerLine(peer, key, value, valueBytes)
|
err = cfg.handlePeerLine(peer, key, value, valueBytes)
|
||||||
}
|
}
|
||||||
@ -128,63 +118,73 @@ func FromUAPI(r io.Reader) (*Config, error) {
|
|||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Config) handleDeviceLine(key, value string) error {
|
func parseKeyHex(s []byte, dst []byte) error {
|
||||||
switch key {
|
n, err := hex.Decode(dst, s)
|
||||||
case "private_key":
|
if err != nil {
|
||||||
k, err := parseKeyHex(value)
|
return &ParseError{"Invalid key: " + err.Error(), string(s)}
|
||||||
if err != nil {
|
}
|
||||||
return err
|
if n != wgkey.Size {
|
||||||
}
|
return &ParseError{"Keys must decode to exactly 32 bytes", string(s)}
|
||||||
// wireguard-go guarantees not to send zero value; private keys are already clamped.
|
|
||||||
cfg.PrivateKey = wgkey.Private(*k)
|
|
||||||
case "listen_port":
|
|
||||||
// ignore
|
|
||||||
case "fwmark":
|
|
||||||
// ignore
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unexpected IpcGetOperation key: %v", key)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Config) handlePublicKeyLine(value string) (*Peer, error) {
|
func (cfg *Config) handleDeviceLine(key, value mem.RO, valueBytes []byte) error {
|
||||||
k, err := parseKeyHex(value)
|
switch {
|
||||||
if err != nil {
|
case key.EqualString("private_key"):
|
||||||
return nil, err
|
// wireguard-go guarantees not to send zero value; private keys are already clamped.
|
||||||
}
|
if err := parseKeyHex(valueBytes, cfg.PrivateKey[:]); err != nil {
|
||||||
cfg.Peers = append(cfg.Peers, Peer{})
|
|
||||||
peer := &cfg.Peers[len(cfg.Peers)-1]
|
|
||||||
peer.PublicKey = *k
|
|
||||||
return peer, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cfg *Config) handlePeerLine(peer *Peer, key, value string, valueBytes []byte) error {
|
|
||||||
switch key {
|
|
||||||
case "endpoint":
|
|
||||||
err := json.Unmarshal(valueBytes, &peer.Endpoints)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "persistent_keepalive_interval":
|
case key.EqualString("listen_port") || key.EqualString("fwmark"):
|
||||||
n, err := strconv.ParseUint(value, 10, 16)
|
// ignore
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unexpected IpcGetOperation key: %q", key.StringCopy())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *Config) handlePublicKeyLine(valueBytes []byte) (*Peer, error) {
|
||||||
|
p := Peer{}
|
||||||
|
if err := parseKeyHex(valueBytes, p.PublicKey[:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cfg.Peers = append(cfg.Peers, p)
|
||||||
|
return &cfg.Peers[len(cfg.Peers)-1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *Config) handlePeerLine(peer *Peer, key, value mem.RO, valueBytes []byte) error {
|
||||||
|
switch {
|
||||||
|
case key.EqualString("endpoint"):
|
||||||
|
if err := json.Unmarshal(valueBytes, &peer.Endpoints); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case key.EqualString("persistent_keepalive_interval"):
|
||||||
|
n, err := mem.ParseUint(value, 10, 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
peer.PersistentKeepalive = uint16(n)
|
peer.PersistentKeepalive = uint16(n)
|
||||||
case "allowed_ip":
|
case key.EqualString("allowed_ip"):
|
||||||
ipp, err := netaddr.ParseIPPrefix(value)
|
ipp := netaddr.IPPrefix{}
|
||||||
|
err := ipp.UnmarshalText(valueBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
peer.AllowedIPs = append(peer.AllowedIPs, ipp)
|
peer.AllowedIPs = append(peer.AllowedIPs, ipp)
|
||||||
case "protocol_version":
|
case key.EqualString("protocol_version"):
|
||||||
if value != "1" {
|
if !value.EqualString("1") {
|
||||||
return fmt.Errorf("invalid protocol version: %v", value)
|
return fmt.Errorf("invalid protocol version: %q", value.StringCopy())
|
||||||
}
|
}
|
||||||
case "replace_allowed_ips", "preshared_key", "last_handshake_time_sec", "last_handshake_time_nsec", "tx_bytes", "rx_bytes":
|
case key.EqualString("replace_allowed_ips") ||
|
||||||
// ignore
|
key.EqualString("preshared_key") ||
|
||||||
|
key.EqualString("last_handshake_time_sec") ||
|
||||||
|
key.EqualString("last_handshake_time_nsec") ||
|
||||||
|
key.EqualString("tx_bytes") ||
|
||||||
|
key.EqualString("rx_bytes"):
|
||||||
|
// ignore
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unexpected IpcGetOperation key: %v", key)
|
return fmt.Errorf("unexpected IpcGetOperation key: %q", key.StringCopy())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user