xdp

package
v0.0.0-...-eb7798b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2023 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package xdp allows to use XDP sockets from Go.

An XDP socket allows to get packets from a network interface driver into a userspace process very fast, bypassing the Linux kernel's network stack, see https://lwn.net/Articles/750845/ for more information.

NOTE:

* If your network link device supports multiple queues - you might not see all of the incoming traffic because it might be e.g. load-balanced between multiple queues. You can use the `ethtool -L` command to control the load-balancing behaviour or even make it so that all of the incoming traffic is put on a single queue.

* On recent versions of Linux kernel, the eBPF map memory counts towards the "locked memory" user limit, so most likely you'll have to increase it. On Fedora Linux, this can be done by running `ulimit -l <new-limit>` command, or to make it permanent, by creating a file at `/etc/security/limits.d/50-lockedmem.conf` with e.g. the following contents (1MiB should be enough for this package):

  • - lockedmem 1048576

logging out and logging back in. When you hit this limit, you'll get an error that looks like this:

error: failed to create an XDP socket: ebpf.NewMap qidconf_map failed: map create: operation not permitted

Here is a minimal example of a program which receives network frames, modifies their destination MAC address in-place to broadcast address and transmits them back out the same network link:

package main

import (
	"os"
	"os/signal"
	"syscall"

	"github.com/asavie/xdp"
	"github.com/vishvananda/netlink"
)

func main() {
	const LinkName = "enp6s0"
	const QueueID = 0

	link, err := netlink.LinkByName(LinkName)
	if err != nil {
		panic(err)
	}

	program, err := xdp.NewProgram(QueueID + 1)
	if err != nil {
		panic(err)
	}
	if err := program.Attach(link.Attrs().Index); err != nil {
		panic(err)
	}

	xsk, err := xdp.NewSocket(link.Attrs().Index, QueueID, nil)
	if err != nil {
		panic(err)
	}

	if err := program.Register(QueueID, xsk.FD()); err != nil {
		panic(err)
	}

	// Remove the XDP BPF program on interrupt.
	c := make(chan os.Signal)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-c
		program.Detach(link.Attrs().Index)
		os.Exit(1)
	}()

	for {
		xsk.Fill(xsk.GetDescs(xsk.NumFreeFillSlots(), true))
		numRx, _, err := xsk.Poll(-1)
		if err != nil {
			panic(err)
		}
		rxDescs := xsk.Receive(numRx)
		for i := 0; i < len(rxDescs); i++ {
			// Set destination MAC address to
			// ff:ff:ff:ff:ff:ff
			frame := xsk.GetFrame(rxDescs[i])
			for i := 0; i < 6; i++ {
				frame[i] = byte(0xff)
			}
		}
		xsk.Transmit(rxDescs)
	}
}

Index

Constants

This section is empty.

Variables

View Source
var DefaultSocketFlags uint16

DefaultSocketFlags are the flags which are passed to bind(2) system call when the XDP socket is bound, possible values include unix.XDP_SHARED_UMEM, unix.XDP_COPY, unix.XDP_ZEROCOPY.

View Source
var DefaultSocketOptions = SocketOptions{
	NumFrames:              128,
	FrameSize:              2048,
	FillRingNumDescs:       64,
	CompletionRingNumDescs: 64,
	RxRingNumDescs:         64,
	TxRingNumDescs:         64,
}

DefaultSocketOptions is the default SocketOptions used by an xdp.Socket created without specifying options.

View Source
var DefaultXdpFlags uint32

DefaultXdpFlags are the flags which are passed when the XDP program is attached to the network link, possible values include unix.XDP_FLAGS_DRV_MODE, unix.XDP_FLAGS_HW_MODE, unix.XDP_FLAGS_SKB_MODE, unix.XDP_FLAGS_UPDATE_IF_NOEXIST.

Functions

This section is empty.

Types

type Desc

type Desc unix.XDPDesc

Desc represents an XDP Rx/Tx descriptor.

type Program

type Program struct {
	Program *ebpf.Program
	Events  *ebpf.Map
}

Program represents the necessary data structures for a simple XDP program that can filter traffic based on the attached rx queue.

func (*Program) Attach

func (p *Program) Attach(Ifindex int) error

Attach the XDP Program to an interface.

func (*Program) Close

func (p *Program) Close() error

Close closes and frees the resources allocated for the Program.

func (*Program) Detach

func (p *Program) Detach(Ifindex int) error

Detach the XDP Program from an interface.

type Socket

type Socket struct {
	// contains filtered or unexported fields
}

A Socket is an implementation of the AF_XDP Linux socket type for reading packets from a device.

func NewSocket

func NewSocket(Ifindex int, QueueID int, options *SocketOptions) (xsk *Socket, err error)

NewSocket returns a new XDP socket attached to the network interface which has the given interface, and attached to the given queue on that network interface.

func (*Socket) Close

func (xsk *Socket) Close() error

Close closes and frees the resources allocated by the Socket.

func (*Socket) Complete

func (xsk *Socket) Complete(n int)

Complete consumes up to n descriptors from the Completion ring queue to which the kernel produces when it has actually transmitted a descriptor it got from Tx ring queue. You should use this method if you are doing polling on the xdp.Socket file descriptor yourself, rather than using the Poll() method.

func (*Socket) FD

func (xsk *Socket) FD() int

FD returns the file descriptor associated with this xdp.Socket which can be used e.g. to do polling.

func (*Socket) Fill

func (xsk *Socket) Fill(descs []Desc) int

Fill submits the given descriptors to be filled (i.e. to receive frames into) it returns how many descriptors where actually put onto Fill ring queue. The descriptors can be acquired either by calling the GetDescs() method or by calling Receive() method.

func (*Socket) GetDescs

func (xsk *Socket) GetDescs(n int, rx bool) []Desc

GetDescs returns up to n descriptors which are not currently in use. if rx is true, return desc in first half of umem, 2nd half otherwise

func (*Socket) GetFrame

func (xsk *Socket) GetFrame(d Desc) []byte

GetFrame returns the buffer containing the frame corresponding to the given descriptor. The returned byte slice points to the actual buffer of the corresponding frame, so modiyfing this slice modifies the frame contents.

func (*Socket) NumCompleted

func (xsk *Socket) NumCompleted() int

NumCompleted returns how many descriptors are there on the Completion ring queue which were produced by the kernel and which we have not yet consumed.

func (*Socket) NumFilled

func (xsk *Socket) NumFilled() int

NumFilled returns how many descriptors are there on the Fill ring queue which have not yet been consumed by the kernel. This method is useful if you're polling the xdp.Socket file descriptor yourself, rather than using the Poll() method - if it returns a number greater than zero it means you should set the unix.POLLIN flag.

func (*Socket) NumFreeFillSlots

func (xsk *Socket) NumFreeFillSlots() int

NumFreeFillSlots returns how many free slots are available on the Fill ring queue, i.e. the queue to which we produce descriptors which should be filled by the kernel with incoming frames.

func (*Socket) NumFreeTxSlots

func (xsk *Socket) NumFreeTxSlots() int

NumFreeTxSlots returns how many free slots are available on the Tx ring queue, i.e. the queue to which we produce descriptors which should be transmitted by the kernel to the wire.

func (*Socket) NumReceived

func (xsk *Socket) NumReceived() int

NumReceived returns how many descriptors are there on the Rx ring queue which were produced by the kernel and which we have not yet consumed.

func (*Socket) NumTransmitted

func (xsk *Socket) NumTransmitted() int

NumTransmitted returns how many descriptors are there on the Tx ring queue which have not yet been consumed by the kernel. Note that even after the descriptors are consumed by the kernel from the Tx ring queue, it doesn't mean that they have actually been sent out on the wire, that can be assumed only after the descriptors have been produced by the kernel to the Completion ring queue. This method is useful if you're polling the xdp.Socket file descriptor yourself, rather than using the Poll() method - if it returns a number greater than zero it means you should set the unix.POLLOUT flag.

func (*Socket) Poll

func (xsk *Socket) Poll(timeout int) (numReceived int, numCompleted int, err error)

Poll blocks until kernel informs us that it has either received or completed (i.e. actually sent) some frames that were previously submitted using Fill() or Transmit() methods. The numReceived return value can be used as the argument for subsequent Receive() method call.

func (*Socket) Receive

func (xsk *Socket) Receive(num int) []Desc

Receive returns the descriptors which were filled, i.e. into which frames were received into.

func (*Socket) Stats

func (xsk *Socket) Stats() (Stats, error)

Stats returns various statistics for this XDP socket.

func (*Socket) Transmit

func (xsk *Socket) Transmit(descs []Desc) (numSubmitted int)

Transmit submits the given descriptors to be sent out, it returns how many descriptors were actually pushed onto the Tx ring queue. The descriptors can be acquired either by calling the GetDescs() method or by calling Receive() method.

type SocketOptions

type SocketOptions struct {
	NumFrames              int
	FrameSize              int
	FillRingNumDescs       int
	CompletionRingNumDescs int
	RxRingNumDescs         int
	TxRingNumDescs         int
}

SocketOptions are configuration settings used to bind an XDP socket.

type Stats

type Stats struct {
	// Filled is the number of items consumed thus far by the Linux kernel
	// from the Fill ring queue.
	Filled uint64

	// Received is the number of items consumed thus far by the user of
	// this package from the Rx ring queue.
	Received uint64

	// Transmitted is the number of items consumed thus far by the Linux
	// kernel from the Tx ring queue.
	Transmitted uint64

	// Completed is the number of items consumed thus far by the user of
	// this package from the Completion ring queue.
	Completed uint64

	// KernelStats contains the in-kernel statistics of the corresponding
	// XDP socket, such as the number of invalid descriptors that were
	// submitted into Fill or Tx ring queues.
	KernelStats unix.XDPStatistics
}

Stats contains various counters of the XDP socket, such as numbers of sent/received frames.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL