[CWS] Add io_uring socket/splice/ftruncate hooks + tests#52494
[CWS] Add io_uring socket/splice/ftruncate hooks + tests#52494danielmercier wants to merge 2 commits into
Conversation
|
All contributors have signed the CLA ✍️ ✅ |
|
🎯 Code Coverage (details) 🔗 Commit SHA: bb9b350 | Docs | Datadog PR Page | Give us feedback! |
f2e128d to
e4aae80
Compare
Files inventory check summaryFile checks results against ancestor 66a3cda3: Results for datadog-agent_7.82.0~devel.git.620.bb9b350.pipeline.122616201-1_amd64.deb:No change detected |
Static quality checks✅ Please find below the results from static quality gates Successful checksInfo
19 successful checks with minimal change (< 2 KiB)
|
Regression DetectorRegression Detector ResultsMetrics dashboard Baseline: 66a3cda Optimization Goals: ✅ No significant changes detected
|
| perf | experiment | goal | Δ mean % | Δ mean % CI | trials | links |
|---|---|---|---|---|---|---|
| ➖ | quality_gate_idle_all_features | memory utilization | +0.19 | [+0.15, +0.23] | 1 | Logs bounds checks dashboard |
| ➖ | quality_gate_idle | memory utilization | +0.11 | [+0.05, +0.16] | 1 | Logs bounds checks dashboard |
| ➖ | quality_gate_security_no_fs_load | memory utilization | -0.12 | [-0.22, -0.02] | 1 | Logs bounds checks dashboard |
| ➖ | quality_gate_security_idle | memory utilization | -0.15 | [-0.22, -0.09] | 1 | Logs bounds checks dashboard |
| ➖ | quality_gate_security_mean_fs_load | memory utilization | -0.34 | [-0.38, -0.30] | 1 | Logs bounds checks dashboard |
| ➖ | quality_gate_logs | % cpu utilization | -0.91 | [-1.98, +0.16] | 1 | Logs bounds checks dashboard |
| ➖ | quality_gate_metrics_logs | memory utilization | -1.75 | [-2.00, -1.51] | 1 | Logs bounds checks dashboard |
Bounds Checks: ✅ Passed
| perf | experiment | bounds_check_name | replicates_passed | observed_value | links |
|---|---|---|---|---|---|
| ✅ | quality_gate_idle | intake_connections | 10/10 | 3 ≤ 4 | bounds checks dashboard |
| ✅ | quality_gate_idle | memory_usage | 10/10 | 146.69MiB ≤ 154MiB | bounds checks dashboard |
| ✅ | quality_gate_idle | total_bytes_received | 10/10 | 579.20KiB ≤ 819.20KiB | bounds checks dashboard |
| ✅ | quality_gate_idle_all_features | intake_connections | 10/10 | 3 ≤ 4 | bounds checks dashboard |
| ✅ | quality_gate_idle_all_features | memory_usage | 10/10 | 489.31MiB ≤ 495MiB | bounds checks dashboard |
| ✅ | quality_gate_idle_all_features | total_bytes_received | 10/10 | 0.89MiB ≤ 1.25MiB | bounds checks dashboard |
| ✅ | quality_gate_logs | intake_connections | 10/10 | 3 ≤ 6 | bounds checks dashboard |
| ✅ | quality_gate_logs | memory_usage | 10/10 | 182.09MiB ≤ 195MiB | bounds checks dashboard |
| ✅ | quality_gate_logs | missed_bytes | 10/10 | 0B = 0B | bounds checks dashboard |
| ✅ | quality_gate_logs | total_bytes_received | 10/10 | 264.20MiB ≤ 292MiB | bounds checks dashboard |
| ✅ | quality_gate_metrics_logs | cpu_usage | 10/10 | 340.46 ≤ 2000 | bounds checks dashboard |
| ✅ | quality_gate_metrics_logs | intake_connections | 10/10 | 3 ≤ 6 | bounds checks dashboard |
| ✅ | quality_gate_metrics_logs | memory_usage | 10/10 | 392.57MiB ≤ 430MiB | bounds checks dashboard |
| ✅ | quality_gate_metrics_logs | missed_bytes | 10/10 | 0B = 0B | bounds checks dashboard |
| ✅ | quality_gate_metrics_logs | total_bytes_received | 10/10 | 0.86GiB ≤ 1.04GiB | bounds checks dashboard |
| ✅ | quality_gate_security_idle | cpu_usage | 10/10 | 28.91 ≤ 40 | bounds checks dashboard |
| ✅ | quality_gate_security_idle | memory_usage | 10/10 | 297.08MiB ≤ 330MiB | bounds checks dashboard |
| ✅ | quality_gate_security_mean_fs_load | cpu_usage | 10/10 | 63.38 ≤ 80 | bounds checks dashboard |
| ✅ | quality_gate_security_mean_fs_load | memory_usage | 10/10 | 275.35MiB ≤ 310MiB | bounds checks dashboard |
| ✅ | quality_gate_security_no_fs_load | cpu_usage | 10/10 | 23.16 ≤ 40 | bounds checks dashboard |
| ✅ | quality_gate_security_no_fs_load | memory_usage | 10/10 | 282.00MiB ≤ 320MiB | bounds checks dashboard |
Explanation
Confidence level: 90.00%
Effect size tolerance: |Δ mean %| ≥ 5.00%
Performance changes are noted in the perf column of each table:
- ✅ = significantly better comparison variant performance
- ❌ = significantly worse comparison variant performance
- ➖ = no significant change in performance
A regression test is an A/B test of target performance in a repeatable rig, where "performance" is measured as "comparison variant minus baseline variant" for an optimization goal (e.g., ingress throughput). Due to intrinsic variability in measuring that goal, we can only estimate its mean value for each experiment; we report uncertainty in that value as a 90.00% confidence interval denoted "Δ mean % CI".
For each experiment, we decide whether a change in performance is a "regression" -- a change worth investigating further -- if all of the following criteria are true:
-
Its estimated |Δ mean %| ≥ 5.00%, indicating the change is big enough to merit a closer look.
-
Its 90.00% confidence interval "Δ mean % CI" does not contain zero, indicating that if our statistical model is accurate, there is at least a 90.00% chance there is a difference in performance between baseline and comparison variants.
-
Its configuration does not mark it "erratic".
Replicate Execution Details
We run multiple replicates for each experiment/variant. However, we allow replicates to be automatically retried if there are any failures, up to 8 times, at which point the replicate is marked dead and we are unable to run analysis for the entire experiment. We call each of these attempts at running replicates a replicate execution. This section lists all replicate executions that failed due to the target crashing or being oom killed.
Note: In the below tables we bucket failures by experiment, variant, and failure type. For each of these buckets we list out the replicate indexes that failed with an annotation signifying how many times said replicate failed with the given failure mode. In the below example the baseline variant of the experiment named experiment_with_failures had two replicates that failed by oom kills. Replicate 0, which failed 8 executions, and replicate 1 which failed 6 executions, all with the same failure mode.
| Experiment | Variant | Replicates | Failure | Logs | Debug Dashboard |
|---|---|---|---|---|---|
| experiment_with_failures | baseline | 0 (x8) 1 (x6) | Oom killed | Debug Dashboard |
The debug dashboard links will take you to a debugging dashboard specifically designed to investigate replicate execution failures.
❌ Retried Profiling Replicate Execution Failures (ddprof)
Note: Profiling replicas may still be executing. See the debug dashboard for up to date status.
| Experiment | Variant | Replicates | Failure | Debug Dashboard |
|---|---|---|---|---|
| quality_gate_idle | baseline | 10 | Oom killed | Debug Dashboard |
| quality_gate_idle | comparison | 10 | Oom killed | Debug Dashboard |
| quality_gate_idle_all_features | baseline | 10 | Oom killed | Debug Dashboard |
| quality_gate_idle_all_features | comparison | 10 | Oom killed | Debug Dashboard |
| quality_gate_logs | baseline | 10 | Oom killed | Debug Dashboard |
| quality_gate_logs | comparison | 10 | Oom killed | Debug Dashboard |
| quality_gate_metrics_logs | baseline | 10 | Oom killed | Debug Dashboard |
| quality_gate_metrics_logs | comparison | 10 | Oom killed | Debug Dashboard |
| quality_gate_security_idle | baseline | 10 | Oom killed | Debug Dashboard |
| quality_gate_security_idle | comparison | 10 | Oom killed | Debug Dashboard |
| quality_gate_security_mean_fs_load | baseline | 10 | Oom killed | Debug Dashboard |
| quality_gate_security_mean_fs_load | comparison | 10 | Oom killed | Debug Dashboard |
| quality_gate_security_no_fs_load | baseline | 10 | Oom killed | Debug Dashboard |
| quality_gate_security_no_fs_load | comparison | 10 | Oom killed | Debug Dashboard |
CI Pass/Fail Decision
✅ Passed. All Quality Gates passed.
- quality_gate_security_idle, bounds check memory_usage: 10/10 replicas passed. Gate passed.
- quality_gate_security_idle, bounds check cpu_usage: 10/10 replicas passed. Gate passed.
- quality_gate_metrics_logs, bounds check cpu_usage: 10/10 replicas passed. Gate passed.
- quality_gate_metrics_logs, bounds check total_bytes_received: 10/10 replicas passed. Gate passed.
- quality_gate_metrics_logs, bounds check memory_usage: 10/10 replicas passed. Gate passed.
- quality_gate_metrics_logs, bounds check intake_connections: 10/10 replicas passed. Gate passed.
- quality_gate_metrics_logs, bounds check missed_bytes: 10/10 replicas passed. Gate passed.
- quality_gate_idle, bounds check intake_connections: 10/10 replicas passed. Gate passed.
- quality_gate_idle, bounds check memory_usage: 10/10 replicas passed. Gate passed.
- quality_gate_idle, bounds check total_bytes_received: 10/10 replicas passed. Gate passed.
- quality_gate_security_no_fs_load, bounds check memory_usage: 10/10 replicas passed. Gate passed.
- quality_gate_security_no_fs_load, bounds check cpu_usage: 10/10 replicas passed. Gate passed.
- quality_gate_security_mean_fs_load, bounds check cpu_usage: 10/10 replicas passed. Gate passed.
- quality_gate_security_mean_fs_load, bounds check memory_usage: 10/10 replicas passed. Gate passed.
- quality_gate_logs, bounds check intake_connections: 10/10 replicas passed. Gate passed.
- quality_gate_logs, bounds check memory_usage: 10/10 replicas passed. Gate passed.
- quality_gate_logs, bounds check missed_bytes: 10/10 replicas passed. Gate passed.
- quality_gate_logs, bounds check total_bytes_received: 10/10 replicas passed. Gate passed.
- quality_gate_idle_all_features, bounds check memory_usage: 10/10 replicas passed. Gate passed.
- quality_gate_idle_all_features, bounds check total_bytes_received: 10/10 replicas passed. Gate passed.
- quality_gate_idle_all_features, bounds check intake_connections: 10/10 replicas passed. Gate passed.
e4aae80 to
8bbbd5a
Compare
|
recheck |
eBPF complexity changesSummary result: ❔ - needs attention
runtime_security detailsruntime_security [programs with changes]
runtime_security [programs without changes]
runtime_security_fentry detailsruntime_security_fentry [programs with changes]
runtime_security_fentry [programs without changes]
runtime_security_syscall_wrapper detailsruntime_security_syscall_wrapper [programs with changes]
runtime_security_syscall_wrapper [programs without changes]
This report was generated based on the complexity data for the current branch daniel.mercier/iouring-coverage-tests (pipeline 122616201, commit bb9b350) and the base branch main (commit 66a3cda). Objects without changes are not reported. Contact #ebpf-platform if you have any questions/feedback. Table complexity legend: 🔵 - new; ⚪ - unchanged; 🟢 - reduced; 🔴 - increased |
|
I have read the CLA Document and I hereby sign the CLA |
13d7bd8 to
4f6125c
Compare
976e90b to
8ed9148
Compare
8ed9148 to
a8bdce9
Compare
a8bdce9 to
2de46d2
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a8bdce91b0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
2de46d2 to
cee70c0
Compare
| OffsetNameRtnlLinkOpsKind: 16, | ||
| OffsetNameMntNamespaceNs: 8, | ||
| OffsetNameNsCommonInum: 16, | ||
| OffsetNameIoKiocbStructOpcode: 72, |
There was a problem hiding this comment.
IMO we should add a fallback for this one, ia pet generated me this (better double check first :)):
func getIoKcbOpcodeOffset(kv *kernel.Version) uint64 {
switch {
case kv.Code >= kernel.Kernel5_19:
// Since the introduction of io_uring commands, io_kiocb.opcode follows the
// embedded io_cmd_data union.
return 64
case kv.Code >= kernel.Kernel5_10:
return 72
case kv.Code >= kernel.Kernel5_7:
return 76
default:
// IORING_OP_SPLICE is not available before 5.7, but keep a best-effort
// fallback for older io_uring kernels.
return getIoKcbCtxOffset(kv) - 8
}
}
Adds a SKILL.md to automate io_uring coverage auditing, and closes the three gaps where CWS observed the syscall but emitted no event via io_uring by adding eBPF hooks for the opcodes (and tests): - IORING_OP_SOCKET: io_socket hooks; domain/type/protocol read via BTF-resolved LOAD_CONSTANT offsets on struct io_socket - IORING_OP_SPLICE: io_splice hooks, reusing the get_pipe_info path. We have to hook on io_issue_sqe instead because io_splice is inlined in some kernel versions. - IORING_OP_FTRUNCATE: io_ftruncate hooks, reusing do_truncate (observed as an open+O_TRUNC event; needs kernel 6.9+)
cee70c0 to
bb9b350
Compare
What does this PR do?
Closes the three gaps where CWS observed the syscall but emitted no event when issued through io_uring, by adding the missing eBPF hooks (plus tests, and a SKILL.md to automate future io_uring coverage audits):
io_sockethooks; domain/type/protocol read via BTF-resolvedLOAD_CONSTANToffsets onstruct io_socketio_splicehooks, reusing the get_pipe_info path. We have to hook onio_issue_sqeinstead becauseio_spliceis inlined in some kernel versions.io_ftruncatehooks, reusingdo_truncate(observed as an open+O_TRUNC event; requires kernel 6.9+)Motivation
Improve io_uring coverage: these opcodes were observed on the syscall path but produced no event via io_uring.
Describe how you validated your changes
Functional tests on a 6.8 kernel:
TestSpliceEvent/io_uringandTestSocketEvent/socket-af-inet-tcp-io-uringpass; controls (TestOpen/io_uring,TestAcceptEvent/...io-uring) still pass.TestOpen/io_uring_ftruncateskips below 6.9 and still needs verification on a 6.9+ kernel.Additional Notes