如何使用GSO发送UDP数据包

huangapple go评论76阅读模式
英文:

How to use GSO for sending UDP packets

问题

可以利用Linux通用分段卸载(GSO)吗?

英文:

Is it possible to make use of Linux Generic Segmentation Offload (GSO)?

答案1

得分: 1

是的和不是

GSO是在内核中设置的,具体是在网络驱动程序中。这篇文章详细介绍了相关内容。在Linux中,通常通过ethtool实用程序来启用GSO:

ethtool --offload  eth0 gso on

所以假设已经设置了这个选项,那么它将影响通过接口传输的所有流量,包括由Go应用程序生成的流量。

更困难一些,但也可以使用Go程序通过ethtool协议启用GSO。你可能可以找到一个适用于此的ethtool Go包。

更新

正如你指出的,你可以进一步优化GSO(在上述信息中启用它之后)通过设置分段大小套接字选项。从你分享的Cloudflare博客中,他们展示了如何在C中实现:

setsockopt(fd, SOL_UDP, UDP_SEGMENT, &gso_size, sizeof(gso_size)))

在底层,这是通过操作系统Syscall来完成的。

我假设你正在使用go-quic,因为Cloudflare博客中提到了QUIC。go-quic可以接受一个预先制作的net.PacketConn,所以你需要从头开始创建一个并添加分段套接字选项:

s, err := syscall.Socket(...)
if err != nil {
        // 错误处理
}
if err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.UDP_SEGMENT, gso_size); err != nil {
        syscall.Close(s)
        // 错误处理
}
if err := syscall.Bind(s, ...); err != nil {
        syscall.Close(s)
        // 错误处理
}
if err := syscall.Listen(s, ...); err != nil { // 或者 syscall.Connect
        syscall.Close(s)
        // 错误处理
}
f := os.File(s, ...)
ln, err := net.FileLitsener(f) // 或者 net.FileConn, net.FilePacketConn

//ln现在可以被go-quic使用

注意:gso_size是一个int类型的变量,在之前必须已知。

英文:

Yes and No

GSO is set in the Kernel, specifically the Network Driver. This article goes into the specifics. Enabling GSO is typically done via the ethtool utility in Linux:

ethtool --offload  eth0 gso on

So assuming this is set, then it will effect all traffic going through the interface including that which is generated by a Go application.

It would be more difficult, but it is also possible to use the go program to enable GSO via the ethtool protocol. You can probably find an ethtool go package for this.

Update

As you pointed out, you can optimize for GSO (after enabling it per the above information) even further by setting the segment size socket options. From the cloudflare blog you shared, the show how to do it in C:

setsockopt(fd, SOL_UDP, UDP_SEGMENT, &gso_size, sizeof(gso_size)))

Under the hood, this is done via an operating system Syscall.

I am assuming you are using go-quic as QUIC is referenced in the Cloudflare blog. go-quic can take a premade net.PacketConn, so you will need to create one from scratch and add the Segmentation socket option:

s, err := syscall.Socket(...)
if err != nil {
        // error handling
}
if err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.UDP_SEGMENT, gso_size); err != nil {
        syscall.Close(s)
        // error handling
}
if err := syscall.Bind(s, ...); err != nil {
        syscall.Close(s)
        // error handling
}
if err := syscall.Listen(s, ...); err != nil { // or syscall.Connect
        syscall.Close(s)
        // error handling
}
f := os.File(s, ...)
ln, err := net.FileLitsener(f) // or net.FileConn, net.FilePacketConn

//ln can now be used by go-quic

Note: gso_size is an int and must be known prior

huangapple
  • 本文由 发表于 2021年8月3日 03:58:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/68627315.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定