github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/examples/xdp/main.go (about)

     1  // This program demonstrates attaching an eBPF program to a network interface
     2  // with XDP (eXpress Data Path). The program parses the IPv4 source address
     3  // from packets and writes the packet count by IP to an LRU hash map.
     4  // The userspace program (Go code in this file) prints the contents
     5  // of the map to stdout every second.
     6  // It is possible to modify the XDP program to drop or redirect packets
     7  // as well -- give it a try!
     8  // This example depends on bpf_link, available in Linux kernel version 5.7 or newer.
     9  package main
    10  
    11  import (
    12  	"fmt"
    13  	"log"
    14  	"net"
    15  	"net/netip"
    16  	"os"
    17  	"strings"
    18  	"time"
    19  
    20  	"github.com/cilium/ebpf"
    21  	"github.com/cilium/ebpf/link"
    22  )
    23  
    24  //go:generate go run github.com/cilium/ebpf/cmd/bpf2go bpf xdp.c -- -I../headers
    25  
    26  func main() {
    27  	if len(os.Args) < 2 {
    28  		log.Fatalf("Please specify a network interface")
    29  	}
    30  
    31  	// Look up the network interface by name.
    32  	ifaceName := os.Args[1]
    33  	iface, err := net.InterfaceByName(ifaceName)
    34  	if err != nil {
    35  		log.Fatalf("lookup network iface %q: %s", ifaceName, err)
    36  	}
    37  
    38  	// Load pre-compiled programs into the kernel.
    39  	objs := bpfObjects{}
    40  	if err := loadBpfObjects(&objs, nil); err != nil {
    41  		log.Fatalf("loading objects: %s", err)
    42  	}
    43  	defer objs.Close()
    44  
    45  	// Attach the program.
    46  	l, err := link.AttachXDP(link.XDPOptions{
    47  		Program:   objs.XdpProgFunc,
    48  		Interface: iface.Index,
    49  	})
    50  	if err != nil {
    51  		log.Fatalf("could not attach XDP program: %s", err)
    52  	}
    53  	defer l.Close()
    54  
    55  	log.Printf("Attached XDP program to iface %q (index %d)", iface.Name, iface.Index)
    56  	log.Printf("Press Ctrl-C to exit and remove the program")
    57  
    58  	// Print the contents of the BPF hash map (source IP address -> packet count).
    59  	ticker := time.NewTicker(1 * time.Second)
    60  	defer ticker.Stop()
    61  	for range ticker.C {
    62  		s, err := formatMapContents(objs.XdpStatsMap)
    63  		if err != nil {
    64  			log.Printf("Error reading map: %s", err)
    65  			continue
    66  		}
    67  		log.Printf("Map contents:\n%s", s)
    68  	}
    69  }
    70  
    71  func formatMapContents(m *ebpf.Map) (string, error) {
    72  	var (
    73  		sb  strings.Builder
    74  		key netip.Addr
    75  		val uint32
    76  	)
    77  	iter := m.Iterate()
    78  	for iter.Next(&key, &val) {
    79  		sourceIP := key // IPv4 source address in network byte order.
    80  		packetCount := val
    81  		sb.WriteString(fmt.Sprintf("\t%s => %d\n", sourceIP, packetCount))
    82  	}
    83  	return sb.String(), iter.Err()
    84  }