mirror of
https://github.com/vishvananda/netlink.git
synced 2025-09-26 20:01:13 +08:00
Add support for xdp set/get of a bpf program (#156)
* Add netlink definitions for extra IFLAs The relevant IFLA_* are defined in the kernel but not in the syscall package. * Parameterize the return value of loadSimpleBpf Allow the return value of the bpf program created by loadSimpleBpf to be specified by the caller. Before this, the value was hardcoded to 1. * Add support for a new IFLA that enables using a bpf program as a filter early in the driver path of some NICs. * Add a test for set/get of an xdp program. Since currently, the XDP IFLA is optional, check that the hardware supports it before trying to set the field. Signed-off-by: Brenden Blanco <bblanco@plumgrid.com>
This commit is contained in:

committed by
Vish Ishaya

parent
d710fbade4
commit
fadc1088f6
12
bpf_linux.go
12
bpf_linux.go
@@ -8,11 +8,11 @@ package netlink
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int load_simple_bpf(int prog_type) {
|
||||
static int load_simple_bpf(int prog_type, int ret) {
|
||||
#ifdef __NR_bpf
|
||||
// { return 1; }
|
||||
// { return ret; }
|
||||
__u64 __attribute__((aligned(8))) insns[] = {
|
||||
0x00000001000000b7ull,
|
||||
0x00000000000000b7ull | ((__u64)ret<<32),
|
||||
0x0000000000000095ull,
|
||||
};
|
||||
__u8 __attribute__((aligned(8))) license[] = "ASL2";
|
||||
@@ -51,10 +51,12 @@ const (
|
||||
BPF_PROG_TYPE_KPROBE
|
||||
BPF_PROG_TYPE_SCHED_CLS
|
||||
BPF_PROG_TYPE_SCHED_ACT
|
||||
BPF_PROG_TYPE_TRACEPOINT
|
||||
BPF_PROG_TYPE_XDP
|
||||
)
|
||||
|
||||
// loadSimpleBpf loads a trivial bpf program for testing purposes
|
||||
func loadSimpleBpf(progType BpfProgType) (int, error) {
|
||||
fd, err := C.load_simple_bpf(C.int(progType))
|
||||
func loadSimpleBpf(progType BpfProgType, ret int) (int, error) {
|
||||
fd, err := C.load_simple_bpf(C.int(progType), C.int(ret))
|
||||
return int(fd), err
|
||||
}
|
||||
|
@@ -290,7 +290,7 @@ func TestFilterU32BpfAddDel(t *testing.T) {
|
||||
t.Fatal("Qdisc is the wrong type")
|
||||
}
|
||||
|
||||
fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_ACT)
|
||||
fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_ACT, 1)
|
||||
if err != nil {
|
||||
t.Skipf("Loading bpf program failed: %s", err)
|
||||
}
|
||||
@@ -411,7 +411,7 @@ func TestFilterClsActBpfAddDel(t *testing.T) {
|
||||
Protocol: syscall.ETH_P_ALL,
|
||||
Priority: 1,
|
||||
}
|
||||
fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_CLS)
|
||||
fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_CLS, 1)
|
||||
if err != nil {
|
||||
t.Skipf("Loading bpf program failed: %s", err)
|
||||
}
|
||||
|
6
link.go
6
link.go
@@ -32,6 +32,7 @@ type LinkAttrs struct {
|
||||
Alias string
|
||||
Statistics *LinkStatistics
|
||||
Promisc int
|
||||
Xdp *LinkXdp
|
||||
}
|
||||
|
||||
// NewLinkAttrs returns LinkAttrs structure filled with default values
|
||||
@@ -70,6 +71,11 @@ type LinkStatistics struct {
|
||||
TxCompressed uint32
|
||||
}
|
||||
|
||||
type LinkXdp struct {
|
||||
Fd int
|
||||
Attached bool
|
||||
}
|
||||
|
||||
// Device links cannot be created via netlink. These links
|
||||
// are links created by udev like 'lo' and 'etho0'
|
||||
type Device struct {
|
||||
|
@@ -416,6 +416,23 @@ func (h *Handle) LinkSetNsFd(link Link, fd int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// LinkSetXdpFd adds a bpf function to the driver. The fd must be a bpf
|
||||
// program loaded with bpf(type=BPF_PROG_TYPE_XDP)
|
||||
func LinkSetXdpFd(link Link, fd int) error {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Index = int32(base.Index)
|
||||
req.AddData(msg)
|
||||
|
||||
addXdpAttrs(&LinkXdp{Fd: fd}, req)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
func boolAttr(val bool) []byte {
|
||||
var v uint8
|
||||
if val {
|
||||
@@ -693,6 +710,10 @@ func (h *Handle) LinkAdd(link Link) error {
|
||||
req.AddData(attr)
|
||||
}
|
||||
|
||||
if base.Xdp != nil {
|
||||
addXdpAttrs(base.Xdp, req)
|
||||
}
|
||||
|
||||
linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil)
|
||||
nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
|
||||
|
||||
@@ -1005,6 +1026,12 @@ func linkDeserialize(m []byte) (Link, error) {
|
||||
base.Alias = string(attr.Value[:len(attr.Value)-1])
|
||||
case syscall.IFLA_STATS:
|
||||
base.Statistics = parseLinkStats(attr.Value[:])
|
||||
case nl.IFLA_XDP:
|
||||
xdp, err := parseLinkXdp(attr.Value[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base.Xdp = xdp
|
||||
}
|
||||
}
|
||||
// Links that don't have IFLA_INFO_KIND are hardware devices
|
||||
@@ -1436,3 +1463,28 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
func parseLinkStats(data []byte) *LinkStatistics {
|
||||
return (*LinkStatistics)(unsafe.Pointer(&data[0:SizeofLinkStats][0]))
|
||||
}
|
||||
|
||||
func addXdpAttrs(xdp *LinkXdp, req *nl.NetlinkRequest) {
|
||||
attrs := nl.NewRtAttr(nl.IFLA_XDP|syscall.NLA_F_NESTED, nil)
|
||||
b := make([]byte, 4)
|
||||
native.PutUint32(b, uint32(xdp.Fd))
|
||||
nl.NewRtAttrChild(attrs, nl.IFLA_XDP_FD, b)
|
||||
req.AddData(attrs)
|
||||
}
|
||||
|
||||
func parseLinkXdp(data []byte) (*LinkXdp, error) {
|
||||
attrs, err := nl.ParseRouteAttr(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
xdp := &LinkXdp{}
|
||||
for _, attr := range attrs {
|
||||
switch attr.Attr.Type {
|
||||
case nl.IFLA_XDP_FD:
|
||||
xdp.Fd = int(native.Uint32(attr.Value[0:4]))
|
||||
case nl.IFLA_XDP_ATTACHED:
|
||||
xdp.Attached = attr.Value[0] != 0
|
||||
}
|
||||
}
|
||||
return xdp, nil
|
||||
}
|
||||
|
27
link_test.go
27
link_test.go
@@ -942,3 +942,30 @@ func TestLinkStats(t *testing.T) {
|
||||
t.Fatalf("veth ends counters differ:\n%v\n%v", v0Stats, v1Stats)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkXdp(t *testing.T) {
|
||||
links, err := LinkList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var testXdpLink Link
|
||||
for _, link := range links {
|
||||
if link.Attrs().Xdp != nil && !link.Attrs().Xdp.Attached {
|
||||
testXdpLink = link
|
||||
break
|
||||
}
|
||||
}
|
||||
if testXdpLink == nil {
|
||||
t.Skipf("No link supporting XDP found")
|
||||
}
|
||||
fd, err := loadSimpleBpf(BPF_PROG_TYPE_XDP, 2 /*XDP_PASS*/)
|
||||
if err != nil {
|
||||
t.Skipf("Loading bpf program failed: %s", err)
|
||||
}
|
||||
if err := LinkSetXdpFd(testXdpLink, fd); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := LinkSetXdpFd(testXdpLink, -1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@@ -1,13 +1,35 @@
|
||||
package nl
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
DEFAULT_CHANGE = 0xFFFFFFFF
|
||||
// doesn't exist in syscall
|
||||
IFLA_VFINFO_LIST = 0x16
|
||||
IFLA_VFINFO_LIST = syscall.IFLA_IFALIAS + 1 + iota
|
||||
IFLA_STATS64
|
||||
IFLA_VF_PORTS
|
||||
IFLA_PORT_SELF
|
||||
IFLA_AF_SPEC
|
||||
IFLA_GROUP
|
||||
IFLA_NET_NS_FD
|
||||
IFLA_EXT_MASK
|
||||
IFLA_PROMISCUITY
|
||||
IFLA_NUM_TX_QUEUES
|
||||
IFLA_NUM_RX_QUEUES
|
||||
IFLA_CARRIER
|
||||
IFLA_PHYS_PORT_ID
|
||||
IFLA_CARRIER_CHANGES
|
||||
IFLA_PHYS_SWITCH_ID
|
||||
IFLA_LINK_NETNSID
|
||||
IFLA_PHYS_PORT_NAME
|
||||
IFLA_PROTO_DOWN
|
||||
IFLA_GSO_MAX_SEGS
|
||||
IFLA_GSO_MAX_SIZE
|
||||
IFLA_PAD
|
||||
IFLA_XDP
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -89,11 +111,6 @@ const (
|
||||
IFLA_IPVLAN_MAX = IFLA_IPVLAN_MODE
|
||||
)
|
||||
|
||||
const (
|
||||
// not defined in syscall
|
||||
IFLA_NET_NS_FD = 28
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_MACVLAN_UNSPEC = iota
|
||||
IFLA_MACVLAN_MODE
|
||||
@@ -394,3 +411,10 @@ func DeserializeVfRssQueryEn(b []byte) *VfRssQueryEn {
|
||||
func (msg *VfRssQueryEn) Serialize() []byte {
|
||||
return (*(*[SizeofVfRssQueryEn]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
const (
|
||||
IFLA_XDP_UNSPEC = iota
|
||||
IFLA_XDP_FD /* fd of xdp program to attach, or -1 to remove */
|
||||
IFLA_XDP_ATTACHED /* read-only bool indicating if prog is attached */
|
||||
IFLA_XDP_MAX = IFLA_XDP_ATTACHED
|
||||
)
|
||||
|
Reference in New Issue
Block a user