Skip to content

Commit

Permalink
link: add netfilter support
Browse files Browse the repository at this point in the history
Signed-off-by: Mehrdad Arshad Rad <arshad.rad@gmail.com>
  • Loading branch information
mehrdadrad committed Jan 30, 2024
1 parent bfbacc1 commit a6e838d
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 0 deletions.
12 changes: 12 additions & 0 deletions internal/cmd/gentypes/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,17 @@ import (
rename("cnt", "count"),
},
},
{
"LinkCreateNetfilter", retFd, "link_create", "BPF_LINK_CREATE",
[]patch{
chooseNth(4, 5),
replace(enumTypes["AttachType"], "attach_type"),
modify(func(m *btf.Member) error {
return rename("flags", "netfilter_flags")(m.Type.(*btf.Struct))
}, "netfilter"),
flattenAnon,
},
},
{
"LinkCreateTracing", retFd, "link_create", "BPF_LINK_CREATE",
[]patch{
Expand Down Expand Up @@ -548,6 +559,7 @@ import (
{"TcxLinkInfo", "tcx", []patch{
replace(enumTypes["AttachType"], "attach_type"),
}},
{"NetfilterLinkInfo", "netfilter", nil},
}

sort.Slice(linkInfoExtraTypes, func(i, j int) bool {
Expand Down
27 changes: 27 additions & 0 deletions internal/sys/types.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions link/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ func wrapRawLink(raw *RawLink) (_ Link, err error) {
return nil, fmt.Errorf("recovering perf event fd: %w", ErrNotSupported)
case TCXType:
return &tcxLink{*raw}, nil
case NetfilterType:
return &netfilterLink{*raw}, nil
default:
return raw, nil
}
Expand Down Expand Up @@ -135,6 +137,7 @@ type CgroupInfo sys.CgroupLinkInfo
type NetNsInfo sys.NetNsLinkInfo
type XDPInfo sys.XDPLinkInfo
type TCXInfo sys.TcxLinkInfo
type NetfilterInfo sys.NetfilterLinkInfo

// Tracing returns tracing type-specific link info.
//
Expand Down Expand Up @@ -176,6 +179,14 @@ func (r Info) TCX() *TCXInfo {
return e
}

// Netfilter returns netfilter type-specific link info.
//
// Returns nil if the type-specific link info isn't available.
func (r Info) Netfilter() *NetfilterInfo {
e, _ := r.extra.(*NetfilterInfo)
return e
}

// RawLink is the low-level API to bpf_link.
//
// You should consider using the higher level interfaces in this
Expand Down Expand Up @@ -328,6 +339,8 @@ func (l *RawLink) Info() (*Info, error) {
// Extra metadata not supported.
case TCXType:
extra = &TCXInfo{}
case NetfilterType:
extra = &NetfilterInfo{}
default:
return nil, fmt.Errorf("unknown link info type: %d", info.Type)
}
Expand Down
5 changes: 5 additions & 0 deletions link/link_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ func testLink(t *testing.T, link Link, prog *ebpf.Program) {
if tcx.Ifindex == 0 {
t.Fatalf("Failed to get link TCX extra info")
}
case sys.BPF_LINK_TYPE_NETFILTER:
nf := info.Netfilter()
if nf.Priority == 0 {
t.Fatalf("Failed to get link Netfilter extra info")
}
}
})

Expand Down
70 changes: 70 additions & 0 deletions link/netfilter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package link

import (
"fmt"

"github.com/cilium/ebpf"
"github.com/cilium/ebpf/internal/sys"
)

const NFIPDefrag NetfilterAttachFlags = 0 // Enable IP packet defragmentation

type NetfilterAttachFlags uint32

type NetfilterOptions struct {
// Program must be a netfilter BPF program.
Program *ebpf.Program
// The protocol family.
ProtocolFamily uint32
// The number of the hook you are interested in.
HookNumber uint32
// Priority within hook
Priority int32
// Extra link flags
Flags uint32
// Netfilter flags
NetfilterFlags NetfilterAttachFlags
}

type netfilterLink struct {
RawLink
}

// AttachNetfilter links a netfilter BPF program to a netfilter hook.
func AttachNetfilter(opts NetfilterOptions) (Link, error) {
if opts.Program == nil {
return nil, fmt.Errorf("netfilter program is nil")
}

if t := opts.Program.Type(); t != ebpf.Netfilter {
return nil, fmt.Errorf("invalid program type %s, expected netfilter", t)
}

progFd := opts.Program.FD()
if progFd < 0 {
return nil, fmt.Errorf("invalid program: %s", sys.ErrClosedFd)
}

attr := sys.LinkCreateNetfilterAttr{
ProgFd: uint32(opts.Program.FD()),
AttachType: sys.BPF_NETFILTER,
Flags: opts.Flags,
Pf: uint32(opts.ProtocolFamily),
Hooknum: uint32(opts.HookNumber),
Priority: opts.Priority,
NetfilterFlags: uint32(opts.NetfilterFlags),
}

fd, err := sys.LinkCreateNetfilter(&attr)
if err != nil {
return nil, fmt.Errorf("attach netfilter link: %w", err)
}

return &netfilterLink{RawLink{fd, ""}}, nil
}

func (*netfilterLink) Update(new *ebpf.Program) error {
return fmt.Errorf("netfilter update: %w", ErrNotSupported)
}

var _ Link = (*netfilterLink)(nil)
27 changes: 27 additions & 0 deletions link/netfilter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package link

import (
"testing"

"github.com/cilium/ebpf"
"github.com/cilium/ebpf/internal/testutils"
"golang.org/x/sys/unix"
)

func TestAttachNetfilter(t *testing.T) {
testutils.SkipOnOldKernel(t, "6.4", "BPF_LINK_TYPE_NETFILTER")

prog := mustLoadProgram(t, ebpf.Netfilter, ebpf.AttachNetfilter, "")

l, err := AttachNetfilter(NetfilterOptions{
Program: prog,
ProtocolFamily: unix.NFPROTO_IPV4,
HookNumber: unix.NF_INET_LOCAL_OUT,
Priority: -128,
})
if err != nil {
t.Fatal(err)
}

testLink(t, l, prog)
}
1 change: 1 addition & 0 deletions link/syscalls.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
PerfEventType = sys.BPF_LINK_TYPE_PERF_EVENT
KprobeMultiType = sys.BPF_LINK_TYPE_KPROBE_MULTI
TCXType = sys.BPF_LINK_TYPE_TCX
NetfilterType = sys.BPF_LINK_TYPE_NETFILTER
)

var haveProgAttach = internal.NewFeatureTest("BPF_PROG_ATTACH", "4.10", func() error {
Expand Down

0 comments on commit a6e838d

Please sign in to comment.