From 061fb2b2380752eed06a78d10567da172ea8e27c Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Tue, 19 May 2026 15:47:09 +0300 Subject: w6: extend KindFd socket introspection coverage --- cmd/ioworkload/scenario_socket.go | 54 ++++++++++++++++++++++++++++++++++++++ cmd/ioworkload/scenarios.go | 1 + integrationtests/socket_test.go | 14 ++++++++++ internal/generate/classify.go | 8 ++++++ internal/generate/classify_test.go | 13 +++++++-- 5 files changed, 88 insertions(+), 2 deletions(-) diff --git a/cmd/ioworkload/scenario_socket.go b/cmd/ioworkload/scenario_socket.go index db95ad4..420cdfb 100644 --- a/cmd/ioworkload/scenario_socket.go +++ b/cmd/ioworkload/scenario_socket.go @@ -120,3 +120,57 @@ func socketAcceptLifecyclePlain() error { } return nil } + +func socketIntrospection() error { + dir, cleanup, err := makeTempDir("socket-introspection") + if err != nil { + return err + } + defer cleanup() + + socketPath := filepath.Join(dir, "introspection.sock") + + listenerFD, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_STREAM, 0) + if err != nil { + return fmt.Errorf("listener socket: %w", err) + } + defer syscall.Close(listenerFD) //nolint:errcheck + + if err := syscall.Bind(listenerFD, &syscall.SockaddrUnix{Name: socketPath}); err != nil { + return fmt.Errorf("bind: %w", err) + } + if err := syscall.Listen(listenerFD, 1); err != nil { + return fmt.Errorf("listen: %w", err) + } + + clientFD, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_STREAM, 0) + if err != nil { + return fmt.Errorf("client socket: %w", err) + } + defer syscall.Close(clientFD) //nolint:errcheck + + if err := syscall.Connect(clientFD, &syscall.SockaddrUnix{Name: socketPath}); err != nil { + return fmt.Errorf("connect: %w", err) + } + + acceptedFD, _, err := syscall.Accept4(listenerFD, 0) + if err != nil { + return fmt.Errorf("accept4: %w", err) + } + defer syscall.Close(acceptedFD) //nolint:errcheck + + if _, err := syscall.Getsockname(acceptedFD); err != nil { + return fmt.Errorf("getsockname: %w", err) + } + if _, err := syscall.Getpeername(acceptedFD); err != nil { + return fmt.Errorf("getpeername: %w", err) + } + if err := syscall.SetsockoptInt(acceptedFD, syscall.SOL_SOCKET, syscall.SO_RCVBUF, 32768); err != nil { + return fmt.Errorf("setsockopt: %w", err) + } + if _, err := syscall.GetsockoptInt(acceptedFD, syscall.SOL_SOCKET, syscall.SO_RCVBUF); err != nil { + return fmt.Errorf("getsockopt: %w", err) + } + + return nil +} diff --git a/cmd/ioworkload/scenarios.go b/cmd/ioworkload/scenarios.go index 5648801..9700d85 100644 --- a/cmd/ioworkload/scenarios.go +++ b/cmd/ioworkload/scenarios.go @@ -29,6 +29,7 @@ var scenarios = map[string]func() error{ "socketpair-basic": socketpairBasic, "socket-accept-lifecycle": socketAcceptLifecycle, "socket-accept-lifecycle-plain": socketAcceptLifecyclePlain, + "socket-introspection": socketIntrospection, "family-mixed": familyMixed, "close-basic": closeBasic, "close-range": closeRange, diff --git a/integrationtests/socket_test.go b/integrationtests/socket_test.go index 4967c6e..059d339 100644 --- a/integrationtests/socket_test.go +++ b/integrationtests/socket_test.go @@ -75,6 +75,20 @@ func TestSocketAcceptLifecyclePlain(t *testing.T) { }) } +func TestSocketIntrospection(t *testing.T) { + result, _ := runScenarioResult(t, "socket-introspection", []ExpectedEvent{ + {Tracepoint: "enter_getsockname", MinCount: 1}, + {Tracepoint: "enter_getpeername", MinCount: 1}, + {Tracepoint: "enter_setsockopt", MinCount: 1}, + {Tracepoint: "enter_getsockopt", MinCount: 1}, + }) + + assertTracepointPathPrefix(t, result, "enter_getsockname", "socket:1:") + assertTracepointPathPrefix(t, result, "enter_getpeername", "socket:1:") + assertTracepointPathPrefix(t, result, "enter_setsockopt", "socket:1:") + assertTracepointPathPrefix(t, result, "enter_getsockopt", "socket:1:") +} + func assertTracepointPathPrefix(t *testing.T, result TestResult, tracepoint, wantPrefix string) { t.Helper() if got := countTracepointPathPrefix(result, tracepoint, wantPrefix); got == 0 { diff --git a/internal/generate/classify.go b/internal/generate/classify.go index abe6b2e..4f6d14c 100644 --- a/internal/generate/classify.go +++ b/internal/generate/classify.go @@ -104,6 +104,14 @@ func classifyNameOnly(name string) (ClassificationResult, bool) { return ClassificationResult{Kind: KindFd}, true case "sys_enter_shutdown": return ClassificationResult{Kind: KindFd}, true + case "sys_enter_getsockname": + return ClassificationResult{Kind: KindFd}, true + case "sys_enter_getpeername": + return ClassificationResult{Kind: KindFd}, true + case "sys_enter_getsockopt": + return ClassificationResult{Kind: KindFd}, true + case "sys_enter_setsockopt": + return ClassificationResult{Kind: KindFd}, true } if strings.HasPrefix(name, "sys_enter_io_") { return ClassificationResult{Kind: KindNull}, true diff --git a/internal/generate/classify_test.go b/internal/generate/classify_test.go index 07cfe49..5c7111f 100644 --- a/internal/generate/classify_test.go +++ b/internal/generate/classify_test.go @@ -265,8 +265,17 @@ func TestClassifyExitAccept4(t *testing.T) { } } -func TestClassifySocketLifecycleFdSyscallsByName(t *testing.T) { - tests := []string{"bind", "connect", "listen", "shutdown"} +func TestClassifySocketFdSyscallsByName(t *testing.T) { + tests := []string{ + "bind", + "connect", + "listen", + "shutdown", + "getsockname", + "getpeername", + "getsockopt", + "setsockopt", + } for _, name := range tests { t.Run(name, func(t *testing.T) { r := ClassifyFormat(&Format{ -- cgit v1.2.3