github.com/cilium/ebpf@v0.16.0/examples/tcx/main.go (about)

     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  }