Skip to content

Commit

Permalink
init(trafficManager): initialize basic development framework
Browse files Browse the repository at this point in the history
  • Loading branch information
ESWZY committed Jul 14, 2023
1 parent f6a9767 commit ea96c8a
Show file tree
Hide file tree
Showing 10 changed files with 371 additions and 0 deletions.
85 changes: 85 additions & 0 deletions .github/workflows/net_traffic_manager.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Traffic Manager

on:
push:
branches:
- "*"
paths:
- 'eBPF_Supermarket/TrafficManager/**'
- '.github/workflows/net_traffic_manager.yml'
pull_request:
branches:
- "*"
paths:
- 'eBPF_Supermarket/TrafficManager/**'
- '.github/workflows/net_traffic_manager.yml'

jobs:
build-and-test:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3

- name: Cache bpftool build directory
id: cache-bpftool
uses: actions/cache@v3
with:
path: bpftool
key: ${{ runner.os }}-bpftool

# - name: Cache go pkg directory
# id: cache-go
# uses: actions/cache@v3
# with:
# path: ${{ GOPATH }}
# key: ${{ runner.os }}-go

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version-file: eBPF_Supermarket/TrafficManager/go.mod
cache-dependency-path: eBPF_Supermarket/TrafficManager/go.sum

# - name: Install Docker
# run: |
# sudo snap refresh
# sudo snap install docker

# - name: Install Minikube
# run: |
# sudo snap install kubectl --classic
# curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
# sudo install minikube-linux-amd64 /usr/local/bin/minikube
# sudo minikube start --kubernetes-version=1.26.6 --force

- name: Install eBPF development tools
run: |
sudo apt install -y llvm clang
- name: Build bpftool
if: steps.cache-bpftool.outputs.cache-hit != 'false'
run: |
rm -rf bpftool/
sudo apt install libbfd-dev libcap-dev libelf-dev
git clone --recurse-submodules https://github.com/libbpf/bpftool.git
sudo make install -C bpftool/src/
- name: Install bpftool
run: |
sudo cp bpftool/src/bpftool /usr/bin/
- name: Load Dependency
run: |
cd eBPF_Supermarket/TrafficManager/
sudo go mod tidy
- name: Build
run: |
cd eBPF_Supermarket/TrafficManager/
sudo make init
sudo make build
- name: Run
run: |
cd eBPF_Supermarket/TrafficManager/
sudo -E timeout 10 ./main || if [[ $? != 124 && $? != 0 ]]; then exit $?; fi
9 changes: 9 additions & 0 deletions eBPF_Supermarket/TrafficManager/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.idea
.vscode

bpf/headers/vmlinux.h

bpf/headers/bpf/*
!bpf/headers/bpf/update.sh

*.o
33 changes: 33 additions & 0 deletions eBPF_Supermarket/TrafficManager/INSTALL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Install tutorial

## Ubuntu 22.04

```bash
# Install Go
wget https://go.dev/dl/go1.20.5.linux-amd64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.5.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin

# Install Docker
sudo snap refresh
sudo snap install docker

# Install and start local Kubernetes
sudo snap install kubectl --classic
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
sudo minikube start --kubernetes-version=1.26.6 --force

# Install eBPF development tools
sudo apt install -y llvm clang
sudo apt install libbfd-dev libcap-dev libelf-dev
git clone --recurse-submodules https://github.com/libbpf/bpftool.git
sudo make install -C bpftool/src/
sudo cp bpftool/src/bpftool /usr/bin/
sudo rm -rf bpftool/
```

```bash
sudo make init
sudo make
```
13 changes: 13 additions & 0 deletions eBPF_Supermarket/TrafficManager/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.DEFAULT_GOAL := all

all: build
sudo ./main

build:
cd bpf; go generate;
go build -o main main.go

init:
cd bpf/headers/bpf/; ./update.sh
cd bpf/headers/; bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
cd bpf; go generate;
39 changes: 39 additions & 0 deletions eBPF_Supermarket/TrafficManager/bpf/connect.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// +build ignore

#include "connect.h"

const __be32 service_ip = 0x846F070A; // 10.7.111.132
const __be32 pod_ip = 0x0100007F; // 127.0.0.1
const __be16 service_port = 0x5000; // 80 (0x0 * 256 + 0x50)
const __be16 pod_port = 0x901f; // 8080 (0x1f * 256 + 0x144)

static int sock4_forward_entry(struct bpf_sock_addr *ctx)
{
__be32 ori_dst_ip = ctx_get_dst_ip(ctx);
__be16 ori_dst_port = ctx_get_dst_port(ctx);

bpf_printk("original: %08x:%04x", ori_dst_ip, ori_dst_port);
bpf_printk("service: %08x:%04x", service_ip, service_port);
bpf_printk("pod: %08x:%04x", pod_ip, pod_port);

if(ori_dst_ip == service_ip && ori_dst_port == service_port)
{
bpf_printk("redirect to %08x:%04x", pod_ip, pod_port);
ctx_set_ip(ctx, pod_ip);
ctx_set_port(ctx, pod_port);
}
else
{
bpf_printk("skipped, not modified");
}
return 0;
}

SEC("cgroup/connect4")
int sock4_connect(struct bpf_sock_addr *ctx)
{
sock4_forward_entry(ctx);
return SYS_PROCEED;
}

char _license[] SEC("license") = "GPL";
121 changes: 121 additions & 0 deletions eBPF_Supermarket/TrafficManager/bpf/connect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package bpf

//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang -target bpf -cflags "-D__TARGET_ARCH_x86" bpf_connect connect.c -- -I./headers

import (
"bufio"
"fmt"
"os"
"os/signal"
"strings"

"github.com/cilium/ebpf"
"github.com/cilium/ebpf/link"
"github.com/cilium/ebpf/rlimit"
)

const MapsPinPath = "/sys/fs/bpf/sock_ops_map"

type Programs struct {
connectObj bpf_connectObjects
connectCgroup link.Link
backEndSet map[int]bool
currentIndex int
}

// DetectCgroupPath returns the first-found mount point of type cgroup2
func DetectCgroupPath() (string, error) {
f, err := os.Open("/proc/mounts")
if err != nil {
return "", err
}
defer f.Close()

scanner := bufio.NewScanner(f)
for scanner.Scan() {
// example fields: cgroup2 /sys/fs/cgroup/unified cgroup2 rw,nosuid,nodev,noexec,relatime 0 0
fields := strings.Split(scanner.Text(), " ")
if len(fields) >= 3 && fields[2] == "cgroup2" {
return fields[1], nil
}
}

return "", fmt.Errorf("cgroup2 not mounted")
}

func LoadProgram() (Programs, error) {
var programs Programs
var options ebpf.CollectionOptions
options.Maps.PinPath = MapsPinPath

// Allow the current process to lock memory for eBPF resources.
err := rlimit.RemoveMemlock()
if err != nil {
fmt.Println("[ERROR] Setting limit failed:", err)
return Programs{}, fmt.Errorf("setting limit failed: %s", err)
}

err = os.Mkdir(MapsPinPath, os.ModePerm)
if err != nil {
fmt.Println(err)
}

err = loadBpf_connectObjects(&programs.connectObj, &options)
if err != nil {
return Programs{}, fmt.Errorf("error load objects: %s\n", err)
}

programs.backEndSet = make(map[int]bool)
programs.currentIndex = 0

return programs, err
}

func (p *Programs) Attach() error {
fmt.Println("Socket redirect started!")

cgroupPath, err := DetectCgroupPath()
if err != nil {
return fmt.Errorf("detect cgroup path failed: %s", err)
}

p.connectCgroup, err = link.AttachCgroup(link.CgroupOptions{
Path: cgroupPath,
Attach: ebpf.AttachCGroupInet4Connect,
Program: p.connectObj.bpf_connectPrograms.Sock4Connect,
})
if err != nil {
return fmt.Errorf("error attaching connect to cgroup: %s", err)
}

return nil
}

func (p *Programs) Close() {
fmt.Println("Exiting...")

if p.connectCgroup != nil {
fmt.Printf("Closing connect cgroup...\n")
p.connectCgroup.Close()
}

_ = os.Remove(MapsPinPath)
}

func Sample() {
progs, err := LoadProgram()
if err != nil {
fmt.Println("[ERROR] Loading program failed:", err)
return
}

err = progs.Attach()
if err != nil {
fmt.Println("[ERROR] Attaching failed:", err)
}
defer progs.Close()

c := make(chan os.Signal, 1)
signal.Notify(c)
<-c
}
37 changes: 37 additions & 0 deletions eBPF_Supermarket/TrafficManager/bpf/connect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>

#define SYS_PROCEED 1

// sudo cat /sys/kernel/debug/tracing/trace_pipe

#define print_ip_formatted(ip) \
({ \
bpf_printk("ip1: %d.%d", \
ip%256, (ip/256)%256); \
bpf_printk("ip2: %d.%d\n", \
(ip/65536)%256, (ip/16711680)%256); \
})

static __always_inline __be32 ctx_get_dst_ip(const struct bpf_sock_addr *ctx)
{
volatile __u32 dst_ip = ctx->user_ip4;
return (__be32)dst_ip;
}

static __always_inline __be16 ctx_get_dst_port(const struct bpf_sock_addr *ctx)
{
volatile __u32 dport = ctx->user_port;
return (__be16)dport;
}

static __always_inline void ctx_set_ip(struct bpf_sock_addr *ctx, __be32 dst_ip)
{
ctx->user_ip4 = (__u32)dst_ip;
}

static __always_inline void ctx_set_port(struct bpf_sock_addr *ctx, __be16 dport)
{
ctx->user_port = (__u32)dport;
}
18 changes: 18 additions & 0 deletions eBPF_Supermarket/TrafficManager/bpf/headers/bpf/update.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash

# Version of libbpf to fetch headers from
LIBBPF_VERSION=1.0.0

# The headers we want
prefix=libbpf-"$LIBBPF_VERSION"
headers=(
"$prefix"/LICENSE.BSD-2-Clause
"$prefix"/src/bpf_endian.h
"$prefix"/src/bpf_helper_defs.h
"$prefix"/src/bpf_helpers.h
"$prefix"/src/bpf_tracing.h
)

# Fetch libbpf release and extract the desired headers
curl -sL "https://github.com/libbpf/libbpf/archive/refs/tags/v${LIBBPF_VERSION}.tar.gz" | \
tar -xz --xform='s#.*/##' "${headers[@]}"
7 changes: 7 additions & 0 deletions eBPF_Supermarket/TrafficManager/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module github.com/eswzy/eTrafficManager

go 1.20

require github.com/cilium/ebpf v0.10.0

require golang.org/x/sys v0.7.0 // indirect
9 changes: 9 additions & 0 deletions eBPF_Supermarket/TrafficManager/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package main

import (
"github.com/eswzy/eTrafficManager/bpf"
)

func main() {
bpf.Sample()
}

0 comments on commit ea96c8a

Please sign in to comment.