Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tools: Add libbpf tag gen tool #70

Merged
merged 4 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .aspell.en.pws
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,4 @@ GID
decl
inlining
backend
programmatically
18 changes: 12 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,28 +51,34 @@ serve:
-w /docs -e "AS_USER=$$(id -u $${USER})" -e "AS_GROUP=$$(id -g $${USER})" \
"${IMAGE}:${VERSION}" "mkdocs serve -a 0.0.0.0:8000 --watch /docs/docs"

.PHONY: build-tools
build-tools:
.PHONY: build-spellcheck
build-spellcheck:
${CONTAINER_ENGINE} run --rm -v "${REPODIR}:/docs" -w /docs golang:latest bash -c \
"CGO_ENABLED=0 go build -buildvcs=false -o /docs/tools/bin/spellcheck /docs/tools/spellcheck/. && \
"CGO_ENABLED=0 go build -buildvcs=false -o /docs/tools/bin/spellcheck /docs/tools/spellcheck/."

.PHONY: build-gen-tools
build-gen-tools:
${CONTAINER_ENGINE} run --rm -v "${REPODIR}:/docs" -w /docs golang:latest bash -c \
"CGO_ENABLED=0 go build -buildvcs=false -o /docs/tools/bin/libbpf-tag-gen /docs/tools/libbpf-tag-gen/. && \
CGO_ENABLED=0 go build -buildvcs=false -o /docs/tools/bin/helper-ref-gen /docs/tools/helper-ref-gen/. && \
CGO_ENABLED=0 go build -buildvcs=false -o /docs/tools/bin/feature-tag-gen /docs/tools/feature-tag-gen/. && \
CGO_ENABLED=0 go build -buildvcs=false -o /docs/tools/bin/kfunc-gen /docs/tools/spellcheck/. && \
CGO_ENABLED=0 go build -buildvcs=false -o /docs/tools/bin/kfunc-gen /docs/tools/kfunc-gen/. && \
CGO_ENABLED=0 go build -buildvcs=false -o /docs/tools/bin/mtu-calc /docs/tools/mtu-calc/. && \
CGO_ENABLED=0 go build -buildvcs=false -o /docs/tools/bin/helper-def-scraper /docs/tools/helper-def-scraper/."

.PHONY: generate-docs
generate-docs: build-tools
generate-docs: build-gen-tools
${CONTAINER_ENGINE} run --rm -v "${REPODIR}:/docs" \
-w /docs -e "AS_USER=$$(id -u $${USER})" -e "AS_GROUP=$$(id -g $${USER})" "${IMAGE}:${VERSION}" \
"/docs/tools/bin/helper-ref-gen --project-root /docs && \
/docs/tools/bin/libbpf-tag-gen --project-root /docs && \
/docs/tools/bin/feature-tag-gen --project-root /docs && \
/docs/tools/bin/kfunc-gen --project-root /docs && \
/docs/tools/bin/mtu-calc --project-root /docs && \
/docs/tools/bin/helper-def-scraper --helper-path /docs/docs/linux/helper-function"

.PHONY: spellcheck
spellcheck: build-tools html
spellcheck: build-spellcheck html
${CONTAINER_ENGINE} run --rm -v "${REPODIR}:/docs" \
-w /docs -e "AS_USER=$$(id -u $${USER})" -e "AS_GROUP=$$(id -g $${USER})" "${IMAGE}:${VERSION}" \
"/docs/tools/bin/spellcheck --project-root /docs"
2 changes: 1 addition & 1 deletion docs/ebpf-library/libbpf/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
* [`index.md`](index.md)
* [Userspace](userspace/index.md)
* [Userspace](userspace/)
* [eBPF side](ebpf/index.md)
* [Concepts](concepts/index.md)
5 changes: 5 additions & 0 deletions docs/ebpf-library/libbpf/userspace/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- [index](index.md)
- Misc libbpf functions
- [`libbpf_major_version`](libbpf_major_version.md)
- [`libbpf_minor_version`](libbpf_minor_version.md)
- [`libbpf_strerror`](libbpf_strerror.md)
38 changes: 19 additions & 19 deletions docs/ebpf-library/libbpf/userspace/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,6 @@ Definitions for the libbpf userspace library are split across a few different he

In the `libbpf.h` header file you will find the high level APIs which do a lot of work for you under the hood. These are the most commonly used APIs.

* `libbpf_major_version`
* `libbpf_minor_version`
* `libbpf_version_string`
* `libbpf_strerror`
* `libbpf_bpf_attach_type_str`
* `libbpf_bpf_link_type_str`
* `libbpf_bpf_map_type_str`
* `libbpf_bpf_prog_type_str`
* `libbpf_set_print`
* `libbpf_prog_type_by_name`
* `libbpf_attach_type_by_name`
* `libbpf_find_vmlinux_btf_id`
* `libbpf_probe_bpf_prog_type`
* `libbpf_probe_bpf_map_type`
* `libbpf_probe_bpf_helper`
* `libbpf_num_possible_cpus`
* `libbpf_register_prog_handler`
* `libbpf_unregister_prog_handler`
* BPF Object functions
* `bpf_object__open`
* `bpf_object__open_file`
Expand Down Expand Up @@ -221,6 +203,25 @@ In the `libbpf.h` header file you will find the high level APIs which do a lot o
* `bpf_linker__add_file`
* `bpf_linker__finalize`
* `bpf_linker__free`
* Misc libbpf functions
* [`libbpf_major_version`](libbpf_major_version.md)
* [`libbpf_minor_version`](libbpf_minor_version.md)
* `libbpf_version_string`
* [`libbpf_strerror`](libbpf_strerror.md)
* `libbpf_bpf_attach_type_str`
* `libbpf_bpf_link_type_str`
* `libbpf_bpf_map_type_str`
* `libbpf_bpf_prog_type_str`
* `libbpf_set_print`
* `libbpf_prog_type_by_name`
* `libbpf_attach_type_by_name`
* `libbpf_find_vmlinux_btf_id`
* `libbpf_probe_bpf_prog_type`
* `libbpf_probe_bpf_map_type`
* `libbpf_probe_bpf_helper`
* `libbpf_num_possible_cpus`
* `libbpf_register_prog_handler`
* `libbpf_unregister_prog_handler`

## BTF APIs

Expand Down Expand Up @@ -359,7 +360,6 @@ In the `bpf.h` header file you will find the low level APIs which are used to in
* `bpf_raw_tracepoint_open`
* `bpf_task_fd_query`
* `bpf_enable_stats`
* `bpf_enable_stats`
* `bpf_prog_bind_map`
* `bpf_prog_test_run_opts`
* `bpf_token_create`
Expand Down
22 changes: 22 additions & 0 deletions docs/ebpf-library/libbpf/userspace/libbpf_major_version.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: "Libbpf userspace function 'libbpf_major_version'"
description: "This page documents the 'libbpf_major_version' libbpf userspace function, including its definition, usage, and examples."
---
# Libbpf userspace function `libbpf_major_version`

<!-- [LIBBPF_TAG] -->
[:octicons-tag-24: 0.6.0](https://github.com/libbpf/libbpf/releases/tag/v0.6.0)
<!-- [/LIBBPF_TAG] -->

## Definition

`#!c __u32 libbpf_major_version(void)`

## Usage

This function returns the minor version of the libbpf library programmatically. Especially useful when dynamically linking against libbpf.

### Example

!!! example "Docs could be improved"
This part of the docs is incomplete, contributions are very welcome
22 changes: 22 additions & 0 deletions docs/ebpf-library/libbpf/userspace/libbpf_minor_version.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: "Libbpf userspace function 'libbpf_minor_version'"
description: "This page documents the 'libbpf_minor_version' libbpf userspace function, including its definition, usage, and examples."
---
# Libbpf userspace function `libbpf_minor_version`

<!-- [LIBBPF_TAG] -->
[:octicons-tag-24: 0.6.0](https://github.com/libbpf/libbpf/releases/tag/v0.6.0)
<!-- [/LIBBPF_TAG] -->

## Definition

`#!c __u32 libbpf_minor_version(void)`

## Usage

This function returns the minor version of the libbpf library programmatically. Especially useful when dynamically linking against libbpf.

### Example

!!! example "Docs could be improved"
This part of the docs is incomplete, contributions are very welcome
30 changes: 30 additions & 0 deletions docs/ebpf-library/libbpf/userspace/libbpf_strerror.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
title: "Libbpf userspace function 'libbpf_strerror'"
description: "This page documents the 'libbpf_strerror' libbpf userspace function, including its definition, usage, and examples."
---
# Libbpf userspace function `libbpf_strerror`

<!-- [LIBBPF_TAG] -->
[:octicons-tag-24: 0.0.1](https://github.com/libbpf/libbpf/releases/tag/v0.0.1)
<!-- [/LIBBPF_TAG] -->

Convert an error code into a human-readable string.

## Definition

`#!c int libbpf_strerror(int err, char *buf, size_t size)`

`err` - error code to convert into a string

`buf` - buffer to store the string

`size` - size of the buffer

## Usage

This function converts an error code into a human-readable string. It is useful for debugging and logging purposes.

### Example

!!! example "Docs could be improved"
This part of the docs is incomplete, contributions are very welcome
2 changes: 1 addition & 1 deletion docs/linux/helper-function/bpf_get_smp_processor_id.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Get the SMP (symmetric multiprocessing) processor id. Note that all programs run

The SMP id of the processor running the program.

`#!c static __u32 (* const bpf_get_smp_processor_id)(void) = (void *) 8;`
`#!c static __bpf_fastcall __u32 (* const bpf_get_smp_processor_id)(void) = (void *) 8;`
<!-- [/HELPER_FUNC_DEF] -->

## Usage
Expand Down
4 changes: 2 additions & 2 deletions docs/linux/helper-function/bpf_kptr_xchg.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ description: "This page documents the 'bpf_kptr_xchg' eBPF helper function, incl


<!-- [HELPER_FUNC_DEF] -->
Exchange kptr at pointer _map_value_ with _ptr_, and return the old value. _ptr_ can be NULL, otherwise it must be a referenced pointer which will be released when this helper is called.
Exchange kptr at pointer _dst_ with _ptr_, and return the old value. _dst_ can be map value or local kptr. _ptr_ can be NULL, otherwise it must be a referenced pointer which will be released when this helper is called.

### Returns

The old value of kptr (which can be NULL). The returned pointer if not NULL, is a reference which must be released using its corresponding release function, or moved into a BPF map before program exit.

`#!c static void *(* const bpf_kptr_xchg)(void *map_value, void *ptr) = (void *) 194;`
`#!c static void *(* const bpf_kptr_xchg)(void *dst, void *ptr) = (void *) 194;`
<!-- [/HELPER_FUNC_DEF] -->

## Usage
Expand Down
2 changes: 1 addition & 1 deletion docs/linux/helper-function/bpf_loop.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ description: "This page documents the 'bpf_loop' eBPF helper function, including
<!-- [HELPER_FUNC_DEF] -->
For **nr_loops**, call **callback_fn** function with **callback_ctx** as the context parameter. The **callback_fn** should be a static function and the **callback_ctx** should be a pointer to the stack. The **flags** is used to control certain aspects of the helper. Currently, the **flags** must be 0. Currently, nr_loops is limited to 1 << 23 (~8 million) loops.

long (\_callback_fn)(u32 index, void \_ctx);
long (\_callback_fn)(u64 index, void \_ctx);

where **index** is the current index in the loop. The index is zero-indexed.

Expand Down
2 changes: 0 additions & 2 deletions docs/linux/helper-function/bpf_override_return.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ This helper works by setting the PC (program counter) to an override function wh

This helper has security implications, and thus is subject to restrictions. It is only available if the kernel was compiled with the **CONFIG_BPF_KPROBE_OVERRIDE** configuration option, and in this case it only works on functions tagged with **ALLOW_ERROR_INJECTION** in the kernel code.

Also, the helper is only available for the architectures having the CONFIG_FUNCTION_ERROR_INJECTION option. As of this writing, x86 architecture is the only one to support this feature.

### Returns

0
Expand Down
2 changes: 1 addition & 1 deletion docs/linux/helper-function/bpf_setsockopt.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ This helper actually implements a subset of **setsockopt()**. It supports the fo

* **SOL_SOCKET**, which supports the following _optname_s:
**SO_RCVBUF**, **SO_SNDBUF**, **SO_MAX_PACING_RATE**, **SO_PRIORITY**, **SO_RCVLOWAT**, **SO_MARK**, **SO_BINDTODEVICE**, **SO_KEEPALIVE**, **SO_REUSEADDR**, **SO_REUSEPORT**, **SO_BINDTOIFINDEX**, **SO_TXREHASH**. * **IPPROTO_TCP**, which supports the following _optname_s:
**TCP_CONGESTION**, **TCP_BPF_IW**, **TCP_BPF_SNDCWND_CLAMP**, **TCP_SAVE_SYN**, **TCP_KEEPIDLE**, **TCP_KEEPINTVL**, **TCP_KEEPCNT**, **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**, **TCP_NODELAY**, **TCP_MAXSEG**, **TCP_WINDOW_CLAMP**, **TCP_THIN_LINEAR_TIMEOUTS**, **TCP_BPF_DELACK_MAX**, **TCP_BPF_RTO_MIN**. * **IPPROTO_IP**, which supports _optname_ **IP_TOS**.
**TCP_CONGESTION**, **TCP_BPF_IW**, **TCP_BPF_SNDCWND_CLAMP**, **TCP_SAVE_SYN**, **TCP_KEEPIDLE**, **TCP_KEEPINTVL**, **TCP_KEEPCNT**, **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**, **TCP_NODELAY**, **TCP_MAXSEG**, **TCP_WINDOW_CLAMP**, **TCP_THIN_LINEAR_TIMEOUTS**, **TCP_BPF_DELACK_MAX**, **TCP_BPF_RTO_MIN**, **TCP_BPF_SOCK_OPS_CB_FLAGS**. * **IPPROTO_IP**, which supports _optname_ **IP_TOS**.
* **IPPROTO_IPV6**, which supports the following _optname_s:
**IPV6_TCLASS**, **IPV6_AUTOFLOWLABEL**.

Expand Down
153 changes: 153 additions & 0 deletions tools/libbpf-tag-gen/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package main

import (
"bufio"
"flag"
"fmt"
"io"
"net/http"
"os"
"path"
"strings"
)

var projectroot = flag.String("project-root", "", "Root of the project")

const libbpfMapURL = "https://raw.githubusercontent.com/libbpf/libbpf/refs/heads/master/src/libbpf.map"

const (
LIBBPF_TAG_START = "<!-- [LIBBPF_TAG] -->"
LIBBPF_TAG_END = "<!-- [/LIBBPF_TAG] -->"
)

func main() {
flag.Parse()
if *projectroot == "" {
panic("project-root is required")
}

resp, err := http.Get(libbpfMapURL)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to download libbpf.map: %v\n", err)
os.Exit(1)
}

defer resp.Body.Close()
funcToTag, err := parseLibbpfMap(resp.Body)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to parse libbpf.map: %v\n", err)
os.Exit(1)
}

dirPath := path.Join(*projectroot, "docs", "ebpf-library", "libbpf", "userspace")
dirEntries, err := os.ReadDir(dirPath)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to read directory: %v\n", err)
os.Exit(1)
}

for _, entry := range dirEntries {
if entry.IsDir() {
continue
}
if !strings.HasSuffix(entry.Name(), ".md") {
continue
}

entrypath := path.Join([]string{*projectroot, "docs", "ebpf-library", "libbpf", "userspace", entry.Name()}...)
file, err := os.OpenFile(entrypath, os.O_RDWR, 0644)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to open file: %v\n", err)
continue
}

fileContents, err := io.ReadAll(file)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to read file: %v\n", err)
continue
}

funcName := strings.TrimSuffix(entry.Name(), ".md")
tag, ok := funcToTag[funcName]
if !ok {
fmt.Fprintf(os.Stderr, "Function %s not found in libbpf.map\n", funcName)
continue
}

fileStr := string(fileContents)
startIndex := strings.Index(fileStr, LIBBPF_TAG_START)
endIndex := strings.Index(fileStr, LIBBPF_TAG_END)

if startIndex == -1 || endIndex == -1 {
fmt.Fprintf(os.Stderr, "Skipping, can not find tag markers in file '%s'\n", entry.Name())
continue
}

var newFile strings.Builder
// Write everything before the marker
newFile.WriteString(fileStr[:startIndex])
newFile.WriteString(LIBBPF_TAG_START)
fmt.Fprintf(&newFile, "\n[:octicons-tag-24: %s](https://github.com/libbpf/libbpf/releases/tag/v%s)\n", tag, tag)
newFile.WriteString(LIBBPF_TAG_END)
newFile.WriteString(fileStr[endIndex+len(LIBBPF_TAG_END):])

_, err = file.Seek(0, 0)
if err != nil {
panic(err)
}

err = file.Truncate(0)
if err != nil {
panic(err)
}

_, err = io.Copy(file, strings.NewReader(newFile.String()))
if err != nil {
panic(err)
}
file.Close()
}
}

func parseLibbpfMap(body io.Reader) (map[string]string, error) {
scan := bufio.NewScanner(body)
funcToTag := make(map[string]string)

for scan.Scan() {
line := scan.Text()
if strings.HasPrefix(strings.TrimSpace(line), "LIBBPF_") {
if err := parseBlock(scan, funcToTag); err != nil {
return nil, err
}
}
}

return funcToTag, nil
}

func parseBlock(scan *bufio.Scanner, funcToTag map[string]string) error {
line := scan.Text()
bareLine := strings.TrimSpace(line)
fields := strings.Fields(bareLine)
if len(fields) == 0 {
return nil
}

tag := strings.TrimPrefix(fields[0], "LIBBPF_")

for scan.Scan() {
line := scan.Text()
bareLine := strings.TrimSpace(line)
if strings.HasPrefix(bareLine, "}") {
break
}

if strings.HasSuffix(bareLine, ":") {
continue
}

funcToTag[bareLine[:len(bareLine)-1]] = tag
}

return nil
}
Loading
Loading