lizrice / lb-from-scratch

A very basic eBPF Load Balancer in a few lines of C
GNU General Public License v3.0
311 stars 54 forks source link

Function abnormality after loading xdp through cilium/ebpf library #4

Open Zhouchaowen opened 1 year ago

Zhouchaowen commented 1 year ago

Kernel:Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-84-generic x86_64)

Hi lizrice, I'm having some trouble loading xdp_lb. Loading the xdp program to eth0 of the lizrice/ubuntu-ebpf-lb container through the makefile script you provided can run perfectly, but when I load it through the cilium/ebpf library, it can be loaded successfully, and there is debugging information when accessing lb through the client, but Load balancing cannot be achieved. After capturing packets from backend-A/B, I found that there is only the IP information of the data packet from client to lb.

I guess the modification of the destination address and source address was unsuccessful, but judging from the debug information, the modification was successful. Can you help me take a look? The following is the loading code:

package main

import (
    "bufio"
    "context"
    "flag"
    "github.com/cilium/ebpf/link"
    "io"
    "log"
    "net"
    "os"
    "os/signal"
    "syscall"
)

// $BPF_CLANG and $BPF_CFLAGS are set by the Makefile.
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf lb4.c -- -I../../headers -Ilb4.h

var (
    InterfaceName string
)

func init() {
    flag.StringVar(&InterfaceName, "n", "lo", "a network interface name")
}

func main() {
    flag.Parse()

    if len(InterfaceName) == 0 {
        log.Fatalf("Please specify a network interface")
    }
    // Look up the network interface by name.
    iface, err := net.InterfaceByName(InterfaceName)
    if err != nil {
        log.Fatalf("lookup network iface %s: %s", InterfaceName, err)
    }

    // Load pre-compiled programs into the kernel.
    objs := bpfObjects{}
    if err := loadBpfObjects(&objs, nil); err != nil {
        log.Fatalf("loading objects: %s", err)
    }
    defer objs.Close()

    // Attach the program.
    l, err := link.AttachXDP(link.XDPOptions{
        Program:   objs.XdpLoadBalancer,
        Interface: iface.Index,
    })
    if err != nil {
        log.Fatalf("could not attach XDP program: %s", err)
    }
    defer l.Close()

    log.Printf("Attached XDP program to iface %q (index %d)", iface.Name, iface.Index)
    log.Printf("Press Ctrl-C to exit and remove the program")
    log.Printf("Successfully started! Please run \"sudo cat /sys/kernel/debug/tracing/trace_pipe\" to see output of the BPF programs\n")

    // Wait for a signal and close the XDP program,
    stopper := make(chan os.Signal, 1)
    signal.Notify(stopper, os.Interrupt, syscall.SIGTERM)

    cxt, cancel := context.WithCancel(context.Background())
    go func(cxt context.Context) {
        f, err := os.Open("/sys/kernel/debug/tracing/trace_pipe")
        if err != nil {
            log.Panicf("open file failed, %v", err)
        }
        defer f.Close()

        r := bufio.NewReader(f)
        for {
            select {
            case <-cxt.Done():
                return
            default:
                // ReadLine is a low-level line-reading primitive.
                // Most callers should use ReadBytes('\n') or ReadString('\n') instead or use a Scanner.
                bytes, _, err := r.ReadLine()
                if err == io.EOF {
                    break
                }
                if err != nil {
                    panic(err)
                }
                log.Println(string(bytes))
            }
        }
    }(cxt)

    <-stopper
    cancel()
    log.Println("Received signal, exiting XDP program..")
}

Complete project address :https://github.com/Zhouchaowen/ebpf_labs/blob/master/xdp/lb4/main.go