diff --git a/gotests/main.go b/gotests/main.go index 817e3270..5f8dffa5 100644 --- a/gotests/main.go +++ b/gotests/main.go @@ -37,6 +37,7 @@ const ( netdataEBPFKernel515 = 331520 netdataEBPFKernel516 = 331776 netdataEBPFKernel68 = 395264 + netdataEBPFKernel69 = 395520 netdataEBPFKernel612 = 396288 netdataV310 = 1 << 0 @@ -99,6 +100,7 @@ type specifyName struct { type module struct { kernels uint32 bufferKernels uint32 + arenaKernels uint32 flags uint64 name string updateNames *[]specifyName @@ -116,6 +118,7 @@ type options struct { unitTest bool showHelp bool bufferMode bool + arenaMode bool } type logState struct { @@ -170,6 +173,31 @@ var ( retprobe: false, required: true, }, + { + programName: "netdata_swap_readpage_buffer", + functionToAttach: "swap_read_folio", + fallbackFunction: "swap_readpage", + retprobe: false, + required: true, + }, + { + programName: "netdata_swap_writepage_buffer", + functionToAttach: "__swap_writepage", + fallbackFunction: "swap_writepage", + retprobe: false, + required: true, + }, + } + + // close_fd replaced __close_fd in kernel 5.11; RH backported this rename to their 5.10 kernels. + fdOptionalNames = []specifyName{ + { + programName: "netdata_close_buffer", + functionToAttach: "close_fd", + fallbackFunction: "__close_fd", + retprobe: false, + required: true, + }, } zfsOptionalNames = []specifyName{ @@ -217,11 +245,11 @@ var ( ebpfModules = []module{ {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV510 | netdataV514, flags: flagBtrfs, name: "btrfs", ctrlTable: "btrfs_ctrl"}, - {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV515 | netdataV514 | netdataV516, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagCachestat, name: "cachestat", ctrlTable: "cstat_ctrl"}, - {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagDC, name: "dc", updateNames: &dcOptionalNames, ctrlTable: "dcstat_ctrl"}, + {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV515 | netdataV514 | netdataV516, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, arenaKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagCachestat, name: "cachestat", ctrlTable: "cstat_ctrl"}, + {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, arenaKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagDC, name: "dc", updateNames: &dcOptionalNames, ctrlTable: "dcstat_ctrl"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagDisk, name: "disk", ctrlTable: "disk_ctrl"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagExt4, name: "ext4", ctrlTable: "ext4_ctrl"}, - {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV511 | netdataV514, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagFD, name: "fd", ctrlTable: "fd_ctrl"}, + {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV511 | netdataV514, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, arenaKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagFD, name: "fd", updateNames: &fdOptionalNames, ctrlTable: "fd_ctrl"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagSync, name: "fdatasync"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagSync, name: "fsync"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagHardIRQ, name: "hardirq"}, @@ -229,18 +257,18 @@ var ( {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagMount, name: "mount"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagSync, name: "msync"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagSocket, name: "socket", ctrlTable: "socket_ctrl"}, - {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagDNS, name: "dns"}, + {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, arenaKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagDNS, name: "dns"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagNFS, name: "nfs", ctrlTable: "nfs_ctrl"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagNetworkViewer, name: "network_viewer", ctrlTable: "nv_ctrl"}, - {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagOOMKill, name: "oomkill"}, - {kernels: netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514 | netdataV510 | netdataV612, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagProcess, name: "process", ctrlTable: "process_ctrl"}, - {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagSHM, name: "shm", ctrlTable: "shm_ctrl"}, + {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, arenaKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagOOMKill, name: "oomkill"}, + {kernels: netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514 | netdataV510 | netdataV612, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, arenaKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagProcess, name: "process", ctrlTable: "process_ctrl"}, + {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, arenaKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagSHM, name: "shm", ctrlTable: "shm_ctrl"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagSoftIRQ, name: "softirq"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagSync, name: "sync"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagSync, name: "syncfs"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagSync, name: "sync_file_range"}, - {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514 | netdataV68 | netdataV612, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagSwap, name: "swap", updateNames: &swapOptionalNames, ctrlTable: "swap_ctrl"}, - {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagVFS, name: "vfs", ctrlTable: "vfs_ctrl"}, + {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514 | netdataV68 | netdataV612, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, arenaKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagSwap, name: "swap", updateNames: &swapOptionalNames, ctrlTable: "swap_ctrl"}, + {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, arenaKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagVFS, name: "vfs", ctrlTable: "vfs_ctrl"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagXFS, name: "xfs", ctrlTable: "xfs_ctrl"}, {kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagZFS, name: "zfs", updateNames: &zfsOptionalNames, ctrlTable: "zfs_ctrl"}, } @@ -264,7 +292,7 @@ func run() int { } logger := &logState{writer: os.Stderr} - opts, parseCode := parseArguments(os.Args[1:], kernelVersion, logger) + opts, parseCode := parseArguments(os.Args[1:], kernelVersion, rhfVersion, logger) if logger.file != nil { defer logger.file.Close() } @@ -361,11 +389,51 @@ func parseKernelRelease(version string) int { func getRedHatRelease() int { data, err := os.ReadFile("/etc/redhat-release") + if err == nil { + if result := parseRedHatRelease(string(data)); result != -1 { + return result + } + } + + data, err = os.ReadFile("/etc/os-release") if err != nil { return -1 } + return parseOSRelease(string(data)) +} - return parseRedHatRelease(string(data)) +// parseOSRelease detects RH-family distros from /etc/os-release. +// Matches ID or ID_LIKE containing "rhel", "centos", "almalinux", or "rocky", +// then parses VERSION_ID=X.Y to return X*256+Y. Returns -1 on no match. +func parseOSRelease(content string) int { + major := 0 + minor := 0 + isRHEL := false + + for _, line := range strings.Split(content, "\n") { + if strings.HasPrefix(line, "ID=") || strings.HasPrefix(line, "ID_LIKE=") { + low := strings.ToLower(line) + if strings.Contains(low, "rhel") || strings.Contains(low, "centos") || + strings.Contains(low, "almalinux") || strings.Contains(low, "rocky") { + isRHEL = true + } + } else if strings.HasPrefix(line, "VERSION_ID=") { + val := strings.TrimPrefix(line, "VERSION_ID=") + val = strings.Trim(val, "\"") + parts := strings.SplitN(val, ".", 2) + if len(parts) >= 1 { + major = parseLeadingLong(parts[0]) + } + if len(parts) >= 2 { + minor = parseLeadingLong(parts[1]) + } + } + } + + if isRHEL && major > 0 { + return major*256 + minor + } + return -1 } func parseRedHatRelease(release string) int { @@ -415,7 +483,8 @@ func helpText(exe string) string { "--content Test content stored inside hash tables.\n"+ "--iteration Number of iterations when content is read, default value is 1.\n"+ "--pid Specify the number that identifies PID that will be monitored: 0 - Real Parent PID (Default), 1 - Parent PID, 2 - All PID, and 3 - Ignore PID (ring buffer mode).\n"+ - "--buffer Test ring buffer versions of collectors (cachestat, dc, fd, oomkill, process, shm, swap, vfs, dns).\n\n"+ + "--buffer Test ring buffer versions of collectors (cachestat, dc, fd, oomkill, process, shm, swap, vfs, dns).\n"+ + "--arena Test arena versions of collectors (cachestat, dc, fd, oomkill, process, shm, swap, vfs, dns).\n\n"+ "You can also specify an unique eBPF program developed by Netdata with the following\n"+ "options:\n"+ "--btrfs Latency for btrfs.\n"+ @@ -451,7 +520,7 @@ func setCommonFlag() uint64 { return flagCollectors & ^(flagFS | flagLoadBinary | flagMDFlush | flagContent) } -func parseArguments(args []string, kernelVersion int, logger *logState) (options, int) { +func parseArguments(args []string, kernelVersion int, rhfVersion int, logger *logState) (options, int) { opts := options{ iterations: 1, mapLevel: 0, @@ -525,7 +594,7 @@ func parseArguments(args []string, kernelVersion int, logger *logState) (options case "log-path": value, i = optionValue(args, i, value) opts.logPath = value - file, err := os.OpenFile(value, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o644) + file, err := os.OpenFile(value, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0o644) if err != nil { logger.writer = os.Stderr fmt.Fprintf(logger.writer, "\"Error\": \"Cannot open %s\",\n", value) @@ -554,6 +623,9 @@ func parseArguments(args []string, kernelVersion int, logger *logState) (options case "buffer": opts.bufferMode = true opts.flags |= flagContent + case "arena": + opts.arenaMode = true + opts.flags |= flagContent } } @@ -565,11 +637,16 @@ func parseArguments(args []string, kernelVersion int, logger *logState) (options opts.flags &^= flagOOMKill } - if opts.bufferMode && kernelVersion < netdataEBPFKernel58 { + if opts.bufferMode && rhfVersion == -1 && kernelVersion < netdataEBPFKernel58 { fmt.Fprintf(logger.writer, "\"Error\" : \"Ring buffer support requires kernel >= 5.8, current version is not supported.\",\n") return opts, 1 } + if opts.arenaMode && rhfVersion == -1 && kernelVersion < netdataEBPFKernel69 { + fmt.Fprintf(logger.writer, "\"Error\" : \"Arena support requires kernel >= 6.9, current version is not supported.\",\n") + return opts, 1 + } + return opts, 0 } @@ -637,13 +714,18 @@ func resolveBinaryDir(netdataPath string) string { return netdataPath } -func candidateMatches(filename string, moduleName string, isReturn bool, version string, rhfVersion int, bufferMode bool) bool { - var prefix string +func modeSuffix(bufferMode bool, arenaMode bool) string { + if arenaMode { + return "_arena" + } if bufferMode { - prefix = fmt.Sprintf("%cnetdata_ebpf_%s_buffer.", map[bool]rune{true: 'r', false: 'p'}[isReturn], moduleName) - } else { - prefix = fmt.Sprintf("%cnetdata_ebpf_%s.", map[bool]rune{true: 'r', false: 'p'}[isReturn], moduleName) + return "_buffer" } + return "" +} + +func candidateMatches(filename string, moduleName string, isReturn bool, version string, rhfVersion int, bufferMode bool, arenaMode bool) bool { + prefix := fmt.Sprintf("%cnetdata_ebpf_%s%s.", map[bool]rune{true: 'r', false: 'p'}[isReturn], moduleName, modeSuffix(bufferMode, arenaMode)) if !strings.HasPrefix(filename, prefix) || !strings.HasSuffix(filename, ".o") { return false } @@ -664,7 +746,7 @@ func candidateMatches(filename string, moduleName string, isReturn bool, version return !hasRHF } -func candidateVersionIndex(filename string, moduleName string, isReturn bool, rhfVersion int, kernels uint32, maxIndex uint32, bufferMode bool) int { +func candidateVersionIndex(filename string, moduleName string, isReturn bool, rhfVersion int, kernels uint32, maxIndex uint32, bufferMode bool, arenaMode bool) int { if rhfVersion == -1 { kernels &^= netdataV514 } @@ -673,7 +755,7 @@ func candidateVersionIndex(filename string, moduleName string, isReturn bool, rh if kernels&(1< len(candidate) && data[len(candidate)] != ' ' && data[len(candidate)] != '\t' { + continue + } + end := strings.IndexAny(data, " \n") if end < 0 { end = len(data) @@ -941,6 +1029,21 @@ func moduleHasBuffer(name string) bool { return bufferModules[name] } +func moduleHasArena(name string) bool { + arenaModules := map[string]bool{ + "cachestat": true, + "dc": true, + "fd": true, + "oomkill": true, + "process": true, + "shm": true, + "swap": true, + "vfs": true, + "dns": true, + } + return arenaModules[name] +} + func runNetdataTests(w io.Writer, rhfVersion int, kernelVersion int, isReturn bool, opts options, nprocesses int) { supportedMapTypes := detectSupportedMapTypes(rhfVersion, kernelVersion) @@ -949,17 +1052,23 @@ func runNetdataTests(w io.Writer, rhfVersion int, kernelVersion int, isReturn bo continue } + if opts.arenaMode && !moduleHasArena(mod.name) { + continue + } + if opts.bufferMode && !moduleHasBuffer(mod.name) { continue } kernels := mod.kernels - if opts.bufferMode && mod.bufferKernels != 0 { + if opts.arenaMode && mod.arenaKernels != 0 { + kernels = mod.arenaKernels + } else if opts.bufferMode && mod.bufferKernels != 0 { kernels = mod.bufferKernels } maxIndex := selectMaxIndex(rhfVersion, kernelVersion) idx := selectIndex(kernels, rhfVersion, kernelVersion) - candidates := discoverCandidates(mod.name, isReturn, rhfVersion, kernels, maxIndex, opts.netdataPath, opts.bufferMode) + candidates := discoverCandidates(mod.name, isReturn, rhfVersion, kernels, maxIndex, opts.netdataPath, opts.bufferMode, opts.arenaMode) compatible, incompatible, unsupportedType := filterCompatibleCandidates(candidates, supportedMapTypes) if len(compatible) == 0 { @@ -970,7 +1079,7 @@ func runNetdataTests(w io.Writer, rhfVersion int, kernelVersion int, isReturn bo continue } - compatible = []string{mountName(idx, mod.name, isReturn, rhfVersion, opts.netdataPath, opts.bufferMode)} + compatible = []string{mountName(idx, mod.name, isReturn, rhfVersion, opts.netdataPath, opts.bufferMode, opts.arenaMode)} } for _, filename := range compatible { @@ -1037,7 +1146,7 @@ func selectIndex(kernels uint32, rhfVersion int, kernelVersion int) uint32 { return 0 } -func mountName(kernelIndex uint32, name string, isReturn bool, rhfVersion int, netdataPath string, bufferMode bool) string { +func mountName(kernelIndex uint32, name string, isReturn bool, rhfVersion int, netdataPath string, bufferMode bool, arenaMode bool) string { version := selectKernelName(kernelIndex) path := netdataPath if path == "" { @@ -1064,12 +1173,7 @@ func mountName(kernelIndex uint32, name string, isReturn bool, rhfVersion int, n suffix = ".rhf" } - var bufferStr string - if bufferMode { - bufferStr = "_buffer" - } - - return fmt.Sprintf("%s/%cnetdata_ebpf_%s%s.%s%s.o", path, prefix, name, bufferStr, version, suffix) + return fmt.Sprintf("%s/%cnetdata_ebpf_%s%s.%s%s.o", path, prefix, name, modeSuffix(bufferMode, arenaMode), version, suffix) } func startExternalJSON(w io.Writer, filename string) { diff --git a/gotests/main_test.go b/gotests/main_test.go index ad623f93..4f327810 100644 --- a/gotests/main_test.go +++ b/gotests/main_test.go @@ -92,6 +92,63 @@ func TestKernelSelectionHelpers(t *testing.T) { }) } + osReleaseCases := []struct { + name string + content string + want int + }{ + { + name: "alma 9 without redhat-release", + content: `NAME="AlmaLinux" +VERSION="9.4 (Seafoam Ocelot)" +ID="almalinux" +ID_LIKE="rhel centos fedora" +VERSION_ID="9.4" +PLATFORM_ID="platform:el9" +`, + want: 9*256 + 4, + }, + { + name: "rhel 8 via ID_LIKE", + content: `NAME="Red Hat Enterprise Linux" +VERSION="8.9 (Ootpa)" +ID="rhel" +VERSION_ID="8.9" +`, + want: 8*256 + 9, + }, + { + name: "rocky linux", + content: `NAME="Rocky Linux" +ID="rocky" +ID_LIKE="rhel centos fedora" +VERSION_ID="9.3" +`, + want: 9*256 + 3, + }, + { + name: "debian ignored", + content: `NAME="Debian GNU/Linux" +ID=debian +VERSION_ID="12" +`, + want: -1, + }, + { + name: "empty content", + content: ``, + want: -1, + }, + } + + for _, tc := range osReleaseCases { + t.Run("os-release "+tc.name, func(t *testing.T) { + if got := parseOSRelease(tc.content); got != tc.want { + t.Fatalf("unexpected parsed os-release for %q: got %d want %d", tc.name, got, tc.want) + } + }) + } + leadingCases := []struct { input string want int @@ -162,11 +219,13 @@ func TestCandidateSelectionHelpers(t *testing.T) { {name: "wrong family", filename: "pnetdata_ebpf_swap.3.10.o", module: "swap", version: "3.10", rhf: 1, wantMatch: false}, {name: "non-rhf exact", filename: "pnetdata_ebpf_swap.5.14.o", module: "swap", version: "5.14", rhf: -1, wantMatch: true}, {name: "non-rhf rejects rhf", filename: "pnetdata_ebpf_swap.5.14.rhf.o", module: "swap", version: "5.14", rhf: -1, wantMatch: false}, + {name: "arena suffix exact", filename: "pnetdata_ebpf_swap_arena.6.12.o", module: "swap", version: "6.12", rhf: -1, wantMatch: true}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - if got := candidateMatches(tc.filename, tc.module, tc.isReturn, tc.version, tc.rhf, false); got != tc.wantMatch { + arenaMode := tc.name == "arena suffix exact" + if got := candidateMatches(tc.filename, tc.module, tc.isReturn, tc.version, tc.rhf, false, arenaMode); got != tc.wantMatch { t.Fatalf("unexpected match result for %q: got %v want %v", tc.filename, got, tc.wantMatch) } }) @@ -188,7 +247,7 @@ func TestCandidateSelectionHelpers(t *testing.T) { } } - got := discoverCandidates("swap", false, 1, netdataV310, 0, dir, false) + got := discoverCandidates("swap", false, 1, netdataV310, 0, dir, false, false) want := []string{ filepath.Join(dir, "pnetdata_ebpf_swap.3.10.rhf.o"), filepath.Join(dir, "pnetdata_ebpf_swap.3.10.variant.rhf.o"), @@ -219,13 +278,34 @@ func TestCandidateSelectionHelpers(t *testing.T) { } } - got := discoverCandidates("swap", false, -1, netdataV54|netdataV68|netdataV612, 11, dir, false) + got := discoverCandidates("swap", false, -1, netdataV54|netdataV68|netdataV612, 11, dir, false, false) want := []string{filepath.Join(dir, "pnetdata_ebpf_swap.6.12.o")} if len(got) != len(want) || got[0] != want[0] { t.Fatalf("unexpected candidates: got %v want %v", got, want) } }) + t.Run("discovers arena candidates when arena mode is enabled", func(t *testing.T) { + dir := t.TempDir() + files := []string{ + "pnetdata_ebpf_swap_arena.5.4.o", + "pnetdata_ebpf_swap_buffer.5.4.o", + "pnetdata_ebpf_swap_arena.6.12.o", + "pnetdata_ebpf_swap_buffer.6.12.o", + } + for _, name := range files { + if err := os.WriteFile(filepath.Join(dir, name), []byte("x"), 0o644); err != nil { + t.Fatalf("cannot create %s: %v", name, err) + } + } + + got := discoverCandidates("swap", false, -1, netdataV54|netdataV68|netdataV612, 11, dir, false, true) + want := []string{filepath.Join(dir, "pnetdata_ebpf_swap_arena.6.12.o")} + if len(got) != len(want) || got[0] != want[0] { + t.Fatalf("unexpected arena candidates: got %v want %v", got, want) + } + }) + t.Run("returns first unsupported map type", func(t *testing.T) { supported := map[uint32]bool{ bpfMapTypeHash: true, @@ -314,7 +394,7 @@ func TestBinaryAndIPHelpers(t *testing.T) { func TestParseArgumentsUnitTest(t *testing.T) { var log bytes.Buffer - opts, code := parseArguments([]string{"--unit-test"}, netdataEBPFKernel68, &logState{writer: &log}) + opts, code := parseArguments([]string{"--unit-test"}, netdataEBPFKernel68, -1, &logState{writer: &log}) if code != 0 { t.Fatalf("unexpected parse code: %d", code) } @@ -332,7 +412,7 @@ func TestParseArgumentsUnitTest(t *testing.T) { func TestParseArgumentsAll(t *testing.T) { t.Run("--all enables content flag for PID collection", func(t *testing.T) { var log bytes.Buffer - opts, code := parseArguments([]string{"--all"}, netdataEBPFKernel68, &logState{writer: &log}) + opts, code := parseArguments([]string{"--all"}, netdataEBPFKernel68, -1, &logState{writer: &log}) if code != 0 { t.Fatalf("unexpected parse code: %d", code) } @@ -346,7 +426,7 @@ func TestParseArgumentsAll(t *testing.T) { t.Run("--pid 3 is accepted", func(t *testing.T) { var log bytes.Buffer - opts, code := parseArguments([]string{"--all", "--pid", "3"}, netdataEBPFKernel68, &logState{writer: &log}) + opts, code := parseArguments([]string{"--all", "--pid", "3"}, netdataEBPFKernel68, -1, &logState{writer: &log}) if code != 0 { t.Fatalf("unexpected parse code: %d", code) } @@ -362,7 +442,7 @@ func TestParseArgumentsAll(t *testing.T) { func TestParseArgumentsBuffer(t *testing.T) { t.Run("--buffer enables content flag for ring buffer data", func(t *testing.T) { var log bytes.Buffer - opts, code := parseArguments([]string{"--buffer"}, netdataEBPFKernel612, &logState{writer: &log}) + opts, code := parseArguments([]string{"--buffer"}, netdataEBPFKernel612, -1, &logState{writer: &log}) if code != 0 { t.Fatalf("unexpected parse code: %d", code) } @@ -373,6 +453,56 @@ func TestParseArgumentsBuffer(t *testing.T) { t.Fatal("--buffer must enable flagContent so ring buffer data is collected and ring size is shown") } }) + + t.Run("--arena enables content flag for arena data", func(t *testing.T) { + var log bytes.Buffer + opts, code := parseArguments([]string{"--arena"}, netdataEBPFKernel69, -1, &logState{writer: &log}) + if code != 0 { + t.Fatalf("unexpected parse code: %d", code) + } + if !opts.arenaMode { + t.Fatal("--arena must set arenaMode") + } + if opts.flags&flagContent == 0 { + t.Fatal("--arena must enable flagContent so arena data is collected and ring size is shown") + } + }) + + t.Run("--buffer on RH kernel below 5.8 skips version abort", func(t *testing.T) { + var log bytes.Buffer + // netdataMinimumEBPFKernel (4.11) is below the 5.8 ring-buffer threshold. + // On a non-RH kernel this must be rejected; on RH it must proceed. + _, nonRHCode := parseArguments([]string{"--buffer"}, netdataMinimumEBPFKernel, -1, &logState{writer: &log}) + if nonRHCode == 0 { + t.Fatal("non-RH kernel below 5.8 must be rejected for --buffer") + } + log.Reset() + _, rhCode := parseArguments([]string{"--buffer"}, netdataMinimumEBPFKernel, 1, &logState{writer: &log}) + if rhCode != 0 { + t.Fatalf("RH kernel must bypass version check for --buffer, got code %d", rhCode) + } + }) + + t.Run("--arena on RH kernel below 6.9 skips version abort", func(t *testing.T) { + var log bytes.Buffer + _, nonRHCode := parseArguments([]string{"--arena"}, netdataEBPFKernel514, -1, &logState{writer: &log}) + if nonRHCode == 0 { + t.Fatal("non-RH kernel below 6.9 must be rejected for --arena") + } + log.Reset() + _, rhCode := parseArguments([]string{"--arena"}, netdataEBPFKernel514, 1, &logState{writer: &log}) + if rhCode != 0 { + t.Fatalf("RH kernel must bypass version check for --arena, got code %d", rhCode) + } + }) + + t.Run("mountName uses arena suffix", func(t *testing.T) { + got := mountName(11, "swap", false, -1, "/tmp", false, true) + want := "/tmp/pnetdata_ebpf_swap_arena.6.12.o" + if got != want { + t.Fatalf("unexpected arena mount name: got %q want %q", got, want) + } + }) } func TestResolveUnitTestDir(t *testing.T) { diff --git a/includes/netdata_arena_common.h b/includes/netdata_arena_common.h new file mode 100644 index 00000000..6624fe65 --- /dev/null +++ b/includes/netdata_arena_common.h @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef _NETDATA_ARENA_COMMON_ +#define _NETDATA_ARENA_COMMON_ 1 + +#if defined(__BPF_FEATURE_ADDR_SPACE_CAST) +#define __arena __attribute__((address_space(1))) +#define __arena_global __attribute__((address_space(1))) +#else +#define __arena +#define __arena_global SEC(".addr_space.1") +#endif + +#ifndef __arg_arena +#define __arg_arena __attribute__((btf_decl_tag("arg:arena"))) +#endif + +#if defined(__TARGET_ARCH_arm64) +#define NETDATA_ARENA_MAP_EXTRA (0x1ull << 32) +#else +#define NETDATA_ARENA_MAP_EXTRA (0x1ull << 44) +#endif + +#define NETDATA_ARENA_MAP_PAGES 256 +#define NETDATA_ARENA_EVENT_SLOTS 1024 + +#define NETDATA_BPF_ARENA_DEF(NAME, MAX_ENTRIES) \ + struct { \ + __uint(type, BPF_MAP_TYPE_ARENA); \ + __uint(map_flags, BPF_F_MMAPABLE); \ + __uint(max_entries, NETDATA_ARENA_MAP_PAGES); \ + __ulong(map_extra, NETDATA_ARENA_MAP_EXTRA); \ + } NAME SEC(".maps") + +#define NETDATA_ARENA_QUEUE_DECL(PREFIX, EVENT_TYPE, SLOT_COUNT) \ + struct netdata_##PREFIX##_arena_state_t { \ + __u32 head; \ + EVENT_TYPE events[SLOT_COUNT]; \ + }; \ + extern __arena struct netdata_##PREFIX##_arena_state_t PREFIX##_arena_state; \ + static __always_inline __arena EVENT_TYPE *netdata_##PREFIX##_arena_reserve(void) { \ + /* BPF backend rejects using the XADD return value directly. */ \ + __sync_fetch_and_add(&PREFIX##_arena_state.head, 1); \ + __u32 idx = PREFIX##_arena_state.head - 1; \ + return &PREFIX##_arena_state.events[idx % SLOT_COUNT]; \ + } \ + static __always_inline void netdata_##PREFIX##_arena_submit(__arena EVENT_TYPE *ev) { \ + (void)ev; \ + } + +#endif /* _NETDATA_ARENA_COMMON_ */ diff --git a/includes/netdata_cachestat_arena.h b/includes/netdata_cachestat_arena.h new file mode 100644 index 00000000..821c25bd --- /dev/null +++ b/includes/netdata_cachestat_arena.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef _NETDATA_CACHESTAT_ARENA_H_ +#define _NETDATA_CACHESTAT_ARENA_H_ 1 + +#include "netdata_cache_buffer.h" +#include "netdata_arena_common.h" + +NETDATA_ARENA_QUEUE_DECL(cachestat, struct netdata_cachestat_event_t, NETDATA_ARENA_EVENT_SLOTS); + +#endif /* _NETDATA_CACHESTAT_ARENA_H_ */ diff --git a/includes/netdata_common.h b/includes/netdata_common.h index e6df9e0e..4e5b3d47 100644 --- a/includes/netdata_common.h +++ b/includes/netdata_common.h @@ -252,11 +252,15 @@ static __always_inline __u32 monitor_apps(void *ctrl_tbl) #define NETDATA_BPF_PERCPU_ARRAY_DEF(NAME, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES) \ NETDATA_BPF_MAP_DEF(NAME, BPF_MAP_TYPE_PERCPU_ARRAY, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES) +#ifndef NETDATA_BPF_RINGBUF_DEF #define NETDATA_BPF_RINGBUF_DEF(NAME, MAX_ENTRIES) \ NETDATA_BPF_RINGBUF_MAP_DEF(NAME, BPF_MAP_TYPE_RINGBUF, MAX_ENTRIES) +#endif +#ifndef NETDATA_BPF_USER_RINGBUF_DEF #define NETDATA_BPF_USER_RINGBUF_DEF(NAME, MAX_ENTRIES) \ NETDATA_BPF_RINGBUF_MAP_DEF(NAME, BPF_MAP_TYPE_USER_RINGBUF, MAX_ENTRIES) +#endif #else #define NETDATA_BPF_HASH_DEF(NAME, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES) \ NETDATA_BPF_MAP_DEF(NAME, BPF_MAP_TYPE_HASH, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES) @@ -270,12 +274,16 @@ static __always_inline __u32 monitor_apps(void *ctrl_tbl) #define NETDATA_BPF_PERCPU_ARRAY_DEF(NAME, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES) \ NETDATA_BPF_MAP_DEF(NAME, BPF_MAP_TYPE_ARRAY, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES) +#ifndef NETDATA_BPF_RINGBUF_DEF #define NETDATA_BPF_RINGBUF_DEF(NAME, MAX_ENTRIES) \ NETDATA_BPF_RINGBUF_MAP_DEF(NAME, BPF_MAP_TYPE_RINGBUF, MAX_ENTRIES) +#endif +#ifndef NETDATA_BPF_USER_RINGBUF_DEF #define NETDATA_BPF_USER_RINGBUF_DEF(NAME, MAX_ENTRIES) \ NETDATA_BPF_RINGBUF_MAP_DEF(NAME, BPF_MAP_TYPE_USER_RINGBUF, MAX_ENTRIES) #endif +#endif #else #define NETDATA_BPF_MAP_DEF(NAME, TYPE, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES) \ diff --git a/includes/netdata_dc_arena.h b/includes/netdata_dc_arena.h new file mode 100644 index 00000000..2c46bce0 --- /dev/null +++ b/includes/netdata_dc_arena.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef _NETDATA_DC_ARENA_H_ +#define _NETDATA_DC_ARENA_H_ 1 + +#include "netdata_dc_buffer.h" +#include "netdata_arena_common.h" + +NETDATA_ARENA_QUEUE_DECL(dc, struct netdata_dc_event_t, NETDATA_ARENA_EVENT_SLOTS); + +#endif /* _NETDATA_DC_ARENA_H_ */ diff --git a/includes/netdata_dns_arena.h b/includes/netdata_dns_arena.h new file mode 100644 index 00000000..4793a52c --- /dev/null +++ b/includes/netdata_dns_arena.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef _NETDATA_DNS_ARENA_H_ +#define _NETDATA_DNS_ARENA_H_ 1 + +#include "netdata_dns_buffer.h" +#include "netdata_arena_common.h" + +NETDATA_ARENA_QUEUE_DECL(dns, struct netdata_dns_event_t, NETDATA_ARENA_EVENT_SLOTS); + +#endif /* _NETDATA_DNS_ARENA_H_ */ diff --git a/includes/netdata_fd_arena.h b/includes/netdata_fd_arena.h new file mode 100644 index 00000000..2821632e --- /dev/null +++ b/includes/netdata_fd_arena.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef _NETDATA_FD_ARENA_H_ +#define _NETDATA_FD_ARENA_H_ 1 + +#include "netdata_fd_buffer.h" +#include "netdata_arena_common.h" + +NETDATA_ARENA_QUEUE_DECL(fd, struct netdata_fd_event_t, NETDATA_ARENA_EVENT_SLOTS); + +#endif /* _NETDATA_FD_ARENA_H_ */ diff --git a/includes/netdata_oomkill_arena.h b/includes/netdata_oomkill_arena.h new file mode 100644 index 00000000..93b69ccc --- /dev/null +++ b/includes/netdata_oomkill_arena.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef _NETDATA_OOMKILL_ARENA_H_ +#define _NETDATA_OOMKILL_ARENA_H_ 1 + +#include "netdata_oomkill_buffer.h" +#include "netdata_arena_common.h" + +NETDATA_ARENA_QUEUE_DECL(oomkill, struct netdata_oomkill_event_t, NETDATA_ARENA_EVENT_SLOTS); + +#endif /* _NETDATA_OOMKILL_ARENA_H_ */ diff --git a/includes/netdata_process_arena.h b/includes/netdata_process_arena.h new file mode 100644 index 00000000..5ad1c659 --- /dev/null +++ b/includes/netdata_process_arena.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef _NETDATA_PROCESS_ARENA_H_ +#define _NETDATA_PROCESS_ARENA_H_ 1 + +#include "netdata_process_buffer.h" +#include "netdata_arena_common.h" + +NETDATA_ARENA_QUEUE_DECL(process, struct netdata_process_event_t, NETDATA_ARENA_EVENT_SLOTS); + +#endif /* _NETDATA_PROCESS_ARENA_H_ */ diff --git a/includes/netdata_shm_arena.h b/includes/netdata_shm_arena.h new file mode 100644 index 00000000..31c9a7fd --- /dev/null +++ b/includes/netdata_shm_arena.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef _NETDATA_SHM_ARENA_H_ +#define _NETDATA_SHM_ARENA_H_ 1 + +#include "netdata_shm_buffer.h" +#include "netdata_arena_common.h" + +NETDATA_ARENA_QUEUE_DECL(shm, struct netdata_shm_event_t, NETDATA_ARENA_EVENT_SLOTS); + +#endif /* _NETDATA_SHM_ARENA_H_ */ diff --git a/includes/netdata_swap_arena.h b/includes/netdata_swap_arena.h new file mode 100644 index 00000000..a46ddaed --- /dev/null +++ b/includes/netdata_swap_arena.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef _NETDATA_SWAP_ARENA_H_ +#define _NETDATA_SWAP_ARENA_H_ 1 + +#include "netdata_swap_buffer.h" +#include "netdata_arena_common.h" + +NETDATA_ARENA_QUEUE_DECL(swap, struct netdata_swap_event_t, NETDATA_ARENA_EVENT_SLOTS); + +#endif /* _NETDATA_SWAP_ARENA_H_ */ diff --git a/includes/netdata_vfs_arena.h b/includes/netdata_vfs_arena.h new file mode 100644 index 00000000..dacb820f --- /dev/null +++ b/includes/netdata_vfs_arena.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef _NETDATA_VFS_ARENA_H_ +#define _NETDATA_VFS_ARENA_H_ 1 + +#include "netdata_vfs_buffer.h" +#include "netdata_arena_common.h" + +NETDATA_ARENA_QUEUE_DECL(vfs, struct netdata_vfs_event_t, NETDATA_ARENA_EVENT_SLOTS); + +#endif /* _NETDATA_VFS_ARENA_H_ */ diff --git a/kernel/Makefile b/kernel/Makefile index 5f7bcf76..5dc2ff21 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -123,9 +123,30 @@ else NETDATA_RINGBUF_APPS= endif -all: $(NETDATA_APPS) $(NETDATA_RINGBUF_APPS) +# BPF_MAP_TYPE_ARENA requires kernel >= 6.9 (395520 = 6 * 65536 + 9 * 256) +ifeq ($(shell test $(CURRENT_KERNEL) -ge 395520 ; echo $$?),0) +NETDATA_ARENA_APPS= cachestat_arena \ + dc_arena \ + dns_arena \ + fd_arena \ + oomkill_arena \ + process_arena \ + shm_arena \ + swap_arena \ + vfs_arena \ + # +else +NETDATA_ARENA_APPS= +endif + +# Arena objects need address-space-cast support so the verifier sees PTR_TO_ARENA +ifneq ($(NETDATA_ARENA_APPS),) +$(addsuffix _kern.o,$(NETDATA_ARENA_APPS)): EXTRA_CFLAGS += -D__BPF_FEATURE_ADDR_SPACE_CAST -Wno-address-space-conversion +endif + +all: $(NETDATA_APPS) $(NETDATA_RINGBUF_APPS) $(NETDATA_ARENA_APPS) -dev: ${NETDATA_ALL_APPS} ${NETDATA_RINGBUF_APPS} +dev: ${NETDATA_ALL_APPS} ${NETDATA_RINGBUF_APPS} ${NETDATA_ARENA_APPS} libbpf: # -fPIE added to be compatible with olders clang/gcc @@ -170,6 +191,8 @@ ${NETDATA_ALL_APPS}: %: %_kern.o ${NETDATA_RINGBUF_APPS}: %: %_kern.o +${NETDATA_ARENA_APPS}: %: %_kern.o + tester: libbpf cd ../tests && $(MAKE) tester diff --git a/kernel/cachestat_arena_kern.c b/kernel/cachestat_arena_kern.c new file mode 100644 index 00000000..1457f5aa --- /dev/null +++ b/kernel/cachestat_arena_kern.c @@ -0,0 +1,21 @@ +#define KBUILD_MODNAME "cachestat_arena_kern" +#include +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) +#include +#else +#include +#endif +#include "bpf_tracing.h" +#include "bpf_helpers.h" +#include "netdata_arena_common.h" +#include "netdata_cachestat_arena.h" + +struct netdata_cachestat_arena_state_t cachestat_arena_state __arena_global; + +#define NETDATA_BPF_RINGBUF_DEF(NAME, MAX_ENTRIES) NETDATA_BPF_ARENA_DEF(NAME, MAX_ENTRIES) +#define bpf_ringbuf_reserve(MAP, SIZE, FLAGS) netdata_cachestat_arena_reserve() +#define bpf_ringbuf_submit(EV, FLAGS) netdata_cachestat_arena_submit(EV) + +#include "cachestat_buffer_kern.c" diff --git a/kernel/cachestat_buffer_kern.c b/kernel/cachestat_buffer_kern.c index 65dbbe67..3f44bdfb 100644 --- a/kernel/cachestat_buffer_kern.c +++ b/kernel/cachestat_buffer_kern.c @@ -11,6 +11,7 @@ #include "bpf_tracing.h" #include "bpf_helpers.h" #include "netdata_common.h" +#include "netdata_arena_common.h" #include "netdata_cache.h" #include "netdata_cache_buffer.h" @@ -30,15 +31,23 @@ NETDATA_BPF_ARRAY_DEF(cstat_ctrl, __u32, __u64, NETDATA_CONTROLLER_END); * ***********************************************************************************/ -static __always_inline void netdata_cachestat_fill_event(struct netdata_cachestat_event_t *ev, void *ctrl) +static __always_inline void netdata_cachestat_fill_event(struct netdata_cachestat_event_t __arena *ev, void *ctrl) { __u32 tgid = 0; + char comm[TASK_COMM_LEN]; ev->ct = bpf_ktime_get_ns(); ev->pid = netdata_get_pid(ctrl, &tgid); ev->tgid = tgid; - libnetdata_update_uid_gid(&ev->uid, &ev->gid); + { + __u64 uid_gid = bpf_get_current_uid_gid(); + ev->uid = (__u32)uid_gid; + ev->gid = (__u32)(uid_gid >> 32); + } #if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) - bpf_get_current_comm(ev->name, TASK_COMM_LEN); + bpf_get_current_comm(comm, TASK_COMM_LEN); +#pragma unroll + for (int i = 0; i < TASK_COMM_LEN; i++) + ev->name[i] = comm[i]; #else ev->name[0] = '\0'; #endif @@ -59,7 +68,7 @@ int netdata_add_to_page_cache_lru_buffer(struct pt_regs *ctx) if (!monitor_apps(&cstat_ctrl)) return 0; - struct netdata_cachestat_event_t *ev = bpf_ringbuf_reserve(&cachestat_events, sizeof(*ev), 0); + struct netdata_cachestat_event_t __arena *ev = bpf_ringbuf_reserve(&cachestat_events, sizeof(*ev), 0); if (!ev) return 0; @@ -78,7 +87,7 @@ int netdata_mark_page_accessed_buffer(struct pt_regs *ctx) if (!monitor_apps(&cstat_ctrl)) return 0; - struct netdata_cachestat_event_t *ev = bpf_ringbuf_reserve(&cachestat_events, sizeof(*ev), 0); + struct netdata_cachestat_event_t __arena *ev = bpf_ringbuf_reserve(&cachestat_events, sizeof(*ev), 0); if (!ev) return 0; @@ -111,7 +120,7 @@ int netdata_set_page_dirty_buffer(struct pt_regs *ctx) if (!monitor_apps(&cstat_ctrl)) return 0; - struct netdata_cachestat_event_t *ev = bpf_ringbuf_reserve(&cachestat_events, sizeof(*ev), 0); + struct netdata_cachestat_event_t __arena *ev = bpf_ringbuf_reserve(&cachestat_events, sizeof(*ev), 0); if (!ev) return 0; @@ -136,7 +145,7 @@ int netdata_account_page_dirtied_buffer(struct pt_regs *ctx) if (!monitor_apps(&cstat_ctrl)) return 0; - struct netdata_cachestat_event_t *ev = bpf_ringbuf_reserve(&cachestat_events, sizeof(*ev), 0); + struct netdata_cachestat_event_t __arena *ev = bpf_ringbuf_reserve(&cachestat_events, sizeof(*ev), 0); if (!ev) return 0; @@ -157,7 +166,7 @@ int netdata_mark_buffer_dirty_buffer(struct pt_regs *ctx) if (!monitor_apps(&cstat_ctrl)) return 0; - struct netdata_cachestat_event_t *ev = bpf_ringbuf_reserve(&cachestat_events, sizeof(*ev), 0); + struct netdata_cachestat_event_t __arena *ev = bpf_ringbuf_reserve(&cachestat_events, sizeof(*ev), 0); if (!ev) return 0; diff --git a/kernel/dc_arena_kern.c b/kernel/dc_arena_kern.c new file mode 100644 index 00000000..1a90312c --- /dev/null +++ b/kernel/dc_arena_kern.c @@ -0,0 +1,21 @@ +#define KBUILD_MODNAME "dc_arena_kern" +#include +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) +#include +#else +#include +#endif +#include "bpf_tracing.h" +#include "bpf_helpers.h" +#include "netdata_arena_common.h" +#include "netdata_dc_arena.h" + +struct netdata_dc_arena_state_t dc_arena_state __arena_global; + +#define NETDATA_BPF_RINGBUF_DEF(NAME, MAX_ENTRIES) NETDATA_BPF_ARENA_DEF(NAME, MAX_ENTRIES) +#define bpf_ringbuf_reserve(MAP, SIZE, FLAGS) netdata_dc_arena_reserve() +#define bpf_ringbuf_submit(EV, FLAGS) netdata_dc_arena_submit(EV) + +#include "dc_buffer_kern.c" diff --git a/kernel/dc_buffer_kern.c b/kernel/dc_buffer_kern.c index a2f20ce2..87a6544d 100644 --- a/kernel/dc_buffer_kern.c +++ b/kernel/dc_buffer_kern.c @@ -10,6 +10,7 @@ #include "bpf_tracing.h" #include "bpf_helpers.h" #include "netdata_common.h" +#include "netdata_arena_common.h" #include "netdata_dc.h" #include "netdata_dc_buffer.h" @@ -29,15 +30,23 @@ NETDATA_BPF_PERCPU_ARRAY_DEF(dcstat_ctrl, __u32, __u64, NETDATA_CONTROLLER_END); * ***********************************************************************************/ -static __always_inline void netdata_dc_fill_event(struct netdata_dc_event_t *ev, void *ctrl) +static __always_inline void netdata_dc_fill_event(struct netdata_dc_event_t __arena *ev, void *ctrl) { __u32 tgid = 0; + char comm[TASK_COMM_LEN]; ev->ct = bpf_ktime_get_ns(); ev->pid = netdata_get_pid(ctrl, &tgid); ev->tgid = tgid; - libnetdata_update_uid_gid(&ev->uid, &ev->gid); + { + __u64 uid_gid = bpf_get_current_uid_gid(); + ev->uid = (__u32)uid_gid; + ev->gid = (__u32)(uid_gid >> 32); + } #if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) - bpf_get_current_comm(ev->name, TASK_COMM_LEN); + bpf_get_current_comm(comm, TASK_COMM_LEN); +#pragma unroll + for (int i = 0; i < TASK_COMM_LEN; i++) + ev->name[i] = comm[i]; #else ev->name[0] = '\0'; #endif @@ -58,7 +67,7 @@ int netdata_lookup_fast_buffer(struct pt_regs *ctx) if (!monitor_apps(&dcstat_ctrl)) return 0; - struct netdata_dc_event_t *ev = bpf_ringbuf_reserve(&dc_events, sizeof(*ev), 0); + struct netdata_dc_event_t __arena *ev = bpf_ringbuf_reserve(&dc_events, sizeof(*ev), 0); if (!ev) return 0; @@ -81,7 +90,7 @@ int netdata_d_lookup_buffer(struct pt_regs *ctx) if (!monitor_apps(&dcstat_ctrl)) return 0; - struct netdata_dc_event_t *ev = bpf_ringbuf_reserve(&dc_events, sizeof(*ev), 0); + struct netdata_dc_event_t __arena *ev = bpf_ringbuf_reserve(&dc_events, sizeof(*ev), 0); if (!ev) return 0; diff --git a/kernel/dns_arena_kern.c b/kernel/dns_arena_kern.c new file mode 100644 index 00000000..8d6200bb --- /dev/null +++ b/kernel/dns_arena_kern.c @@ -0,0 +1,24 @@ +#define KBUILD_MODNAME "dns_arena_kern" +#include +#include +#include +#include +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) +#include +#else +#include +#endif +#include "bpf_tracing.h" +#include "bpf_helpers.h" +#include "netdata_arena_common.h" +#include "netdata_dns_arena.h" + +struct netdata_dns_arena_state_t dns_arena_state __arena_global; + +#define NETDATA_BPF_RINGBUF_DEF(NAME, MAX_ENTRIES) NETDATA_BPF_ARENA_DEF(NAME, MAX_ENTRIES) +#define bpf_ringbuf_reserve(MAP, SIZE, FLAGS) netdata_dns_arena_reserve() +#define bpf_ringbuf_submit(EV, FLAGS) netdata_dns_arena_submit(EV) + +#include "dns_buffer_kern.c" diff --git a/kernel/dns_buffer_kern.c b/kernel/dns_buffer_kern.c index b98971b5..b4041dc3 100644 --- a/kernel/dns_buffer_kern.c +++ b/kernel/dns_buffer_kern.c @@ -17,6 +17,7 @@ #include "bpf_endian.h" #include "bpf_helpers.h" #include "netdata_common.h" +#include "netdata_arena_common.h" #include "netdata_dns_buffer.h" /************************************************************************************ @@ -174,7 +175,7 @@ int socket__dns_filter_buffer(struct __sk_buff *skb) if (!is_query && !is_response) return 0; - struct netdata_dns_event_t *ev = bpf_ringbuf_reserve(&dns_events, sizeof(*ev), 0); + struct netdata_dns_event_t __arena *ev = bpf_ringbuf_reserve(&dns_events, sizeof(*ev), 0); if (!ev) return 0; diff --git a/kernel/fd_arena_kern.c b/kernel/fd_arena_kern.c new file mode 100644 index 00000000..d67c0205 --- /dev/null +++ b/kernel/fd_arena_kern.c @@ -0,0 +1,25 @@ +#define KBUILD_MODNAME "fd_arena_kern" +#include +#include +#include +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,10,17)) +# include +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) +#include +#else +#include +#endif +#include "bpf_tracing.h" +#include "bpf_helpers.h" +#include "netdata_arena_common.h" +#include "netdata_fd_arena.h" + +struct netdata_fd_arena_state_t fd_arena_state __arena_global; + +#define NETDATA_BPF_RINGBUF_DEF(NAME, MAX_ENTRIES) NETDATA_BPF_ARENA_DEF(NAME, MAX_ENTRIES) +#define bpf_ringbuf_reserve(MAP, SIZE, FLAGS) netdata_fd_arena_reserve() +#define bpf_ringbuf_submit(EV, FLAGS) netdata_fd_arena_submit(EV) + +#include "fd_buffer_kern.c" diff --git a/kernel/fd_buffer_kern.c b/kernel/fd_buffer_kern.c index 485107c6..c74e0f14 100644 --- a/kernel/fd_buffer_kern.c +++ b/kernel/fd_buffer_kern.c @@ -14,6 +14,7 @@ #include "bpf_tracing.h" #include "bpf_helpers.h" #include "netdata_common.h" +#include "netdata_arena_common.h" #include "netdata_fd.h" #include "netdata_fd_buffer.h" @@ -33,15 +34,23 @@ NETDATA_BPF_ARRAY_DEF(fd_ctrl, __u32, __u64, NETDATA_CONTROLLER_END); * ***********************************************************************************/ -static __always_inline void netdata_fd_fill_event(struct netdata_fd_event_t *ev, void *ctrl) +static __always_inline void netdata_fd_fill_event(struct netdata_fd_event_t __arena *ev, void *ctrl) { __u32 tgid = 0; + char comm[TASK_COMM_LEN]; ev->ct = bpf_ktime_get_ns(); ev->pid = netdata_get_pid(ctrl, &tgid); ev->tgid = tgid; - libnetdata_update_uid_gid(&ev->uid, &ev->gid); + { + __u64 uid_gid = bpf_get_current_uid_gid(); + ev->uid = (__u32)uid_gid; + ev->gid = (__u32)(uid_gid >> 32); + } #if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) - bpf_get_current_comm(ev->name, TASK_COMM_LEN); + bpf_get_current_comm(comm, TASK_COMM_LEN); +#pragma unroll + for (int i = 0; i < TASK_COMM_LEN; i++) + ev->name[i] = comm[i]; #else ev->name[0] = '\0'; #endif @@ -82,7 +91,7 @@ int netdata_sys_open_buffer(struct pt_regs *ctx) if (!monitor_apps(&fd_ctrl)) return 0; - struct netdata_fd_event_t *ev = bpf_ringbuf_reserve(&fd_events, sizeof(*ev), 0); + struct netdata_fd_event_t __arena *ev = bpf_ringbuf_reserve(&fd_events, sizeof(*ev), 0); if (!ev) return 0; @@ -132,7 +141,7 @@ int netdata_close_buffer(struct pt_regs *ctx) if (!monitor_apps(&fd_ctrl)) return 0; - struct netdata_fd_event_t *ev = bpf_ringbuf_reserve(&fd_events, sizeof(*ev), 0); + struct netdata_fd_event_t __arena *ev = bpf_ringbuf_reserve(&fd_events, sizeof(*ev), 0); if (!ev) return 0; diff --git a/kernel/oomkill_arena_kern.c b/kernel/oomkill_arena_kern.c new file mode 100644 index 00000000..0552d060 --- /dev/null +++ b/kernel/oomkill_arena_kern.c @@ -0,0 +1,21 @@ +#define KBUILD_MODNAME "oomkill_arena_kern" +#include +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) +#include +#else +#include +#endif +#include "bpf_tracing.h" +#include "bpf_helpers.h" +#include "netdata_arena_common.h" +#include "netdata_oomkill_arena.h" + +struct netdata_oomkill_arena_state_t oomkill_arena_state __arena_global; + +#define NETDATA_BPF_RINGBUF_DEF(NAME, MAX_ENTRIES) NETDATA_BPF_ARENA_DEF(NAME, MAX_ENTRIES) +#define bpf_ringbuf_reserve(MAP, SIZE, FLAGS) netdata_oomkill_arena_reserve() +#define bpf_ringbuf_submit(EV, FLAGS) netdata_oomkill_arena_submit(EV) + +#include "oomkill_buffer_kern.c" diff --git a/kernel/oomkill_buffer_kern.c b/kernel/oomkill_buffer_kern.c index 18fe1061..263a87aa 100644 --- a/kernel/oomkill_buffer_kern.c +++ b/kernel/oomkill_buffer_kern.c @@ -10,6 +10,7 @@ #include "bpf_tracing.h" #include "bpf_helpers.h" #include "netdata_common.h" +#include "netdata_arena_common.h" #include "netdata_oomkill.h" #include "netdata_oomkill_buffer.h" @@ -30,13 +31,15 @@ NETDATA_BPF_RINGBUF_DEF(oomkill_events, NETDATA_OOMKILL_RINGBUF_SIZE); SEC("tracepoint/oom/mark_victim") int netdata_oom_mark_victim_buffer(struct netdata_oom_mark_victim_entry *ptr) { - struct netdata_oomkill_event_t *ev = bpf_ringbuf_reserve(&oomkill_events, sizeof(*ev), 0); + struct netdata_oomkill_event_t __arena *ev = bpf_ringbuf_reserve(&oomkill_events, sizeof(*ev), 0); if (!ev) return 0; + __u32 pid; ev->ct = bpf_ktime_get_ns(); ev->pad = 0; - bpf_probe_read(&ev->pid, sizeof(ev->pid), &ptr->pid); + bpf_probe_read(&pid, sizeof(pid), &ptr->pid); + ev->pid = pid; bpf_ringbuf_submit(ev, 0); return 0; diff --git a/kernel/process_arena_kern.c b/kernel/process_arena_kern.c new file mode 100644 index 00000000..404377d8 --- /dev/null +++ b/kernel/process_arena_kern.c @@ -0,0 +1,25 @@ +#define KBUILD_MODNAME "process_arena_kern" +#include +#include +#include +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,10,17)) +# include +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) +#include +#else +#include +#endif +#include "bpf_tracing.h" +#include "bpf_helpers.h" +#include "netdata_arena_common.h" +#include "netdata_process_arena.h" + +struct netdata_process_arena_state_t process_arena_state __arena_global; + +#define NETDATA_BPF_RINGBUF_DEF(NAME, MAX_ENTRIES) NETDATA_BPF_ARENA_DEF(NAME, MAX_ENTRIES) +#define bpf_ringbuf_reserve(MAP, SIZE, FLAGS) netdata_process_arena_reserve() +#define bpf_ringbuf_submit(EV, FLAGS) netdata_process_arena_submit(EV) + +#include "process_buffer_kern.c" diff --git a/kernel/process_buffer_kern.c b/kernel/process_buffer_kern.c index 41b091f0..a1e6f1e8 100644 --- a/kernel/process_buffer_kern.c +++ b/kernel/process_buffer_kern.c @@ -14,6 +14,7 @@ #include "bpf_tracing.h" #include "bpf_helpers.h" #include "netdata_common.h" +#include "netdata_arena_common.h" #include "netdata_process.h" #include "netdata_process_buffer.h" @@ -33,15 +34,23 @@ NETDATA_BPF_ARRAY_DEF(process_ctrl, __u32, __u64, NETDATA_CONTROLLER_END); * ***********************************************************************************/ -static __always_inline void netdata_process_fill_event(struct netdata_process_event_t *ev, void *ctrl) +static __always_inline void netdata_process_fill_event(struct netdata_process_event_t __arena *ev, void *ctrl) { __u32 tgid = 0; + char comm[TASK_COMM_LEN]; ev->ct = bpf_ktime_get_ns(); ev->pid = netdata_get_pid(ctrl, &tgid); ev->tgid = tgid; - libnetdata_update_uid_gid(&ev->uid, &ev->gid); + { + __u64 uid_gid = bpf_get_current_uid_gid(); + ev->uid = (__u32)uid_gid; + ev->gid = (__u32)(uid_gid >> 32); + } #if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) - bpf_get_current_comm(ev->name, TASK_COMM_LEN); + bpf_get_current_comm(comm, TASK_COMM_LEN); +#pragma unroll + for (int i = 0; i < TASK_COMM_LEN; i++) + ev->name[i] = comm[i]; #else ev->name[0] = '\0'; #endif @@ -62,7 +71,7 @@ int netdata_tracepoint_sched_process_exit_buffer(struct netdata_sched_process_ex if (!monitor_apps(&process_ctrl)) return 0; - struct netdata_process_event_t *ev = bpf_ringbuf_reserve(&process_events, sizeof(*ev), 0); + struct netdata_process_event_t __arena *ev = bpf_ringbuf_reserve(&process_events, sizeof(*ev), 0); if (!ev) return 0; @@ -81,7 +90,7 @@ int netdata_release_task_buffer(struct pt_regs *ctx) if (!monitor_apps(&process_ctrl)) return 0; - struct netdata_process_event_t *ev = bpf_ringbuf_reserve(&process_events, sizeof(*ev), 0); + struct netdata_process_event_t __arena *ev = bpf_ringbuf_reserve(&process_events, sizeof(*ev), 0); if (!ev) return 0; @@ -100,7 +109,7 @@ int netdata_tracepoint_sched_process_exec_buffer(struct netdata_sched_process_ex if (!monitor_apps(&process_ctrl)) return 0; - struct netdata_process_event_t *ev = bpf_ringbuf_reserve(&process_events, sizeof(*ev), 0); + struct netdata_process_event_t __arena *ev = bpf_ringbuf_reserve(&process_events, sizeof(*ev), 0); if (!ev) return 0; @@ -139,7 +148,7 @@ int netdata_tracepoint_sched_process_fork_buffer(void *ctx) if (!monitor_apps(&process_ctrl)) return 0; - struct netdata_process_event_t *ev = bpf_ringbuf_reserve(&process_events, sizeof(*ev), 0); + struct netdata_process_event_t __arena *ev = bpf_ringbuf_reserve(&process_events, sizeof(*ev), 0); if (!ev) return 0; @@ -173,7 +182,7 @@ int netdata_fork_buffer(struct pt_regs *ctx) libnetdata_update_global(&tbl_total_stats, NETDATA_KEY_ERROR_PROCESS, 1); if (monitor_apps(&process_ctrl)) { - struct netdata_process_event_t *ev = bpf_ringbuf_reserve(&process_events, sizeof(*ev), 0); + struct netdata_process_event_t __arena *ev = bpf_ringbuf_reserve(&process_events, sizeof(*ev), 0); if (ev) { netdata_process_fill_event(ev, &process_ctrl); ev->action = NETDATA_PROCESS_EVENT_FORK_ERR; @@ -200,7 +209,7 @@ int netdata_sys_clone_buffer(struct pt_regs *ctx) libnetdata_update_global(&tbl_total_stats, NETDATA_KEY_ERROR_PROCESS, 1); if (monitor_apps(&process_ctrl)) { - struct netdata_process_event_t *ev = bpf_ringbuf_reserve(&process_events, sizeof(*ev), 0); + struct netdata_process_event_t __arena *ev = bpf_ringbuf_reserve(&process_events, sizeof(*ev), 0); if (ev) { netdata_process_fill_event(ev, &process_ctrl); ev->action = NETDATA_PROCESS_EVENT_FORK_ERR; diff --git a/kernel/shm_arena_kern.c b/kernel/shm_arena_kern.c new file mode 100644 index 00000000..0a602b22 --- /dev/null +++ b/kernel/shm_arena_kern.c @@ -0,0 +1,21 @@ +#define KBUILD_MODNAME "shm_arena_kern" +#include +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) +#include +#else +#include +#endif +#include "bpf_tracing.h" +#include "bpf_helpers.h" +#include "netdata_arena_common.h" +#include "netdata_shm_arena.h" + +struct netdata_shm_arena_state_t shm_arena_state __arena_global; + +#define NETDATA_BPF_RINGBUF_DEF(NAME, MAX_ENTRIES) NETDATA_BPF_ARENA_DEF(NAME, MAX_ENTRIES) +#define bpf_ringbuf_reserve(MAP, SIZE, FLAGS) netdata_shm_arena_reserve() +#define bpf_ringbuf_submit(EV, FLAGS) netdata_shm_arena_submit(EV) + +#include "shm_buffer_kern.c" diff --git a/kernel/shm_buffer_kern.c b/kernel/shm_buffer_kern.c index 94243715..eb7a7225 100644 --- a/kernel/shm_buffer_kern.c +++ b/kernel/shm_buffer_kern.c @@ -10,6 +10,7 @@ #include "bpf_tracing.h" #include "bpf_helpers.h" #include "netdata_common.h" +#include "netdata_arena_common.h" #include "netdata_shm.h" #include "netdata_shm_buffer.h" @@ -29,15 +30,23 @@ NETDATA_BPF_ARRAY_DEF(shm_ctrl, __u32, __u64, NETDATA_CONTROLLER_END); * ***********************************************************************************/ -static __always_inline void netdata_shm_fill_event(struct netdata_shm_event_t *ev, void *ctrl) +static __always_inline void netdata_shm_fill_event(struct netdata_shm_event_t __arena *ev, void *ctrl) { __u32 tgid = 0; + char comm[TASK_COMM_LEN]; ev->ct = bpf_ktime_get_ns(); ev->pid = netdata_get_pid(ctrl, &tgid); ev->tgid = tgid; - libnetdata_update_uid_gid(&ev->uid, &ev->gid); + { + __u64 uid_gid = bpf_get_current_uid_gid(); + ev->uid = (__u32)uid_gid; + ev->gid = (__u32)(uid_gid >> 32); + } #if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) - bpf_get_current_comm(ev->name, TASK_COMM_LEN); + bpf_get_current_comm(comm, TASK_COMM_LEN); +#pragma unroll + for (int i = 0; i < TASK_COMM_LEN; i++) + ev->name[i] = comm[i]; #else ev->name[0] = '\0'; #endif @@ -62,7 +71,7 @@ int netdata_syscall_shmget_buffer(struct pt_regs *ctx) if (!monitor_apps(&shm_ctrl)) return 0; - struct netdata_shm_event_t *ev = bpf_ringbuf_reserve(&shm_events, sizeof(*ev), 0); + struct netdata_shm_event_t __arena *ev = bpf_ringbuf_reserve(&shm_events, sizeof(*ev), 0); if (!ev) return 0; @@ -85,7 +94,7 @@ int netdata_syscall_shmat_buffer(struct pt_regs *ctx) if (!monitor_apps(&shm_ctrl)) return 0; - struct netdata_shm_event_t *ev = bpf_ringbuf_reserve(&shm_events, sizeof(*ev), 0); + struct netdata_shm_event_t __arena *ev = bpf_ringbuf_reserve(&shm_events, sizeof(*ev), 0); if (!ev) return 0; @@ -108,7 +117,7 @@ int netdata_syscall_shmdt_buffer(struct pt_regs *ctx) if (!monitor_apps(&shm_ctrl)) return 0; - struct netdata_shm_event_t *ev = bpf_ringbuf_reserve(&shm_events, sizeof(*ev), 0); + struct netdata_shm_event_t __arena *ev = bpf_ringbuf_reserve(&shm_events, sizeof(*ev), 0); if (!ev) return 0; @@ -131,7 +140,7 @@ int netdata_syscall_shmctl_buffer(struct pt_regs *ctx) if (!monitor_apps(&shm_ctrl)) return 0; - struct netdata_shm_event_t *ev = bpf_ringbuf_reserve(&shm_events, sizeof(*ev), 0); + struct netdata_shm_event_t __arena *ev = bpf_ringbuf_reserve(&shm_events, sizeof(*ev), 0); if (!ev) return 0; diff --git a/kernel/swap_arena_kern.c b/kernel/swap_arena_kern.c new file mode 100644 index 00000000..cd3104ae --- /dev/null +++ b/kernel/swap_arena_kern.c @@ -0,0 +1,21 @@ +#define KBUILD_MODNAME "swap_arena_kern" +#include +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) +#include +#else +#include +#endif +#include "bpf_tracing.h" +#include "bpf_helpers.h" +#include "netdata_arena_common.h" +#include "netdata_swap_arena.h" + +struct netdata_swap_arena_state_t swap_arena_state __arena_global; + +#define NETDATA_BPF_RINGBUF_DEF(NAME, MAX_ENTRIES) NETDATA_BPF_ARENA_DEF(NAME, MAX_ENTRIES) +#define bpf_ringbuf_reserve(MAP, SIZE, FLAGS) netdata_swap_arena_reserve() +#define bpf_ringbuf_submit(EV, FLAGS) netdata_swap_arena_submit(EV) + +#include "swap_buffer_kern.c" diff --git a/kernel/swap_buffer_kern.c b/kernel/swap_buffer_kern.c index cd740782..f0cf8183 100644 --- a/kernel/swap_buffer_kern.c +++ b/kernel/swap_buffer_kern.c @@ -10,6 +10,7 @@ #include "bpf_tracing.h" #include "bpf_helpers.h" #include "netdata_common.h" +#include "netdata_arena_common.h" #include "netdata_swap.h" #include "netdata_swap_buffer.h" @@ -29,15 +30,23 @@ NETDATA_BPF_ARRAY_DEF(swap_ctrl, __u32, __u64, NETDATA_CONTROLLER_END); * ***********************************************************************************/ -static __always_inline void netdata_swap_fill_event(struct netdata_swap_event_t *ev, void *ctrl) +static __always_inline void netdata_swap_fill_event(struct netdata_swap_event_t __arena *ev, void *ctrl) { __u32 tgid = 0; + char comm[TASK_COMM_LEN]; ev->ct = bpf_ktime_get_ns(); ev->pid = netdata_get_pid(ctrl, &tgid); ev->tgid = tgid; - libnetdata_update_uid_gid(&ev->uid, &ev->gid); + { + __u64 uid_gid = bpf_get_current_uid_gid(); + ev->uid = (__u32)uid_gid; + ev->gid = (__u32)(uid_gid >> 32); + } #if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) - bpf_get_current_comm(ev->name, TASK_COMM_LEN); + bpf_get_current_comm(comm, TASK_COMM_LEN); +#pragma unroll + for (int i = 0; i < TASK_COMM_LEN; i++) + ev->name[i] = comm[i]; #else ev->name[0] = '\0'; #endif @@ -62,7 +71,7 @@ int netdata_swap_readpage_buffer(struct pt_regs *ctx) if (!monitor_apps(&swap_ctrl)) return 0; - struct netdata_swap_event_t *ev = bpf_ringbuf_reserve(&swap_events, sizeof(*ev), 0); + struct netdata_swap_event_t __arena *ev = bpf_ringbuf_reserve(&swap_events, sizeof(*ev), 0); if (!ev) return 0; @@ -85,7 +94,7 @@ int netdata_swap_writepage_buffer(struct pt_regs *ctx) if (!monitor_apps(&swap_ctrl)) return 0; - struct netdata_swap_event_t *ev = bpf_ringbuf_reserve(&swap_events, sizeof(*ev), 0); + struct netdata_swap_event_t __arena *ev = bpf_ringbuf_reserve(&swap_events, sizeof(*ev), 0); if (!ev) return 0; diff --git a/kernel/vfs_arena_kern.c b/kernel/vfs_arena_kern.c new file mode 100644 index 00000000..8a469656 --- /dev/null +++ b/kernel/vfs_arena_kern.c @@ -0,0 +1,25 @@ +#define KBUILD_MODNAME "vfs_arena_kern" +#include +#include +#include +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,10,17)) +# include +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) +#include +#else +#include +#endif +#include "bpf_tracing.h" +#include "bpf_helpers.h" +#include "netdata_arena_common.h" +#include "netdata_vfs_arena.h" + +struct netdata_vfs_arena_state_t vfs_arena_state __arena_global; + +#define NETDATA_BPF_RINGBUF_DEF(NAME, MAX_ENTRIES) NETDATA_BPF_ARENA_DEF(NAME, MAX_ENTRIES) +#define bpf_ringbuf_reserve(MAP, SIZE, FLAGS) netdata_vfs_arena_reserve() +#define bpf_ringbuf_submit(EV, FLAGS) netdata_vfs_arena_submit(EV) + +#include "vfs_buffer_kern.c" diff --git a/kernel/vfs_buffer_kern.c b/kernel/vfs_buffer_kern.c index 3799638c..3b26eeb3 100644 --- a/kernel/vfs_buffer_kern.c +++ b/kernel/vfs_buffer_kern.c @@ -14,6 +14,7 @@ #include "bpf_tracing.h" #include "bpf_helpers.h" #include "netdata_common.h" +#include "netdata_arena_common.h" #include "netdata_vfs.h" #include "netdata_vfs_buffer.h" @@ -33,15 +34,23 @@ NETDATA_BPF_ARRAY_DEF(vfs_ctrl, __u32, __u64, NETDATA_CONTROLLER_END); * ***********************************************************************************/ -static __always_inline void netdata_vfs_fill_event(struct netdata_vfs_event_t *ev, void *ctrl) +static __always_inline void netdata_vfs_fill_event(struct netdata_vfs_event_t __arena *ev, void *ctrl) { __u32 tgid = 0; + char comm[TASK_COMM_LEN]; ev->ct = bpf_ktime_get_ns(); ev->pid = netdata_get_pid(ctrl, &tgid); ev->tgid = tgid; - libnetdata_update_uid_gid(&ev->uid, &ev->gid); + { + __u64 uid_gid = bpf_get_current_uid_gid(); + ev->uid = (__u32)uid_gid; + ev->gid = (__u32)(uid_gid >> 32); + } #if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0)) - bpf_get_current_comm(ev->name, TASK_COMM_LEN); + bpf_get_current_comm(comm, TASK_COMM_LEN); +#pragma unroll + for (int i = 0; i < TASK_COMM_LEN; i++) + ev->name[i] = comm[i]; #else ev->name[0] = '\0'; #endif @@ -78,7 +87,7 @@ int netdata_sys_write_buffer(struct pt_regs *ctx) if (!monitor_apps(&vfs_ctrl)) return 0; - struct netdata_vfs_event_t *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); + struct netdata_vfs_event_t __arena *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); if (!ev) return 0; @@ -115,7 +124,7 @@ int netdata_sys_writev_buffer(struct pt_regs *ctx) if (!monitor_apps(&vfs_ctrl)) return 0; - struct netdata_vfs_event_t *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); + struct netdata_vfs_event_t __arena *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); if (!ev) return 0; @@ -152,7 +161,7 @@ int netdata_sys_read_buffer(struct pt_regs *ctx) if (!monitor_apps(&vfs_ctrl)) return 0; - struct netdata_vfs_event_t *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); + struct netdata_vfs_event_t __arena *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); if (!ev) return 0; @@ -189,7 +198,7 @@ int netdata_sys_readv_buffer(struct pt_regs *ctx) if (!monitor_apps(&vfs_ctrl)) return 0; - struct netdata_vfs_event_t *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); + struct netdata_vfs_event_t __arena *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); if (!ev) return 0; @@ -224,7 +233,7 @@ int netdata_sys_unlink_buffer(struct pt_regs *ctx) if (!monitor_apps(&vfs_ctrl)) return 0; - struct netdata_vfs_event_t *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); + struct netdata_vfs_event_t __arena *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); if (!ev) return 0; @@ -259,7 +268,7 @@ int netdata_vfs_fsync_buffer(struct pt_regs *ctx) if (!monitor_apps(&vfs_ctrl)) return 0; - struct netdata_vfs_event_t *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); + struct netdata_vfs_event_t __arena *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); if (!ev) return 0; @@ -294,7 +303,7 @@ int netdata_vfs_open_buffer(struct pt_regs *ctx) if (!monitor_apps(&vfs_ctrl)) return 0; - struct netdata_vfs_event_t *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); + struct netdata_vfs_event_t __arena *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); if (!ev) return 0; @@ -329,7 +338,7 @@ int netdata_vfs_create_buffer(struct pt_regs *ctx) if (!monitor_apps(&vfs_ctrl)) return 0; - struct netdata_vfs_event_t *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); + struct netdata_vfs_event_t __arena *ev = bpf_ringbuf_reserve(&vfs_events, sizeof(*ev), 0); if (!ev) return 0; diff --git a/tests/tester_user.c b/tests/tester_user.c index d5356b11..58e8de20 100644 --- a/tests/tester_user.c +++ b/tests/tester_user.c @@ -41,6 +41,11 @@ static ebpf_specify_name_t swap_optional_name[] = { {.program_name = "netdata_sw .fallback_function_to_attach = "swap_writepage", .optional = NULL, .retprobe = 0}, + {.program_name = "netdata_swap_readpage_buffer", + .function_to_attach = "swap_read_folio", + .fallback_function_to_attach = "swap_readpage", + .optional = NULL, + .retprobe = 0}, {.program_name = "netdata_swap_writepage_buffer", .function_to_attach = "__swap_writepage", .fallback_function_to_attach = "swap_writepage", @@ -52,6 +57,18 @@ static ebpf_specify_name_t swap_optional_name[] = { {.program_name = "netdata_sw .optional = NULL, .retprobe = 0}}; +// close_fd replaced __close_fd in kernel 5.11; RH backported this rename to their 5.10 kernels. +static ebpf_specify_name_t fd_optional_name[] = { {.program_name = "netdata_close_buffer", + .function_to_attach = "close_fd", + .fallback_function_to_attach = "__close_fd", + .optional = NULL, + .retprobe = 0}, + {.program_name = NULL, + .function_to_attach = NULL, + .fallback_function_to_attach = NULL, + .optional = NULL, + .retprobe = 0}}; + // Versions 3_10, 4_18 and 5_14 must be always present to keep compatibility with RH family // Version 4_14, 4_16 must be present for syscalls with old name convention // Version 5_4 must be present for kernels newer than 4.17.0 @@ -60,9 +77,11 @@ ebpf_module_t ebpf_modules[] = { .flags = NETDATA_FLAG_BTRFS, .name = "btrfs", .update_names = NULL, .ctrl_table = "btrfs_ctrl" }, { .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_15 | NETDATA_V5_14 | NETDATA_V5_16, .buffer_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, + .arena_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, .flags = NETDATA_FLAG_CACHESTAT, .name = "cachestat", .update_names = NULL, .ctrl_table = "cstat_ctrl" }, { .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14, .buffer_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, + .arena_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, .flags = NETDATA_FLAG_DC, .name = "dc", .update_names = dc_optional_name, .ctrl_table = "dcstat_ctrl" }, { .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14, .flags = NETDATA_FLAG_DISK, .name = "disk", .update_names = NULL, .ctrl_table = "disk_ctrl" }, @@ -70,7 +89,8 @@ ebpf_module_t ebpf_modules[] = { .flags = NETDATA_FLAG_EXT4, .name = "ext4", .update_names = NULL, .ctrl_table = "ext4_ctrl" }, { .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_11 | NETDATA_V5_14, .buffer_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, - .flags = NETDATA_FLAG_FD, .name = "fd", .update_names = NULL, .ctrl_table = "fd_ctrl" }, + .arena_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, + .flags = NETDATA_FLAG_FD, .name = "fd", .update_names = fd_optional_name, .ctrl_table = "fd_ctrl" }, { .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14, .flags = NETDATA_FLAG_SYNC, .name = "fdatasync", .update_names = NULL, .ctrl_table = NULL }, { .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14, @@ -87,6 +107,7 @@ ebpf_module_t ebpf_modules[] = { .flags = NETDATA_FLAG_SOCKET, .name = "socket", .update_names = NULL, .ctrl_table = "socket_ctrl" }, { .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14, .buffer_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, + .arena_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, .flags = NETDATA_FLAG_DNS, .name = "dns", .update_names = NULL, .ctrl_table = NULL }, { .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14, .flags = NETDATA_FLAG_NFS, .name = "nfs", .update_names = NULL, .ctrl_table = "nfs_ctrl" }, @@ -94,12 +115,15 @@ ebpf_module_t ebpf_modules[] = { .flags = NETDATA_FLAG_NETWORK_VIEWER, .name = "network_viewer", .update_names = NULL, .ctrl_table = "nv_ctrl" }, { .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14, .buffer_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, + .arena_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, .flags = NETDATA_FLAG_OOMKILL, .name = "oomkill", .update_names = NULL, .ctrl_table = NULL }, { .kernels = NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14 | NETDATA_V5_10 | NETDATA_V6_12, .buffer_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, + .arena_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, .flags = NETDATA_FLAG_PROCESS, .name = "process", .update_names = NULL, .ctrl_table = "process_ctrl" }, { .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14, .buffer_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, + .arena_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, .flags = NETDATA_FLAG_SHM, .name = "shm", .update_names = NULL, .ctrl_table = "shm_ctrl" }, { .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14, .flags = NETDATA_FLAG_SOFTIRQ, .name = "softirq", .update_names = NULL, .ctrl_table = NULL }, @@ -111,9 +135,11 @@ ebpf_module_t ebpf_modules[] = { .flags = NETDATA_FLAG_SYNC, .name = "sync_file_range", .update_names = NULL, .ctrl_table = NULL }, { .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14 | NETDATA_V6_8 | NETDATA_V6_12, .buffer_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, + .arena_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, .flags = NETDATA_FLAG_SWAP, .name = "swap", .update_names = swap_optional_name, .ctrl_table = "swap_ctrl" }, { .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14, .buffer_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, + .arena_kernels = NETDATA_V5_10 | NETDATA_V5_11 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16 | NETDATA_V6_8 | NETDATA_V6_12, .flags = NETDATA_FLAG_VFS, .name = "vfs", .update_names = NULL, .ctrl_table = "vfs_ctrl" }, { .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14, .flags = NETDATA_FLAG_XFS, .name = "xfs", .update_names = NULL, .ctrl_table = "xfs_ctrl" }, @@ -127,6 +153,7 @@ char *specific_ebpf = NULL; char *netdata_path = NULL; char *log_path = NULL; int buffer_mode = 0; +int arena_mode = 0; #define NETDATA_DEFAULT_PROCESS_NUMBER 4096 #define NETDATA_DNS_MAX_PORTS 32 #define NETDATA_DNS_DEFAULT_PORT 53 @@ -449,6 +476,15 @@ static void ebpf_free_candidate_list(ebpf_candidate_list_t *list) memset(list, 0, sizeof(*list)); } +static const char *ebpf_mode_suffix(void) +{ + if (arena_mode) + return "_arena"; + if (buffer_mode) + return "_buffer"; + return ""; +} + static int ebpf_candidate_matches(const char *filename, const char *name, int is_return, const char *version, int rhf_version) { @@ -459,10 +495,7 @@ static int ebpf_candidate_matches(const char *filename, const char *name, int is const char *rest; int has_rhf; - if (buffer_mode) - snprintf(prefix, sizeof(prefix), "%cnetdata_ebpf_%s_buffer.", (is_return) ? 'r' : 'p', name); - else - snprintf(prefix, sizeof(prefix), "%cnetdata_ebpf_%s.", (is_return) ? 'r' : 'p', name); + snprintf(prefix, sizeof(prefix), "%cnetdata_ebpf_%s%s.", (is_return) ? 'r' : 'p', name, ebpf_mode_suffix()); prefix_len = strlen(prefix); if (filename_len <= prefix_len + 2) return 0; @@ -840,6 +873,40 @@ int ebpf_get_kernel_version() * * @param return It returns the Red Hat version on success and -1 otherwise. */ +/* Parse /etc/os-release to detect RH-family distros that lack /etc/redhat-release + * (e.g. minimal Alma 9 containers). Returns major*256+minor on match, -1 otherwise. */ +static int ebpf_get_rh_from_os_release(void) +{ + FILE *fp = fopen("/etc/os-release", "r"); + if (!fp) + return -1; + + char line[VERSION_STRING_LEN + 1]; + int major = 0, minor = 0, is_rhel = 0; + + while (fgets(line, sizeof(line), fp)) { + if (strncmp(line, "ID=", 3) == 0 || strncmp(line, "ID_LIKE=", 8) == 0) { + if (strstr(line, "rhel") || strstr(line, "centos") || + strstr(line, "almalinux") || strstr(line, "rocky")) + is_rhel = 1; + } else if (strncmp(line, "VERSION_ID=", 11) == 0) { + char *val = line + 11; + if (*val == '"') + val++; + char *endp; + major = (int)strtol(val, &endp, 10); + if (*endp == '.') + minor = (int)strtol(endp + 1, NULL, 10); + } + } + + fclose(fp); + + if (is_rhel && major > 0) + return major * 256 + minor; + return -1; +} + int ebpf_get_redhat_release() { char buffer[VERSION_STRING_LEN + 1]; @@ -876,9 +943,9 @@ int ebpf_get_redhat_release() fclose(fp); return ((major * 256) + minor); - } else { - return -1; } + + return ebpf_get_rh_from_os_release(); } /** @@ -1033,20 +1100,13 @@ static void ebpf_mount_name(char *out, size_t len, uint32_t kver, char *name, in if (!path) path = ebpf_strdup_string("."); - if (buffer_mode) - snprintf(out, len, "%s/%cnetdata_ebpf_%s_buffer.%s%s.o", - path, - (is_return) ? 'r' : 'p', - name, - version, - (rhf_version != -1) ? ".rhf" : ""); - else - snprintf(out, len, "%s/%cnetdata_ebpf_%s.%s%s.o", - path, - (is_return) ? 'r' : 'p', - name, - version, - (rhf_version != -1) ? ".rhf" : ""); + snprintf(out, len, "%s/%cnetdata_ebpf_%s%s.%s%s.o", + path, + (is_return) ? 'r' : 'p', + name, + ebpf_mode_suffix(), + version, + (rhf_version != -1) ? ".rhf" : ""); free(path); } @@ -1199,6 +1259,10 @@ static void ebpf_update_names(ebpf_specify_name_t *names) if (strncmp(cmp, data, len)) continue; + /* Reject prefix-only matches (e.g. "swap_read_folio_bdev_sync" != "swap_read_folio") */ + if (data[len] != ' ' && data[len] != '\n' && data[len] != '\0') + continue; + end = strchr(data, ' '); if (!end) end = strchr(data, '\n'); @@ -1785,6 +1849,30 @@ static int ebpf_module_has_buffer(const char *name) return 0; } +static int ebpf_module_has_arena(const char *name) +{ + const char *arena_modules[] = { + "cachestat", + "dc", + "fd", + "oomkill", + "process", + "shm", + "swap", + "vfs", + "dns", + NULL + }; + size_t i; + + for (i = 0; arena_modules[i]; i++) { + if (!strcmp(name, arena_modules[i])) + return 1; + } + + return 0; +} + static void ebpf_run_netdata_tests(int rhf_version, uint32_t kver, int is_return, uint64_t flags) { ebpf_map_support_t map_support; @@ -1793,6 +1881,11 @@ static void ebpf_run_netdata_tests(int rhf_version, uint32_t kver, int is_return ebpf_detect_map_support(&map_support, rhf_version, kver); while (ebpf_modules[i].name) { + if (arena_mode && !ebpf_module_has_arena(ebpf_modules[i].name)) { + i++; + continue; + } + if (buffer_mode && !ebpf_module_has_buffer(ebpf_modules[i].name)) { i++; continue; @@ -1804,8 +1897,10 @@ static void ebpf_run_netdata_tests(int rhf_version, uint32_t kver, int is_return char *first_incompatible = NULL; int unsupported_type = 0; size_t j; - uint32_t kernels_to_use = (buffer_mode && ebpf_modules[i].buffer_kernels) ? - ebpf_modules[i].buffer_kernels : ebpf_modules[i].kernels; + uint32_t kernels_to_use = (arena_mode && ebpf_modules[i].arena_kernels) ? + ebpf_modules[i].arena_kernels : + ((buffer_mode && ebpf_modules[i].buffer_kernels) ? + ebpf_modules[i].buffer_kernels : ebpf_modules[i].kernels); uint32_t max_idx = ebpf_select_max_index(rhf_version, kver); uint32_t idx = ebpf_select_index(kernels_to_use, rhf_version, kver); @@ -1905,7 +2000,8 @@ static void ebpf_help() "--content Test content stored inside hash tables.\n" "--iteration Number of iterations when content is read, default value is 1.\n" "--pid Specify the number that identifies PID that will be monitored: 0 - Real Parent PID (Default), 1 - Parent PID, 2 - All PID, and 3 - Ignore PID (ring buffer mode).\n" - "--buffer Test ring buffer versions of collectors (cachestat, dc, fd, oomkill, process, shm, swap, vfs, dns).\n\n" + "--buffer Test ring buffer versions of collectors (cachestat, dc, fd, oomkill, process, shm, swap, vfs, dns).\n" + "--arena Test arena versions of collectors (cachestat, dc, fd, oomkill, process, shm, swap, vfs, dns).\n\n" "You can also specify an unique eBPF program developed by Netdata with the following\n" "options:\n" "--btrfs Latency for btrfs.\n" @@ -1953,13 +2049,14 @@ static uint64_t ebpf_set_common_flag() * * Parse arguments given from command line. * - * @param argc is the number of arguments - * @param argv vector with values. - * @param kver is the current kernel version + * @param argc is the number of arguments + * @param argv vector with values. + * @param kver is the current kernel version + * @param rhf_version Red Hat family version (-1 if not RH) * * @return It returns the flags used during the simulation. */ -uint64_t ebpf_parse_arguments(int argc, char **argv, int kver) +uint64_t ebpf_parse_arguments(int argc, char **argv, int kver, int rhf_version) { uint64_t flags = 0; int option_index = 0; @@ -2000,6 +2097,7 @@ uint64_t ebpf_parse_arguments(int argc, char **argv, int kver) {"iteration", required_argument, 0, 0 }, {"pid", required_argument, 0, 0 }, {"buffer", no_argument, 0, 0 }, + {"arena", no_argument, 0, 0 }, // this must be always the last option {0, no_argument, 0, 0} @@ -2162,7 +2260,7 @@ uint64_t ebpf_parse_arguments(int argc, char **argv, int kver) case NETDATA_OPT_LOG_PATH: { log_path = optarg; - stdlog = fopen(log_path, "a+"); + stdlog = fopen(log_path, "w"); if (!stdlog) { stdlog = stderr; fprintf(stdlog, "\"Error\": \"Cannot open %s\",\n", log_path); @@ -2200,14 +2298,25 @@ uint64_t ebpf_parse_arguments(int argc, char **argv, int kver) flags |= NETDATA_FLAG_CONTENT; break; } + case NETDATA_OPT_ARENA: + { + arena_mode = 1; + flags |= NETDATA_FLAG_CONTENT; + break; + } } } - if (buffer_mode && kver < NETDATA_EBPF_KERNEL_5_8) { + if (buffer_mode && rhf_version == -1 && kver < NETDATA_EBPF_KERNEL_5_8) { fprintf(stdlog, "\"Error\" : \"Ring buffer support requires kernel >= 5.8, current version is not supported.\",\n"); exit(1); } + if (arena_mode && rhf_version == -1 && kver < NETDATA_EBPF_KERNEL_6_9) { + fprintf(stdlog, "\"Error\" : \"Arena support requires kernel >= 6.9, current version is not supported.\",\n"); + exit(1); + } + // When user does not specify any flag, we will use common value if (!(flags & NETDATA_FLAG_COLLECTORS)) flags |= ebpf_set_common_flag(); @@ -2229,6 +2338,7 @@ static void ebpf_fill_names() { ebpf_update_names(dc_optional_name); ebpf_update_names(swap_optional_name); + ebpf_update_names(fd_optional_name); } /** @@ -2240,6 +2350,7 @@ static void ebpf_clean_name_vectors() { ebpf_clean_optional(dc_optional_name); ebpf_clean_optional(swap_optional_name); + ebpf_clean_optional(fd_optional_name); } /** @@ -2283,7 +2394,7 @@ int main(int argc, char **argv) nprocesses = NETDATA_DEFAULT_PROCESS_NUMBER; } - uint64_t flags = ebpf_parse_arguments(argc, argv, my_kernel); + uint64_t flags = ebpf_parse_arguments(argc, argv, my_kernel, rhf_version); // Start JSON output fprintf(stdlog, "{"); diff --git a/tests/tester_user.h b/tests/tester_user.h index 51ef07f1..b598c7cc 100644 --- a/tests/tester_user.h +++ b/tests/tester_user.h @@ -53,6 +53,7 @@ enum netdata_ebpf_kernel_versions { NETDATA_EBPF_KERNEL_5_15 = 331520, // 331520 = 5 * 65536 + 15 * 256 NETDATA_EBPF_KERNEL_5_16 = 331776, // 331776 = 5 * 65536 + 16 * 256 NETDATA_EBPF_KERNEL_6_8 = 395264, // 395264 = 6 * 65536 + 8 * 256 + NETDATA_EBPF_KERNEL_6_9 = 395520, // 395520 = 6 * 65536 + 9 * 256 NETDATA_EBPF_KERNEL_6_12 = 396288 // 396288 = 6 * 65536 + 12 * 256 }; @@ -164,7 +165,8 @@ enum netdata_thread_OPT { NETDATA_OPT_CONTENT, NETDATA_OPT_ITERATION, NETDATA_OPT_PID, - NETDATA_OPT_BUFFER + NETDATA_OPT_BUFFER, + NETDATA_OPT_ARENA }; typedef struct ebpf_specify_name { @@ -178,6 +180,7 @@ typedef struct ebpf_specify_name { typedef struct ebpf_module { uint32_t kernels; uint32_t buffer_kernels; /* kernel bitmask for buffer mode; 0 = use kernels */ + uint32_t arena_kernels; /* kernel bitmask for arena mode; 0 = use kernels */ uint64_t flags; char *name; ebpf_specify_name_t *update_names;