Why is TCP splicing disabled in Linux?

According to go/src/io/io.go at 8e1fdea8316d840fd07e9d6e026048e53290948b · golang/go · GitHub, io.Copy will try to use WriteTo method to do zero copy if available. TCPConn implemented this method, but according to go/src/net/splice_linux.go at 8e1fdea8316d840fd07e9d6e026048e53290948b · golang/go · GitHub, the spliceTo method only works for unix domain sockets, why?

1 Like

spliceTo is a Linux-specific system call, for example windows uses a fundamentally different APIs and cannot handle it.

Okay, but my question was why does it not work with TCP connections on Linux. Because it should work according to the method comment and linux syscall manual.

Why do you think it does not use it? Here is WriteTo implementation for TCPConn. Here are internals for writeTo, where it will try to use spliceTo. In case if it’s linux, then it will use it from here. But for !linux build tag, there is the stub.

Because it requires the writer to be a unix domain socket, please refer to my second permalink.

Okay, I figured it out, 1.22 refactored the whole zero copy code: net: arrange zero-copy of os.File and TCPConn to UnixConn · Issue #58808 · golang/go · GitHub. The TCPConn will fail on spliceTo, but it will fallback to genericWriteTo, which calls io.Copy again with a TCPConn wrapper without the WriteTo method. So, the zero copy path for TCPConn is ReadFrom instead of WriteTo.

Got it. It is not used for TCP connection because the system call is designed for local file descriptor transfers and has specific use cases that don’t align well with TCP. As far as I know linux splice supports only Read from TCP. Since go’s standard library has to focus on cross-platform support, imho it’s very hard to implement and then maintain something this platform specific.