diff options
author | David Fifield <david@bamsoftware.com> | 2022-12-11 17:51:09 -0700 |
---|---|---|
committer | David Fifield <david@bamsoftware.com> | 2022-12-14 23:02:26 -0700 |
commit | 936a1f81382c95950c4659afec1b3fe875c681d9 (patch) | |
tree | 2590f7590bd86aa8282752232e86f8c54aa77789 | |
parent | c6fabb212d7eff3f58021eb0f806376772c2bd4d (diff) | |
download | snowflake-936a1f81382c95950c4659afec1b3fe875c681d9.tar.gz snowflake-936a1f81382c95950c4659afec1b3fe875c681d9.zip |
Add a num-turbotunnel server transport option.
Replaces the hardcoded numKCPInstances.
-rw-r--r-- | server/README.md | 25 | ||||
-rw-r--r-- | server/lib/snowflake.go | 7 | ||||
-rw-r--r-- | server/server.go | 20 |
3 files changed, 45 insertions, 7 deletions
diff --git a/server/README.md b/server/README.md index 5ac7102..2b1fb7a 100644 --- a/server/README.md +++ b/server/README.md @@ -70,6 +70,26 @@ setcap 'cap_net_bind_service=+ep' /usr/local/bin/snowflake-server ``` +# Multiple KCP state machines + +The server internally uses a network protocol called KCP +to manage and persist client sessions. +Each KCP scheduler runs on a single thread. +When there are many simultaneous users (thousands), +a single KCP scheduler can be a bottleneck. +The `num-turbotunnel` pluggable transport option +lets you control the number of KCP instances, +which can help with CPU scaling: +https://bugs.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/40200 + +There is currently no way to set this option automatically. +You have to tune it manually. + +``` +ServerTransportOptions snowflake num-turbotunnel=2 +``` + + # Controlling source addresses Use the `orport-srcaddr` pluggable transport option to control what source addresses @@ -83,6 +103,11 @@ Use `ServerTransportOptions` in torrc to set the option: ServerTransportOptions snowflake orport-srcaddr=127.0.2.0/24 ``` +You can combine it with other options: +``` +ServerTransportOptions snowflake num-turbotunnel=2 orport-srcaddr=127.0.2.0/24 +``` + Specifying a source address range other than the default 127.0.0.1 can help with conserving localhost ephemeral ports on servers that receive a lot of connections: diff --git a/server/lib/snowflake.go b/server/lib/snowflake.go index 2af5dbb..4078358 100644 --- a/server/lib/snowflake.go +++ b/server/lib/snowflake.go @@ -55,11 +55,6 @@ const ( WindowSize = 65535 // StreamSize controls the maximum amount of in flight data between a client and server. StreamSize = 1048576 //1MB - - // numKCPInstances is the number of parallel KCP state machines to run. - // Clients are assigned to a particular KCP instance by a hash of their - // ClientID. - numKCPInstances = 2 ) // Transport is a structure with methods that conform to the Go PT v2.1 API @@ -76,7 +71,7 @@ func NewSnowflakeServer(getCertificate func(*tls.ClientHelloInfo) (*tls.Certific // Listen starts a listener on addr that will accept both turbotunnel // and legacy Snowflake connections. -func (t *Transport) Listen(addr net.Addr) (*SnowflakeListener, error) { +func (t *Transport) Listen(addr net.Addr, numKCPInstances int) (*SnowflakeListener, error) { listener := &SnowflakeListener{ addr: addr, queue: make(chan net.Conn, 65534), diff --git a/server/server.go b/server/server.go index 3d66d35..912fead 100644 --- a/server/server.go +++ b/server/server.go @@ -14,6 +14,7 @@ import ( "os" "os/signal" "path/filepath" + "strconv" "strings" "sync" "syscall" @@ -280,7 +281,24 @@ func main() { orPortSrcAddr = ipnet } - ln, err := transport.Listen(bindaddr.Addr) + numKCPInstances := 1 + // Are we requested to run a certain number of KCP state + // machines? + if value, ok := bindaddr.Options.Get("num-turbotunnel"); ok { + n, err := strconv.Atoi(value) + if err == nil && n < 1 { + err = fmt.Errorf("cannot be less than 1") + } + if err != nil { + err = fmt.Errorf("parsing num-turbotunnel: %w", err) + log.Println(err) + pt.SmethodError(bindaddr.MethodName, err.Error()) + continue + } + numKCPInstances = n + } + + ln, err := transport.Listen(bindaddr.Addr, numKCPInstances) if err != nil { log.Printf("error opening listener: %s", err) pt.SmethodError(bindaddr.MethodName, err.Error()) |