Repository: cilium/ebpf
Pull request #484 (2021-11-12 03:23:24)

Link: add XDP support
This new API: AttachXDP links an XDP program to an interface through BPF_LINK_CREATE.

lmb: Thanks!

Patch:
diff --git a/link/link.go b/link/link.go
index 4d962e5..9ab775e 100644
--- a/link/link.go
+++ b/link/link.go
@@ -52,6 +52,8 @@ type RawLinkOptions struct {
 	Attach ebpf.AttachType
 	// BTF is the BTF of the attachment target.
 	BTF btf.TypeID
+	// Flags control the attach behaviour.
+	Flags uint32
 }
 
 // RawLinkInfo contains metadata on a link.
@@ -90,6 +92,7 @@ func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
 		ProgFd:      uint32(progFd),
 		AttachType:  sys.AttachType(opts.Attach),
 		TargetBtfId: uint32(opts.BTF),
+		Flags:       opts.Flags,
 	}
 	fd, err := sys.LinkCreate(&attr)
 	if err != nil {
diff --git a/link/xdp.go b/link/xdp.go
new file mode 100644
index 0000000..aa8dd3a
--- /dev/null
+++ b/link/xdp.go
@@ -0,0 +1,54 @@
+package link
+
+import (
+	"fmt"
+
+	"github.com/cilium/ebpf"
+)
+
+// XDPAttachFlags represents how XDP program will be attached to interface.
+type XDPAttachFlags uint32
+
+const (
+	// XDPGenericMode (SKB) links XDP BPF program for drivers which do
+	// not yet support native XDP.
+	XDPGenericMode XDPAttachFlags = 1 << (iota + 1)
+	// XDPDriverMode links XDP BPF program into the driver’s receive path.
+	XDPDriverMode
+	// XDPOffloadMode offloads the entire XDP BPF program into hardware.
+	XDPOffloadMode
+)
+
+type XDPOptions struct {
+	// Program must be an XDP BPF program.
+	Program *ebpf.Program
+
+	// Interface is the interface index to attach program to.
+	Interface int
+
+	// Flags is one of XDPAttachFlags (optional).
+	//
+	// Only one XDP mode should be set, without flag defaults
+	// to driver/generic mode (best effort).
+	Flags XDPAttachFlags
+}
+
+// AttachXDP links an XDP BPF program to an XDP hook.
+func AttachXDP(opts XDPOptions) (Link, error) {
+	if t := opts.Program.Type(); t != ebpf.XDP {
+		return nil, fmt.Errorf("invalid program type %s, expected XDP", t)
+	}
+
+	if opts.Interface < 1 {
+		return nil, fmt.Errorf("invalid interface index: %d", opts.Interface)
+	}
+
+	rawLink, err := AttachRawLink(RawLinkOptions{
+		Program: opts.Program,
+		Attach:  ebpf.AttachXDP,
+		Target:  opts.Interface,
+		Flags:   uint32(opts.Flags),
+	})
+
+	return rawLink, err
+}


Test patch:
diff --git a/link/xdp_test.go b/link/xdp_test.go
new file mode 100644
index 0000000..ae8006e
--- /dev/null
+++ b/link/xdp_test.go
@@ -0,0 +1,42 @@
+package link
+
+import (
+	"testing"
+
+	"github.com/cilium/ebpf"
+	"github.com/cilium/ebpf/asm"
+	"github.com/cilium/ebpf/internal/testutils"
+)
+
+const IfIndexLO = 1
+
+func TestAttachXDP(t *testing.T) {
+	testutils.SkipOnOldKernel(t, "5.9", "BPF_LINK_TYPE_XDP")
+	prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
+		Type: ebpf.XDP,
+		Instructions: asm.Instructions{
+			asm.LoadImm(asm.R0, 2, asm.DWord),
+			asm.Return(),
+		},
+		License: "MIT",
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer prog.Close()
+
+	l, err := AttachXDP(XDPOptions{
+		Program:   prog,
+		Interface: IfIndexLO,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	testLink(t, l, testLinkOptions{
+		prog: prog,
+		loadPinned: func(s string, opts *ebpf.LoadPinOptions) (Link, error) {
+			return LoadPinnedRawLink(s, XDPType, opts)
+		},
+	})
+}