summaryrefslogtreecommitdiff
path: root/internal/generate
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-19 15:00:02 +0300
committerPaul Buetow <paul@buetow.org>2026-05-19 15:00:02 +0300
commit71ef23ae16b0e310e66f3bf622cebefb9ec6b208 (patch)
treed61bc007207fbd3f4e21de34874de0248692b9b2 /internal/generate
parent9cc2c7b3c4c7a1f1837a4a5260f11ccea5814c83 (diff)
v6: add KindAccept and wire accept/accept4
Diffstat (limited to 'internal/generate')
-rw-r--r--internal/generate/bpfhandler.go9
-rw-r--r--internal/generate/classify.go17
-rw-r--r--internal/generate/classify_test.go49
-rw-r--r--internal/generate/codegen_test.go17
-rw-r--r--internal/generate/kindregistry.go1
-rw-r--r--internal/generate/testdata.go31
6 files changed, 119 insertions, 5 deletions
diff --git a/internal/generate/bpfhandler.go b/internal/generate/bpfhandler.go
index 50917e7..bada317 100644
--- a/internal/generate/bpfhandler.go
+++ b/internal/generate/bpfhandler.go
@@ -77,6 +77,8 @@ func generateExtra(tp GeneratedTracepoint, isEnter bool) string {
return generateExtraSocket()
case KindSocketpair:
return generateExtraSocketpair(isEnter)
+ case KindAccept:
+ return generateExtraAccept(isEnter)
case KindOpen:
return generateExtraOpen(f)
case KindPathname:
@@ -164,6 +166,13 @@ func generateExtraSocketpair(isEnter bool) string {
return " __s32 family = -1;\n __s32 type = -1;\n __s32 protocol = -1;\n __s32 sv0 = -1;\n __s32 sv1 = -1;\n struct socketpair_ctx *pending = bpf_map_lookup_elem(&socketpair_ctx_map, &tid);\n if (pending) {\n family = pending->family;\n type = pending->type;\n protocol = pending->protocol;\n if (ctx->ret == 0 && pending->usockvec != 0) {\n int sv[2];\n if (bpf_probe_read_user(&sv, sizeof(sv), (void *)pending->usockvec) == 0) {\n sv0 = (__s32)sv[0];\n sv1 = (__s32)sv[1];\n }\n }\n bpf_map_delete_elem(&socketpair_ctx_map, &tid);\n }\n ev->family = family;\n ev->type = type;\n ev->protocol = protocol;\n ev->sv0 = sv0;\n ev->sv1 = sv1;\n ev->ret = ctx->ret;\n"
}
+func generateExtraAccept(isEnter bool) string {
+ if isEnter {
+ return " ev->fd = (__s32)ctx->args[0];\n ev->ret = -1;\n"
+ }
+ return " ev->fd = -1;\n ev->ret = ctx->ret;\n"
+}
+
// eventStructName returns the C struct name for a TracepointKind. The mapping
// is driven by kindRegistry so adding a new kind only requires a registry entry.
func eventStructName(kind TracepointKind) string {
diff --git a/internal/generate/classify.go b/internal/generate/classify.go
index 56f5cd2..abe6b2e 100644
--- a/internal/generate/classify.go
+++ b/internal/generate/classify.go
@@ -17,6 +17,7 @@ const (
KindOpenByHandleAt
KindSocket
KindSocketpair
+ KindAccept
)
type RetClassification string
@@ -87,6 +88,22 @@ func classifyNameOnly(name string) (ClassificationResult, bool) {
return ClassificationResult{Kind: KindSocketpair}, true
case "sys_exit_socketpair":
return ClassificationResult{Kind: KindSocketpair}, true
+ case "sys_enter_accept":
+ return ClassificationResult{Kind: KindAccept}, true
+ case "sys_exit_accept":
+ return ClassificationResult{Kind: KindAccept}, true
+ case "sys_enter_accept4":
+ return ClassificationResult{Kind: KindAccept}, true
+ case "sys_exit_accept4":
+ return ClassificationResult{Kind: KindAccept}, true
+ case "sys_enter_bind":
+ return ClassificationResult{Kind: KindFd}, true
+ case "sys_enter_connect":
+ return ClassificationResult{Kind: KindFd}, true
+ case "sys_enter_listen":
+ return ClassificationResult{Kind: KindFd}, true
+ case "sys_enter_shutdown":
+ 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 e6353b5..07cfe49 100644
--- a/internal/generate/classify_test.go
+++ b/internal/generate/classify_test.go
@@ -237,10 +237,49 @@ func TestClassifyPathnameExecve(t *testing.T) {
}
}
-func TestClassifyFdAccept(t *testing.T) {
+func TestClassifyAccept(t *testing.T) {
r := classifyFromData(t, FormatAccept)
- if r.Kind != KindFd {
- t.Errorf("accept: got kind %d, want KindFd", r.Kind)
+ if r.Kind != KindAccept {
+ t.Errorf("accept: got kind %d, want KindAccept", r.Kind)
+ }
+}
+
+func TestClassifyAccept4(t *testing.T) {
+ r := classifyFromData(t, FormatAccept4)
+ if r.Kind != KindAccept {
+ t.Errorf("accept4: got kind %d, want KindAccept", r.Kind)
+ }
+}
+
+func TestClassifyExitAccept(t *testing.T) {
+ r := classifyFromData(t, FormatExitAccept)
+ if r.Kind != KindAccept {
+ t.Errorf("exit_accept: got kind %d, want KindAccept", r.Kind)
+ }
+}
+
+func TestClassifyExitAccept4(t *testing.T) {
+ r := classifyFromData(t, FormatExitAccept4)
+ if r.Kind != KindAccept {
+ t.Errorf("exit_accept4: got kind %d, want KindAccept", r.Kind)
+ }
+}
+
+func TestClassifySocketLifecycleFdSyscallsByName(t *testing.T) {
+ tests := []string{"bind", "connect", "listen", "shutdown"}
+ for _, name := range tests {
+ t.Run(name, func(t *testing.T) {
+ r := ClassifyFormat(&Format{
+ Name: "sys_enter_" + name,
+ ExternalFields: []Field{
+ {Type: "long", Name: "__syscall_nr"},
+ {Type: "int", Name: "sockfd"},
+ },
+ })
+ if r.Kind != KindFd {
+ t.Errorf("%s: got kind %d, want KindFd", name, r.Kind)
+ }
+ })
}
}
@@ -301,7 +340,8 @@ func TestClassifySyscallPairAccepted(t *testing.T) {
{"symlink", FormatSymlink, FormatExitSymlink, KindName},
{"mknod", FormatMknod, FormatExitMknod, KindPathname},
{"execve", FormatExecve, FormatExitExecve, KindPathname},
- {"accept", FormatAccept, FormatExitAccept, KindFd},
+ {"accept", FormatAccept, FormatExitAccept, KindAccept},
+ {"accept4", FormatAccept4, FormatExitAccept4, KindAccept},
{"socket", FormatSocket, FormatExitSocket, KindSocket},
{"socketpair", FormatSocketpair, FormatExitSocketpair, KindSocketpair},
{"kill", FormatKill, FormatExitKill, KindNull},
@@ -328,6 +368,7 @@ func TestClassifySyscallPairEmitsAllFamilies(t *testing.T) {
{"mknod", FormatMknod, FormatExitMknod, FamilyFS},
{"execve", FormatExecve, FormatExitExecve, FamilyProcess},
{"accept", FormatAccept, FormatExitAccept, FamilyNetwork},
+ {"accept4", FormatAccept4, FormatExitAccept4, FamilyNetwork},
{"socket", FormatSocket, FormatExitSocket, FamilyNetwork},
{"socketpair", FormatSocketpair, FormatExitSocketpair, FamilyNetwork},
{"kill", FormatKill, FormatExitKill, FamilySignals},
diff --git a/internal/generate/codegen_test.go b/internal/generate/codegen_test.go
index 3e29612..d8130c8 100644
--- a/internal/generate/codegen_test.go
+++ b/internal/generate/codegen_test.go
@@ -212,6 +212,19 @@ func TestGenerateSocketpairHandler(t *testing.T) {
requireContains(t, output, "ev->family = pending.family;")
}
+func TestGenerateAcceptHandler(t *testing.T) {
+ output := generateFromPair(t, FormatAccept, FormatExitAccept)
+
+ requireContains(t, output, "struct accept_event *ev")
+ requireContains(t, output, "ev->event_type = ENTER_ACCEPT_EVENT;")
+ requireContains(t, output, "ev->fd = (__s32)ctx->args[0];")
+ requireContains(t, output, "ev->ret = -1;")
+ requireContains(t, output, "SEC(\"tracepoint/syscalls/sys_exit_accept\")")
+ requireContains(t, output, "ev->event_type = EXIT_ACCEPT_EVENT;")
+ requireContains(t, output, "ev->fd = -1;")
+ requireContains(t, output, "ev->ret = ctx->ret;")
+}
+
func TestGenerateNameToHandleAtHandler(t *testing.T) {
output := generateFromPair(t, FormatNameToHandleAt, FormatExitNameToHandleAt)
@@ -321,6 +334,7 @@ func TestGenerateAllEventTypes(t *testing.T) {
{KindOpenByHandleAt, "ENTER_OPEN_BY_HANDLE_AT_EVENT", "EXIT_OPEN_BY_HANDLE_AT_EVENT"},
{KindSocket, "ENTER_SOCKET_EVENT", "EXIT_SOCKET_EVENT"},
{KindSocketpair, "ENTER_SOCKETPAIR_EVENT", "EXIT_SOCKETPAIR_EVENT"},
+ {KindAccept, "ENTER_ACCEPT_EVENT", "EXIT_ACCEPT_EVENT"},
}
for _, tt := range tests {
@@ -349,6 +363,7 @@ func TestEventStructNames(t *testing.T) {
{KindOpenByHandleAt, "open_by_handle_at_event"},
{KindSocket, "socket_event"},
{KindSocketpair, "socketpair_event"},
+ {KindAccept, "accept_event"},
}
for _, tt := range tests {
@@ -367,7 +382,7 @@ func TestEnterReject(t *testing.T) {
t.Error("KindNone should be enter-rejected")
}
- accepted := []TracepointKind{KindFd, KindOpen, KindPathname, KindName, KindFcntl, KindNull, KindDup3, KindOpenByHandleAt, KindSocket, KindSocketpair}
+ accepted := []TracepointKind{KindFd, KindOpen, KindPathname, KindName, KindFcntl, KindNull, KindDup3, KindOpenByHandleAt, KindSocket, KindSocketpair, KindAccept}
for _, k := range accepted {
if isEnterRejected(k) {
t.Errorf("kind %d should NOT be enter-rejected", k)
diff --git a/internal/generate/kindregistry.go b/internal/generate/kindregistry.go
index f716489..186dbbc 100644
--- a/internal/generate/kindregistry.go
+++ b/internal/generate/kindregistry.go
@@ -27,6 +27,7 @@ var kindRegistry = map[TracepointKind]kindMeta{
KindOpenByHandleAt: {structName: "open_by_handle_at_event", enterAccepted: true},
KindSocket: {structName: "socket_event", enterAccepted: true},
KindSocketpair: {structName: "socketpair_event", enterAccepted: true},
+ KindAccept: {structName: "accept_event", enterAccepted: true},
// KindNone is intentionally absent: it represents "unclassified" and is
// never enter-accepted. lookupKind returns the zero kindMeta (enterAccepted=false)
// for any unregistered kind, so KindNone is implicitly rejected.
diff --git a/internal/generate/testdata.go b/internal/generate/testdata.go
index e363a68..090619b 100644
--- a/internal/generate/testdata.go
+++ b/internal/generate/testdata.go
@@ -793,6 +793,37 @@ format:
print fmt: "0x%lx", REC->ret
`
+const FormatAccept4 = `name: sys_enter_accept4
+ID: 1810
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:int __syscall_nr; offset:8; size:4; signed:1;
+ field:int fd; offset:16; size:8; signed:0;
+ field:struct sockaddr * upeer_sockaddr; offset:24; size:8; signed:0;
+ field:int * upeer_addrlen; offset:32; size:8; signed:0;
+ field:int flags; offset:40; size:8; signed:0;
+
+print fmt: "fd: 0x%08lx, upeer_sockaddr: 0x%08lx, upeer_addrlen: 0x%08lx, flags: 0x%08lx", ((unsigned long)(REC->fd)), ((unsigned long)(REC->upeer_sockaddr)), ((unsigned long)(REC->upeer_addrlen)), ((unsigned long)(REC->flags))
+`
+
+const FormatExitAccept4 = `name: sys_exit_accept4
+ID: 1809
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:int __syscall_nr; offset:8; size:4; signed:1;
+ field:long ret; offset:16; size:8; signed:1;
+
+print fmt: "0x%lx", REC->ret
+`
+
const FormatSocket = `name: sys_enter_socket
ID: 1818
format: