xdp: control USE_NEED_WAKEUP via flag for benchmarking

PiperOrigin-RevId: 591382575
This commit is contained in:
Kevin Krakauer
2023-12-15 16:02:53 -08:00
committed by gVisor bot
parent 54e02c3c56
commit c1aef9f901
5 changed files with 45 additions and 48 deletions
+34 -25
View File
@@ -67,10 +67,11 @@ type ControlBlock struct {
// ReadOnlySocketOpts configure a read-only AF_XDP socket.
type ReadOnlySocketOpts struct {
NFrames uint32
FrameSize uint32
NDescriptors uint32
Bind bool
NFrames uint32
FrameSize uint32
NDescriptors uint32
Bind bool
UseNeedWakeup bool
}
// DefaultReadOnlyOpts provides recommended default options for initializing a
@@ -287,30 +288,38 @@ func ReadOnlyFromSocket(sockfd int, ifaceIdx, queueID uint32, opts ReadOnlySocke
// device. In those cases, another process with the same socket will
// bind for us.
if opts.Bind {
addr := unix.SockaddrXDP{
// XDP_USE_NEED_WAKEUP lets the driver sleep if there is no
// work to do. It will need to be woken by poll. It is expected
// that this improves performance by preventing the driver from
// burning cycles.
//
// By not setting either XDP_COPY or XDP_ZEROCOPY, we instruct
// the kernel to use zerocopy if available and then fallback to
// copy mode.
Flags: unix.XDP_USE_NEED_WAKEUP,
Ifindex: ifaceIdx,
// AF_XDP sockets are per device RX queue, although multiple
// sockets on multiple queues (or devices) can share a single
// UMEM.
QueueID: queueID,
// We're not using shared mode, so the value here is irrelevant.
SharedUmemFD: 0,
}
if err := unix.Bind(sockfd, &addr); err != nil {
return nil, fmt.Errorf("failed to bind with addr %+v: %v", addr, err)
if err := Bind(sockfd, ifaceIdx, queueID, opts.UseNeedWakeup); err != nil {
return nil, fmt.Errorf("failed to bind to interface %d: %v", ifaceIdx, err)
}
}
cleanup.Release()
return &cb, nil
}
// Bind binds a socket to a particular network interface and queue.
func Bind(sockfd int, ifindex, queueID uint32, useNeedWakeup bool) error {
var flags uint16
if useNeedWakeup {
flags |= unix.XDP_USE_NEED_WAKEUP
}
addr := unix.SockaddrXDP{
// XDP_USE_NEED_WAKEUP lets the driver sleep if there is no
// work to do. It will need to be woken by poll. It is expected
// that this improves performance by preventing the driver from
// burning cycles.
//
// By not setting either XDP_COPY or XDP_ZEROCOPY, we instruct
// the kernel to use zerocopy if available and then fallback to
// copy mode.
Flags: flags,
Ifindex: ifindex,
// AF_XDP sockets are per device RX queue, although multiple
// sockets on multiple queues (or devices) can share a single
// UMEM.
QueueID: queueID,
// We're not using shared mode, so the value here is irrelevant.
SharedUmemFD: 0,
}
return unix.Bind(sockfd, &addr)
}
+4
View File
@@ -284,6 +284,10 @@ type Config struct {
// eBPF map that runsc hooks into.
AFXDPRedirectHost string `flag:"EXPERIMENTAL-xdp-redirect-host"`
// AFXDPUseNeedWakeup determines whether XDP_USE_NEED_WAKEUP is set
// when using AF_XDP sockets.
AFXDPUseNeedWakeup bool `flag:"EXPERIMENTAL-xdp-need-wakeup"`
// FDLimit specifies a limit on the number of host file descriptors that can
// be open simultaneously by the sentry and gofer. It applies separately to
// each.
+1
View File
@@ -121,6 +121,7 @@ func RegisterFlags(flagSet *flag.FlagSet) {
flagSet.Bool("buffer-pooling", true, "enable allocation of buffers from a shared pool instead of the heap.")
flagSet.Bool("EXPERIMENTAL-afxdp", false, "EXPERIMENTAL. Use an AF_XDP socket to receive packets.")
flagSet.String("EXPERIMENTAL-xdp-redirect-host", "", "EXPERIMENTAL. Use an AF_XDP socket attached to <interface name>. Use the IP of that interface.")
flagSet.Bool("EXPERIMENTAL-xdp-need-wakeup", true, "EXPERIMENTAL. Use XDP_USE_NEED_WAKEUP with XDP sockets.")
flagSet.Bool("reproduce-nat", false, "Scrape the host netns NAT table and reproduce it in the sandbox.")
flagSet.Bool("reproduce-nftables", false, "Attempt to scrape and reproduce nftable rules inside the sandbox. Overrides reproduce-nat when true.")
+1
View File
@@ -38,6 +38,7 @@ go_library(
"//pkg/tcpip/header",
"//pkg/tcpip/stack",
"//pkg/urpc",
"//pkg/xdp",
"//runsc/boot",
"//runsc/boot/procfs",
"//runsc/cgroup",
+5 -23
View File
@@ -26,6 +26,7 @@ import (
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/urpc"
"gvisor.dev/gvisor/pkg/xdp"
"gvisor.dev/gvisor/runsc/boot"
"gvisor.dev/gvisor/runsc/config"
"gvisor.dev/gvisor/runsc/sandbox/bpf"
@@ -114,29 +115,10 @@ func createRedirectInterfacesAndRoutes(conn *urpc.Client, conf *config.Config) e
}
// Bind to the device.
sockAddr := unix.SockaddrXDP{
// XDP_USE_NEED_WAKEUP lets the driver sleep if there is no
// work to do. It will need to be woken by poll. It is expected
// that this improves performance by preventing the driver from
// burning cycles.
//
// By not setting either XDP_COPY or XDP_ZEROCOPY, we instruct
// the kernel to use zerocopy if available and then fallback to
// copy mode.
Flags: unix.XDP_USE_NEED_WAKEUP,
Ifindex: uint32(iface.Index),
// AF_XDP sockets are per device RX queue, although multiple
// sockets on multiple queues (or devices) can share a single
// UMEM.
//
// TODO(b/240191988): We can't assume there's only one queue,
// but this appears to be the case on gVNIC instances.
QueueID: 0,
// We're not using shared mode, so the value here is irrelevant.
SharedUmemFD: 0,
}
if err := unix.Bind(xdpSockFD, &sockAddr); err != nil {
return fmt.Errorf("failed to bind to interface %q with addr %+v: %v", iface.Name, sockAddr, err)
// TODO(b/240191988): We can't assume there's only one queue, but this
// appears to be the case on gVNIC instances.
if err := xdp.Bind(xdpSockFD, uint32(iface.Index), 0 /* queueID */, conf.AFXDPUseNeedWakeup); err != nil {
return fmt.Errorf("failed to bind to interface %q: %v", iface.Name, err)
}
return nil