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 ( "github.com/asavie/xdp" "github.com/vishvananda/netlink" ) func main() { const LinkName = "enp3s0" const QueueID = 0 link, err := netlink.LinkByName(LinkName) if err != nil { panic(err) } xsk, err := xdp.NewSocket(link.Attrs().Index, QueueID) if err != nil { panic(err) } for { xsk.Fill(xsk.GetDescs(xsk.NumFreeFillSlots())) 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
- Variables
- type BatchDesc
- type ProgRef
- type Socket
- func (xsk *Socket) Close() error
- func (xsk *Socket) Complete(n int)
- func (xsk *Socket) FD() int
- func (xsk *Socket) Fill(descs []unix.XDPDesc) int
- func (xsk *Socket) GetDescs(n int) []unix.XDPDesc
- func (xsk *Socket) GetFrame(d unix.XDPDesc) []byte
- func (xsk *Socket) NumCompleted() int
- func (xsk *Socket) NumFilled() int
- func (xsk *Socket) NumFreeFillSlots() int
- func (xsk *Socket) NumFreeTxSlots() int
- func (xsk *Socket) NumReceived() int
- func (xsk *Socket) NumTransmitted() int
- func (xsk *Socket) Poll(timeout int) (numReceived int, numCompleted int, err error)
- func (xsk *Socket) Receive(num int) []unix.XDPDesc
- func (xsk *Socket) Stats() (Stats, error)
- func (xsk *Socket) Transmit(descs []unix.XDPDesc) (numSubmitted int)
- type Stats
- type Tap
Constants ¶
const ( NumFrames = 128 FrameSize = 2048 FillRingNumDescs = 64 CompletionRingNumDescs = 64 RxRingNumDescs = 64 TxRingNumDescs = 64 DescBatchSize = 16 )
Variables ¶
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.
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 Socket ¶
type Socket struct {
// contains filtered or unexported fields
}
Socket XDP socket
func NewSocket ¶
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) Complete ¶
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 ¶
FD returns the file descriptor associated with this xdp.Socket which can be used e.g. to do polling.
func (*Socket) Fill ¶
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) GetFrame ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
Receive returns the descriptors which were filled, i.e. into which frames were received into.
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.
type Tap ¶
type Tap struct {
// contains filtered or unexported fields
}
Tap provides communication between taps in bridges and other endpoints, via XDP/eBFP redirects implements io.ReadWriteCloser
func (*Tap) BatchWrite ¶
BatchWrite takes an array of byte arrays to be transmitted