Search code examples
goebpfxdp-bpf

Unable to unload BPF program


I am unable to unload a BPF program from code. I am using the Cilium eBPF library to load the program and netlink to add the BPF function to an interface. Here's what I'm doing:

type BpfObjects struct {
    CollectIpsProg *ebpf.Program        `ebpf:"collect_ips_prog"`
}

    var objects BpfObjects

    // Load the BPF program
    spec, err := ebpf.LoadCollectionSpec("collect_ips.o")

    if err != nil {
        log.Fatalln("ebpf.LoadCollectionSpec", err)
    }

    if err := spec.LoadAndAssign(objects, nil); err != nil {
        log.Fatalln("ebpf.LoadAndAssign", err)
    }

    // Load to XDP
    link, err := netlink.LinkByName("enp0s8")

    if err != nil {
        log.Fatalln("netlink.LinkByName", err)
    }

    err = netlink.LinkSetXdpFdWithFlags(link, objects.CollectIpsProg.FD(), 2)

    if err != nil {
        log.Fatalln("netlink.LinkSetXdpFdWithFlags:", err)
    }
    ...

    // Cleanup. This does not unload the BPF program
    objects.CollectIpsProg.Close()
    objects.CollectIpsProg.Unpin() 

Even though I am closing the program, bpftool prog and xdp-loader status still show the BPF program. I can unload the program using bpftool or xdp-loader.


Solution

  • eBPF programs only unload when there are no more references to it(File descriptors, pins), but network links also hold their own references. So to unload the program, you first have to detach it from your network link.

    You can do so by setting the program fd to -1:

    err = netlink.LinkSetXdpFd(link, -1)
    if err != nil {
        log.Fatalln("netlink.LinkSetXdpFd:", err)
    }