Skip to content

x/sys/unix: missing function to marshal a Cmsghdr #59653

@marten-seemann

Description

@marten-seemann

What version of Go are you using (go version)?

$ go version
go version go1.20.3 linux/amd64

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE="on"
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/root/src/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/root/src/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/root/bin/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/root/bin/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.20.3"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build1782644412=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I'm implementing UDP GSO for quic-go (tracking issue). Since quic-go does DPLPMTUD, a server will send packets with different sizes to different clients. Therefore, we can't just set a single packet size per UDP socket. Instead, we have to pass the desired packet size to the kernel with every sendmsg call.

In Go, this is done using the WriteMsgUDP function on the net.UDPConn. The size is encoded as a control message, which is passed in the oob []byte parameter to that function:

cm = CMSG_FIRSTHDR(&msg);
cm->cmsg_level = SOL_UDP;
cm->cmsg_type = UDP_SEGMENT;
cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
*((uint16_t *) CMSG_DATA(cm)) = gso_size;

Proof of concept here: https://gist.github.com/marten-seemann/a549773b53f30960b966a9f4068b6e48#file-gso-go-L45-L50

What did you expect to see?

The proof of concept works, as can be confirmed by running tcpdump (e.g. tcpdump host 8.8.8.8 -n -v -i eth0).

What did you see instead?

Serializing the control message has to be done by hand (see the getCmsg function in my PoC). The precise format of the control message is highly dependent on the architecture, and my PoC will only work on amd64 (see definition). Other architectures serialize this message slightly different, there are 41 (!) architecture-dependent ztypes_ files in the unix package that define the Cmsghdr.

x/sys/unix already provides a deserialization function (via ParseOneSocketControlMessage / ParseSocketControlMessage). It would it would provide some kind of serialization function that works on all architectures as well.

Metadata

Metadata

Assignees

No one assigned

    Labels

    FeatureRequestIssues asking for a new feature that does not need a proposal.NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.compiler/runtimeIssues related to the Go compiler and/or runtime.help wanted

    Type

    No type

    Projects

    Status

    Todo

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions