Skip to content

Commit c20a334

Browse files
authored
examples: add tcx example
This example shows how to load an eBPF program that counts incoming and outgoing packets. Signed-off-by: Simone Magnani <[email protected]>
1 parent c959fd7 commit c20a334

File tree

8 files changed

+410
-0
lines changed

8 files changed

+410
-0
lines changed

examples/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Please see our [guide on what makes a good example](https://ebpf-go.dev/contribu
1919
Like kprobes, but with better performance and usability, for kernels 5.5 and later.
2020
* [tcp_connect](fentry/) - Trace outgoing IPv4 TCP connections.
2121
* [tcp_close](tcprtt/) - Log RTT of IPv4 TCP connections using eBPF CO-RE helpers.
22+
* TCx - Attach a program to Linux TC (Traffic Control) to process incoming and outgoing packets.
23+
* [tcx](./tcx/) - Print packet counts for ingress and egress.
2224
* XDP - Attach a program to a network interface to process incoming packets.
2325
* [xdp](xdp/) - Print packet counts by IPv4 source address.
2426

examples/headers/common.h

+13
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,19 @@ enum xdp_action {
6464
XDP_REDIRECT = 4,
6565
};
6666

67+
enum tc_action {
68+
TC_ACT_UNSPEC = -1,
69+
TC_ACT_OK = 0,
70+
TC_ACT_RECLASSIFY = 1,
71+
TC_ACT_SHOT = 2,
72+
TC_ACT_PIPE = 3,
73+
TC_ACT_STOLEN = 4,
74+
TC_ACT_QUEUED = 5,
75+
TC_ACT_REPEAT = 6,
76+
TC_ACT_REDIRECT = 7,
77+
TC_ACT_JUMP = 0x10000000
78+
};
79+
6780
struct xdp_md {
6881
__u32 data;
6982
__u32 data_end;

examples/tcx/bpf_bpfeb.go

+125
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/tcx/bpf_bpfeb.o

3.15 KB
Binary file not shown.

examples/tcx/bpf_bpfel.go

+125
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/tcx/bpf_bpfel.o

3.15 KB
Binary file not shown.

examples/tcx/main.go

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// This program demonstrates attaching an eBPF program to a network interface
2+
// with Linux TC (Traffic Control). The program counts ingress and egress
3+
// packets using two ARRAY maps.
4+
// The userspace program (Go code in this file) prints the contents
5+
// of the two maps to stdout every second.
6+
// This example depends on tcx bpf_link, available in Linux kernel version 6.6 or newer.
7+
package main
8+
9+
import (
10+
"fmt"
11+
"log"
12+
"net"
13+
"os"
14+
"time"
15+
16+
"github.com/cilium/ebpf"
17+
"github.com/cilium/ebpf/link"
18+
)
19+
20+
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go bpf tcx.c -- -I../headers
21+
func main() {
22+
if len(os.Args) < 2 {
23+
log.Fatalf("Please specify a network interface")
24+
}
25+
26+
// Look up the network interface by name.
27+
ifaceName := os.Args[1]
28+
iface, err := net.InterfaceByName(ifaceName)
29+
if err != nil {
30+
log.Fatalf("lookup network iface %q: %s", ifaceName, err)
31+
}
32+
33+
// Load pre-compiled programs into the kernel.
34+
objs := bpfObjects{}
35+
if err := loadBpfObjects(&objs, nil); err != nil {
36+
log.Fatalf("loading objects: %s", err)
37+
}
38+
defer objs.Close()
39+
40+
// Attach the program to Ingress TC.
41+
l, err := link.AttachTCX(link.TCXOptions{
42+
Interface: iface.Index,
43+
Program: objs.IngressProgFunc,
44+
Attach: ebpf.AttachTCXIngress,
45+
})
46+
if err != nil {
47+
log.Fatalf("could not attach TCx program: %s", err)
48+
}
49+
defer l.Close()
50+
51+
log.Printf("Attached TCx program to INGRESS iface %q (index %d)", iface.Name, iface.Index)
52+
53+
// Attach the program to Egress TC.
54+
l2, err := link.AttachTCX(link.TCXOptions{
55+
Interface: iface.Index,
56+
Program: objs.EgressProgFunc,
57+
Attach: ebpf.AttachTCXEgress,
58+
})
59+
if err != nil {
60+
log.Fatalf("could not attach TCx program: %s", err)
61+
}
62+
defer l2.Close()
63+
64+
log.Printf("Attached TCx program to EGRESS iface %q (index %d)", iface.Name, iface.Index)
65+
log.Printf("Press Ctrl-C to exit and remove the program")
66+
67+
// Print the contents of the counters maps.
68+
ticker := time.NewTicker(1 * time.Second)
69+
defer ticker.Stop()
70+
for range ticker.C {
71+
s, err := formatCounters(objs.IngressPktCount, objs.EgressPktCount)
72+
if err != nil {
73+
log.Printf("Error reading map: %s", err)
74+
continue
75+
}
76+
77+
log.Printf("Packet Count: %s\n", s)
78+
}
79+
}
80+
81+
func formatCounters(ingressMap, egressMap *ebpf.Map) (string, error) {
82+
var (
83+
ingressPacketCount uint64
84+
egressPacketCount uint64
85+
key int32
86+
)
87+
88+
// retrieve value from the ingress map
89+
if err := ingressMap.Lookup(&key, &ingressPacketCount); err != nil {
90+
return "", err
91+
}
92+
93+
// retrieve value from the egress map
94+
if err := egressMap.Lookup(&key, &egressPacketCount); err != nil {
95+
return "", err
96+
}
97+
98+
return fmt.Sprintf("%10v Ingress, %10v Egress", ingressPacketCount, egressPacketCount), nil
99+
}

0 commit comments

Comments
 (0)