Skip to content

Commit 0d6b6a1

Browse files
committed
examples: add filter/matchall example
Signed-off-by: Florian Lehner <[email protected]>
1 parent 4aeadc5 commit 0d6b6a1

File tree

2 files changed

+159
-5
lines changed

2 files changed

+159
-5
lines changed

example_gteq_1.16_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ import (
1212
"github.com/cilium/ebpf/asm"
1313
"github.com/florianl/go-tc"
1414
"github.com/florianl/go-tc/core"
15-
"github.com/florianl/go-tc/internal/unix"
1615
"github.com/jsimonetti/rtnetlink"
1716
"github.com/mdlayher/netlink"
17+
"golang.org/x/sys/unix"
1818
)
1919

20-
// This example demonstrate how to attach an eBPF program with TC to an interface.
20+
// This example demonstrates how to attach an eBPF program with TC to an interface.
2121
func Example_eBPF() {
2222
tcIface := "ExampleEBPF"
2323

@@ -73,9 +73,8 @@ func Example_eBPF() {
7373
Msg: tc.Msg{
7474
Family: unix.AF_UNSPEC,
7575
Ifindex: uint32(devID.Index),
76-
Handle: core.BuildHandle(tc.HandleRoot, 0x0000),
76+
Handle: core.BuildHandle(tc.HandleRoot, 0x0),
7777
Parent: tc.HandleIngress,
78-
Info: 0,
7978
},
8079
Attribute: tc.Attribute{
8180
Kind: "clsact",
@@ -124,7 +123,7 @@ func Example_eBPF() {
124123
Ifindex: uint32(devID.Index),
125124
Handle: 0,
126125
Parent: core.BuildHandle(tc.HandleRoot, tc.HandleMinIngress),
127-
Info: 0x300,
126+
Info: core.FilterInfo(0, unix.ETH_P_ALL),
128127
},
129128
tc.Attribute{
130129
Kind: "bpf",

example_matchall_gteq_1.16_test.go

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
//go:build go1.16 && linux
2+
// +build go1.16,linux
3+
4+
package tc_test
5+
6+
import (
7+
"fmt"
8+
"net"
9+
"os"
10+
11+
"github.com/cilium/ebpf"
12+
"github.com/cilium/ebpf/asm"
13+
"github.com/florianl/go-tc"
14+
"github.com/florianl/go-tc/core"
15+
"github.com/jsimonetti/rtnetlink"
16+
"github.com/mdlayher/netlink"
17+
"golang.org/x/sys/unix"
18+
)
19+
20+
// This example demonstrates how to use an eBPF program in a TC filer/matchall action.
21+
func ExampleMatchall() {
22+
tcIface := "matchallIface"
23+
24+
// For the purpose of testing a dummy network interface is set up for the example.
25+
rtnl, err := setupDummyInterface(tcIface)
26+
if err != nil {
27+
fmt.Fprintf(os.Stderr, "could not setup dummy interface: %v\n", err)
28+
return
29+
}
30+
defer rtnl.Close()
31+
32+
// Get the net.Interface by its name to which the tc/qdisc and tc/filter with
33+
// the eBPF program will be attached on.
34+
devID, err := net.InterfaceByName(tcIface)
35+
if err != nil {
36+
fmt.Fprintf(os.Stderr, "could not get interface ID: %v\n", err)
37+
return
38+
}
39+
defer func(devID uint32, rtnl *rtnetlink.Conn) {
40+
// As a dummy network interface was set up for this test make sure to
41+
// remove this link again once this example finished.
42+
if err := rtnl.Link.Delete(devID); err != nil {
43+
fmt.Fprintf(os.Stderr, "could not delete interface: %v\n", err)
44+
}
45+
}(uint32(devID.Index), rtnl)
46+
47+
// Open a netlink/tc connection to the Linux kernel. This connection is
48+
// used to manage the tc/qdisc and tc/filter to which
49+
// the eBPF program will be attached
50+
tcnl, err := tc.Open(&tc.Config{})
51+
if err != nil {
52+
fmt.Fprintf(os.Stderr, "could not open rtnetlink socket: %v\n", err)
53+
return
54+
}
55+
defer func() {
56+
if err := tcnl.Close(); err != nil {
57+
fmt.Fprintf(os.Stderr, "could not close rtnetlink socket: %v\n", err)
58+
}
59+
}()
60+
61+
// For enhanced error messages from the kernel, it is recommended to set
62+
// option `NETLINK_EXT_ACK`, which is supported since 4.12 kernel.
63+
//
64+
// If not supported, `unix.ENOPROTOOPT` is returned.
65+
if err := tcnl.SetOption(netlink.ExtendedAcknowledge, true); err != nil {
66+
fmt.Fprintf(os.Stderr, "could not set option ExtendedAcknowledge: %v\n", err)
67+
return
68+
}
69+
70+
// For the purpose of this example handcraft an eBPF program of type BPF_PROG_TYPE_SCHED_ACT
71+
// that will be attached to the networking interface via the TC filter/matchall action.
72+
//
73+
// Check out ebpf.LoadCollection() and ebpf.LoadCollectionSpec() for different ways to load
74+
// an eBPF program.
75+
//
76+
// For eBPF programs of type BPF_PROG_TYPE_SCHED_ACT the returned code defines the action that
77+
// will be applied to the network packet. Returning 0 translates to TC_ACT_OK and will terminate
78+
// the packet processing pipeline within netlink/tc and allows the packet to proceed.
79+
spec := ebpf.ProgramSpec{
80+
Name: "matchAll",
81+
Type: ebpf.SchedACT,
82+
Instructions: asm.Instructions{
83+
// Set exit code to 0
84+
asm.Mov.Imm(asm.R0, 0),
85+
asm.Return(),
86+
},
87+
License: "GPL",
88+
}
89+
90+
// Load the eBPF program into the kernel.
91+
prog, err := ebpf.NewProgram(&spec)
92+
if err != nil {
93+
fmt.Fprintf(os.Stderr, "failed to load eBPF program: %v\n", err)
94+
return
95+
}
96+
97+
// Create a qdisc/ingress object.
98+
qdisc := tc.Object{
99+
Msg: tc.Msg{
100+
Family: unix.AF_UNSPEC,
101+
Ifindex: uint32(devID.Index),
102+
Handle: core.BuildHandle(tc.HandleRoot, 0x0),
103+
Parent: tc.HandleIngress,
104+
},
105+
Attribute: tc.Attribute{
106+
Kind: "ingress",
107+
},
108+
}
109+
// Attach the qdisc/ingress to the networking interface.
110+
if err := tcnl.Qdisc().Add(&qdisc); err != nil {
111+
fmt.Fprintf(os.Stderr, "could not assign clsact to %s: %v\n", tcIface, err)
112+
return
113+
}
114+
// When deleting the qdisc, the applied filter will also be gone
115+
defer func() {
116+
if err := tcnl.Qdisc().Delete(&qdisc); err != nil {
117+
fmt.Fprintf(os.Stderr, "failed to delete qdisc: %v\n", err)
118+
}
119+
}()
120+
121+
fd := uint32(prog.FD())
122+
eBpfActionIndex := uint32(73) // Arbitrary ID to reference the bpf action.
123+
124+
// Create a filter/matchall object.
125+
filter := tc.Object{
126+
Msg: tc.Msg{
127+
Family: unix.AF_UNSPEC,
128+
Ifindex: uint32(devID.Index),
129+
Info: core.FilterInfo(0, unix.ETH_P_ALL),
130+
Parent: tc.HandleIngress + 1,
131+
},
132+
Attribute: tc.Attribute{
133+
Kind: "matchall",
134+
Matchall: &tc.Matchall{
135+
Actions: &[]*tc.Action{
136+
{
137+
Kind: "bpf",
138+
Bpf: &tc.ActBpf{
139+
Parms: &tc.ActBpfParms{
140+
Index: eBpfActionIndex,
141+
},
142+
FD: &fd,
143+
},
144+
},
145+
},
146+
},
147+
},
148+
}
149+
150+
// Load and attach the filter object to the ingress path of the interface.
151+
if err := tcnl.Filter().Add(&filter); err != nil {
152+
fmt.Fprintf(os.Stderr, "failed to attach matchall filter: %v\n", err)
153+
return
154+
}
155+
}

0 commit comments

Comments
 (0)