@wenathlan/saddle 1.8.17 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +1339 -0
- package/README.md +68 -22
- package/alternatives.ts +1218 -0
- package/biome.json +153 -0
- package/boards.json +1517 -0
- package/compute.ts +3144 -0
- package/cores.json +1801 -0
- package/dist/acquisition.d.ts +359 -0
- package/dist/acquisition.d.ts.map +1 -0
- package/dist/acquisition.js +629 -0
- package/dist/acquisition.js.map +1 -0
- package/dist/alternatives.d.ts +509 -0
- package/dist/alternatives.d.ts.map +1 -0
- package/dist/alternatives.js +951 -0
- package/dist/alternatives.js.map +1 -0
- package/dist/automation.d.ts +426 -0
- package/dist/automation.d.ts.map +1 -0
- package/dist/automation.js +561 -0
- package/dist/automation.js.map +1 -0
- package/dist/browser.d.ts +562 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +1057 -0
- package/dist/browser.js.map +1 -0
- package/dist/capacitor.config.d.ts +13 -0
- package/dist/capacitor.config.d.ts.map +1 -0
- package/dist/capacitor.config.js +26 -0
- package/dist/capacitor.config.js.map +1 -0
- package/dist/cli.d.ts +17 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +111 -0
- package/dist/cli.js.map +1 -0
- package/dist/communication.d.ts +192 -0
- package/dist/communication.d.ts.map +1 -0
- package/dist/communication.js +418 -0
- package/dist/communication.js.map +1 -0
- package/dist/compute.d.ts +1161 -0
- package/dist/compute.d.ts.map +1 -0
- package/dist/compute.js +2273 -0
- package/dist/compute.js.map +1 -0
- package/dist/distribution.d.ts +529 -0
- package/dist/distribution.d.ts.map +1 -0
- package/dist/distribution.js +811 -0
- package/dist/distribution.js.map +1 -0
- package/dist/execution.d.ts +530 -0
- package/dist/execution.d.ts.map +1 -0
- package/dist/execution.js +761 -0
- package/dist/execution.js.map +1 -0
- package/dist/format.d.ts +19 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +60 -0
- package/dist/format.js.map +1 -0
- package/dist/foundation.d.ts +176 -0
- package/dist/foundation.d.ts.map +1 -0
- package/dist/foundation.js +309 -0
- package/dist/foundation.js.map +1 -0
- package/dist/index.d.ts +733 -122
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1018 -122
- package/dist/index.js.map +1 -1
- package/dist/integration.d.ts +236 -0
- package/dist/integration.d.ts.map +1 -0
- package/dist/integration.js +236 -0
- package/dist/integration.js.map +1 -0
- package/dist/intelligence.d.ts +94 -0
- package/dist/intelligence.d.ts.map +1 -0
- package/dist/intelligence.js +145 -0
- package/dist/intelligence.js.map +1 -0
- package/dist/isolation.d.ts +129 -0
- package/dist/isolation.d.ts.map +1 -0
- package/dist/isolation.js +96 -0
- package/dist/isolation.js.map +1 -0
- package/dist/media.d.ts +344 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +986 -0
- package/dist/media.js.map +1 -0
- package/dist/modes.d.ts +359 -0
- package/dist/modes.d.ts.map +1 -0
- package/dist/modes.js +134 -0
- package/dist/modes.js.map +1 -0
- package/dist/{library/public.d.ts → operations.d.ts} +15 -1
- package/dist/operations.d.ts.map +1 -0
- package/dist/{library/public.js → operations.js} +18 -7
- package/dist/operations.js.map +1 -0
- package/dist/orchestrator.d.ts +1339 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +4308 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/performance.d.ts +416 -0
- package/dist/performance.d.ts.map +1 -0
- package/dist/performance.js +827 -0
- package/dist/performance.js.map +1 -0
- package/dist/quantum.d.ts +810 -0
- package/dist/quantum.d.ts.map +1 -0
- package/dist/quantum.js +2073 -0
- package/dist/quantum.js.map +1 -0
- package/dist/render.d.ts +381 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +1073 -0
- package/dist/render.js.map +1 -0
- package/dist/scheduler.d.ts +596 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +1259 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/security.d.ts +501 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +1170 -0
- package/dist/security.js.map +1 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/{server/node.js → server.js} +16 -2
- package/dist/server.js.map +1 -0
- package/dist/tiers.d.ts +1002 -0
- package/dist/tiers.d.ts.map +1 -0
- package/dist/tiers.js +2165 -0
- package/dist/tiers.js.map +1 -0
- package/dist/virtual.d.ts +641 -0
- package/dist/virtual.d.ts.map +1 -0
- package/dist/virtual.js +1285 -0
- package/dist/virtual.js.map +1 -0
- package/dist/virtualcpu.d.ts +316 -0
- package/dist/virtualcpu.d.ts.map +1 -0
- package/dist/virtualcpu.js +1180 -0
- package/dist/virtualcpu.js.map +1 -0
- package/dist/virtualgpu.d.ts +345 -0
- package/dist/virtualgpu.d.ts.map +1 -0
- package/dist/virtualgpu.js +1000 -0
- package/dist/virtualgpu.js.map +1 -0
- package/dist/virtualization.d.ts +607 -0
- package/dist/virtualization.d.ts.map +1 -0
- package/dist/virtualization.js +1187 -0
- package/dist/virtualization.js.map +1 -0
- package/dist/virtualmemory.d.ts +818 -0
- package/dist/virtualmemory.d.ts.map +1 -0
- package/dist/virtualmemory.js +1796 -0
- package/dist/virtualmemory.js.map +1 -0
- package/dist/webscrape.d.ts +720 -0
- package/dist/webscrape.d.ts.map +1 -0
- package/dist/webscrape.js +2697 -0
- package/dist/webscrape.js.map +1 -0
- package/docker.config +769 -0
- package/docs/CONVERSA.txt +1523 -0
- package/docs/alternatives.md +499 -0
- package/docs/architecture-1.8.19.md +76 -0
- package/docs/architecture-1.8.19.mmd +33 -0
- package/docs/architecture-1.8.19.png +0 -0
- package/docs/architecture.md +355 -0
- package/docs/artifactavailability.md +6 -0
- package/docs/brancharchive-2026-08-18.md +18 -0
- package/docs/browser.md +7 -0
- package/docs/consolidation.md +70 -0
- package/docs/e2ugh-engine.md +528 -0
- package/{dist/examples/localjob.js → docs/example-localjob.ts} +3 -3
- package/{dist/examples/publicapi.js → docs/example-publicapi.ts} +2 -2
- package/docs/hardware.md +342 -0
- package/docs/optimization.md +126 -0
- package/docs/performance.md +499 -0
- package/docs/planning.1.8.18.md +94 -0
- package/docs/planning.1.8.19.md +49 -0
- package/docs/releasenotes-1.8.17.md +6 -0
- package/docs/releasenotes-1.8.18.md +32 -0
- package/docs/releasenotes-1.8.19.md +35 -0
- package/docs/research-1.8.18-isolation.md +43 -0
- package/docs/research-1.8.19-virtual-browser.md +27 -0
- package/docs/saddle.archive.1.8.17.tar.gz.gpg +0 -0
- package/docs/security.md +454 -0
- package/docs/todo-1.8.16.md +56 -1
- package/docs/todo-1.8.18.md +164 -0
- package/docs/todo-1.8.19.md +241 -0
- package/docs/viability.md +777 -0
- package/docs/virtualization.md +335 -0
- package/docs/web-duplicatecleanup.md +9 -0
- package/docs/web-ideas.md +106 -0
- package/docs/workflowimprovements-2026-08-19.md +70 -0
- package/gpumonitor.cpp +1543 -0
- package/gpus.json +2408 -0
- package/index.ts +1478 -0
- package/media.ts +1337 -0
- package/mttg.config +1549 -0
- package/orchestrator.ts +5462 -0
- package/package.json +304 -55
- package/passage.config +1331 -0
- package/performance.ts +1049 -0
- package/processors.json +2217 -0
- package/qemu.config +1062 -0
- package/qemubridge.py +1340 -0
- package/quantum.ts +2393 -0
- package/render.ts +1325 -0
- package/scheduler.ts +1600 -0
- package/security.ts +1449 -0
- package/tiers.ts +2871 -0
- package/tsconfig.json +29 -0
- package/virtualcpu.ts +1273 -0
- package/virtualgpu.ts +1181 -0
- package/virtualhardware.c +1011 -0
- package/virtualhardware.json +739 -0
- package/virtualization.ts +1628 -0
- package/virtualizationcore.cpp +4635 -0
- package/virtualmemory.ts +2303 -0
- package/vm.config.json +1910 -0
- package/{extension → web/extension}/manifest.json +1 -1
- package/web/readme.md +382 -0
- package/web/tsconfig.json +25 -0
- package/dist/adapters/forge.d.ts +0 -17
- package/dist/adapters/forge.d.ts.map +0 -1
- package/dist/adapters/forge.js +0 -19
- package/dist/adapters/forge.js.map +0 -1
- package/dist/adapters/forgejo.d.ts +0 -49
- package/dist/adapters/forgejo.d.ts.map +0 -1
- package/dist/adapters/forgejo.js +0 -8
- package/dist/adapters/forgejo.js.map +0 -1
- package/dist/adapters/github.d.ts +0 -12
- package/dist/adapters/github.d.ts.map +0 -1
- package/dist/adapters/github.js +0 -20
- package/dist/adapters/github.js.map +0 -1
- package/dist/adapters/gitlab.d.ts +0 -17
- package/dist/adapters/gitlab.d.ts.map +0 -1
- package/dist/adapters/gitlab.js +0 -10
- package/dist/adapters/gitlab.js.map +0 -1
- package/dist/adapters/huggingface.d.ts +0 -17
- package/dist/adapters/huggingface.d.ts.map +0 -1
- package/dist/adapters/huggingface.js +0 -6
- package/dist/adapters/huggingface.js.map +0 -1
- package/dist/adapters/socket.d.ts +0 -11
- package/dist/adapters/socket.d.ts.map +0 -1
- package/dist/adapters/socket.js +0 -17
- package/dist/adapters/socket.js.map +0 -1
- package/dist/adapters/transport.d.ts +0 -7
- package/dist/adapters/transport.d.ts.map +0 -1
- package/dist/adapters/transport.js +0 -36
- package/dist/adapters/transport.js.map +0 -1
- package/dist/ai/chunk.d.ts +0 -2
- package/dist/ai/chunk.d.ts.map +0 -1
- package/dist/ai/chunk.js +0 -36
- package/dist/ai/chunk.js.map +0 -1
- package/dist/ai/llmstxt.d.ts +0 -6
- package/dist/ai/llmstxt.d.ts.map +0 -1
- package/dist/ai/llmstxt.js +0 -12
- package/dist/ai/llmstxt.js.map +0 -1
- package/dist/ai/provenance.d.ts +0 -22
- package/dist/ai/provenance.d.ts.map +0 -1
- package/dist/ai/provenance.js +0 -25
- package/dist/ai/provenance.js.map +0 -1
- package/dist/ai/rag.d.ts +0 -26
- package/dist/ai/rag.d.ts.map +0 -1
- package/dist/ai/rag.js +0 -22
- package/dist/ai/rag.js.map +0 -1
- package/dist/ai/tokens.d.ts +0 -15
- package/dist/ai/tokens.d.ts.map +0 -1
- package/dist/ai/tokens.js +0 -9
- package/dist/ai/tokens.js.map +0 -1
- package/dist/api/auth.d.ts +0 -16
- package/dist/api/auth.d.ts.map +0 -1
- package/dist/api/auth.js +0 -19
- package/dist/api/auth.js.map +0 -1
- package/dist/api/contracts.d.ts +0 -28
- package/dist/api/contracts.d.ts.map +0 -1
- package/dist/api/contracts.js +0 -14
- package/dist/api/contracts.js.map +0 -1
- package/dist/api/control.d.ts +0 -10
- package/dist/api/control.d.ts.map +0 -1
- package/dist/api/control.js +0 -35
- package/dist/api/control.js.map +0 -1
- package/dist/api/http.d.ts +0 -7
- package/dist/api/http.d.ts.map +0 -1
- package/dist/api/http.js +0 -12
- package/dist/api/http.js.map +0 -1
- package/dist/api/rate.d.ts +0 -28
- package/dist/api/rate.d.ts.map +0 -1
- package/dist/api/rate.js +0 -36
- package/dist/api/rate.js.map +0 -1
- package/dist/api/security.d.ts +0 -12
- package/dist/api/security.d.ts.map +0 -1
- package/dist/api/security.js +0 -56
- package/dist/api/security.js.map +0 -1
- package/dist/api/service.d.ts +0 -5
- package/dist/api/service.d.ts.map +0 -1
- package/dist/api/service.js +0 -70
- package/dist/api/service.js.map +0 -1
- package/dist/apps/registry.d.ts +0 -33
- package/dist/apps/registry.d.ts.map +0 -1
- package/dist/apps/registry.js +0 -24
- package/dist/apps/registry.js.map +0 -1
- package/dist/binary/archive.d.ts +0 -27
- package/dist/binary/archive.d.ts.map +0 -1
- package/dist/binary/archive.js +0 -46
- package/dist/binary/archive.js.map +0 -1
- package/dist/binary/build.d.ts +0 -29
- package/dist/binary/build.d.ts.map +0 -1
- package/dist/binary/build.js +0 -17
- package/dist/binary/build.js.map +0 -1
- package/dist/binary/transform.d.ts +0 -70
- package/dist/binary/transform.d.ts.map +0 -1
- package/dist/binary/transform.js +0 -105
- package/dist/binary/transform.js.map +0 -1
- package/dist/bot/adapter.d.ts +0 -5
- package/dist/bot/adapter.d.ts.map +0 -1
- package/dist/bot/adapter.js +0 -11
- package/dist/bot/adapter.js.map +0 -1
- package/dist/bot/bot.d.ts +0 -28
- package/dist/bot/bot.d.ts.map +0 -1
- package/dist/bot/bot.js +0 -52
- package/dist/bot/bot.js.map +0 -1
- package/dist/bot/commands.d.ts +0 -8
- package/dist/bot/commands.d.ts.map +0 -1
- package/dist/bot/commands.js +0 -19
- package/dist/bot/commands.js.map +0 -1
- package/dist/bot/permissions.d.ts +0 -13
- package/dist/bot/permissions.d.ts.map +0 -1
- package/dist/bot/permissions.js +0 -16
- package/dist/bot/permissions.js.map +0 -1
- package/dist/browser/actions.d.ts +0 -33
- package/dist/browser/actions.d.ts.map +0 -1
- package/dist/browser/actions.js +0 -44
- package/dist/browser/actions.js.map +0 -1
- package/dist/browser/agent.d.ts +0 -21
- package/dist/browser/agent.d.ts.map +0 -1
- package/dist/browser/agent.js +0 -13
- package/dist/browser/agent.js.map +0 -1
- package/dist/browser/context.d.ts +0 -43
- package/dist/browser/context.d.ts.map +0 -1
- package/dist/browser/context.js +0 -54
- package/dist/browser/context.js.map +0 -1
- package/dist/browser/fingerprint.d.ts +0 -4
- package/dist/browser/fingerprint.d.ts.map +0 -1
- package/dist/browser/fingerprint.js +0 -12
- package/dist/browser/fingerprint.js.map +0 -1
- package/dist/browser/index.d.ts +0 -11
- package/dist/browser/index.d.ts.map +0 -1
- package/dist/browser/index.js +0 -11
- package/dist/browser/index.js.map +0 -1
- package/dist/browser/playwright.d.ts +0 -11
- package/dist/browser/playwright.d.ts.map +0 -1
- package/dist/browser/playwright.js +0 -24
- package/dist/browser/playwright.js.map +0 -1
- package/dist/browser/recorder.d.ts +0 -21
- package/dist/browser/recorder.d.ts.map +0 -1
- package/dist/browser/recorder.js +0 -58
- package/dist/browser/recorder.js.map +0 -1
- package/dist/browser/session.d.ts +0 -14
- package/dist/browser/session.d.ts.map +0 -1
- package/dist/browser/session.js +0 -21
- package/dist/browser/session.js.map +0 -1
- package/dist/browser/snapshot.d.ts +0 -69
- package/dist/browser/snapshot.d.ts.map +0 -1
- package/dist/browser/snapshot.js +0 -133
- package/dist/browser/snapshot.js.map +0 -1
- package/dist/captcha/contract.d.ts +0 -35
- package/dist/captcha/contract.d.ts.map +0 -1
- package/dist/captcha/contract.js +0 -17
- package/dist/captcha/contract.js.map +0 -1
- package/dist/captcha/evidence.d.ts +0 -10
- package/dist/captcha/evidence.d.ts.map +0 -1
- package/dist/captcha/evidence.js +0 -9
- package/dist/captcha/evidence.js.map +0 -1
- package/dist/captcha/guard.d.ts +0 -23
- package/dist/captcha/guard.d.ts.map +0 -1
- package/dist/captcha/guard.js +0 -12
- package/dist/captcha/guard.js.map +0 -1
- package/dist/cli/main.d.ts +0 -4
- package/dist/cli/main.d.ts.map +0 -1
- package/dist/cli/main.js +0 -46
- package/dist/cli/main.js.map +0 -1
- package/dist/core/errors.d.ts +0 -84
- package/dist/core/errors.d.ts.map +0 -1
- package/dist/core/errors.js +0 -54
- package/dist/core/errors.js.map +0 -1
- package/dist/core/events.d.ts +0 -9
- package/dist/core/events.d.ts.map +0 -1
- package/dist/core/events.js +0 -21
- package/dist/core/events.js.map +0 -1
- package/dist/core/hash.d.ts +0 -10
- package/dist/core/hash.d.ts.map +0 -1
- package/dist/core/hash.js +0 -82
- package/dist/core/hash.js.map +0 -1
- package/dist/core/ids.d.ts +0 -10
- package/dist/core/ids.d.ts.map +0 -1
- package/dist/core/ids.js +0 -15
- package/dist/core/ids.js.map +0 -1
- package/dist/delivery/manifest.d.ts +0 -35
- package/dist/delivery/manifest.d.ts.map +0 -1
- package/dist/delivery/manifest.js +0 -68
- package/dist/delivery/manifest.js.map +0 -1
- package/dist/deploy/index.d.ts +0 -6
- package/dist/deploy/index.d.ts.map +0 -1
- package/dist/deploy/index.js +0 -6
- package/dist/deploy/index.js.map +0 -1
- package/dist/dispatch/resumable.d.ts +0 -102
- package/dist/dispatch/resumable.d.ts.map +0 -1
- package/dist/dispatch/resumable.js +0 -64
- package/dist/dispatch/resumable.js.map +0 -1
- package/dist/dispatch/workflow.d.ts +0 -6
- package/dist/dispatch/workflow.d.ts.map +0 -1
- package/dist/dispatch/workflow.js +0 -37
- package/dist/dispatch/workflow.js.map +0 -1
- package/dist/domain/artifacts.d.ts +0 -12
- package/dist/domain/artifacts.d.ts.map +0 -1
- package/dist/domain/artifacts.js +0 -14
- package/dist/domain/artifacts.js.map +0 -1
- package/dist/domain/jobs.d.ts +0 -12
- package/dist/domain/jobs.d.ts.map +0 -1
- package/dist/domain/jobs.js +0 -20
- package/dist/domain/jobs.js.map +0 -1
- package/dist/domain/providers.d.ts +0 -10
- package/dist/domain/providers.d.ts.map +0 -1
- package/dist/domain/providers.js +0 -8
- package/dist/domain/providers.js.map +0 -1
- package/dist/domain/runtime.d.ts +0 -14
- package/dist/domain/runtime.d.ts.map +0 -1
- package/dist/domain/runtime.js +0 -10
- package/dist/domain/runtime.js.map +0 -1
- package/dist/domain/sessions.d.ts +0 -12
- package/dist/domain/sessions.d.ts.map +0 -1
- package/dist/domain/sessions.js +0 -57
- package/dist/domain/sessions.js.map +0 -1
- package/dist/examples/localjob.d.ts +0 -2
- package/dist/examples/localjob.d.ts.map +0 -1
- package/dist/examples/localjob.js.map +0 -1
- package/dist/examples/publicapi.d.ts +0 -2
- package/dist/examples/publicapi.d.ts.map +0 -1
- package/dist/examples/publicapi.js.map +0 -1
- package/dist/extension/build.d.ts +0 -9
- package/dist/extension/build.d.ts.map +0 -1
- package/dist/extension/build.js +0 -85
- package/dist/extension/build.js.map +0 -1
- package/dist/extension/content.d.ts +0 -6
- package/dist/extension/content.d.ts.map +0 -1
- package/dist/extension/content.js +0 -135
- package/dist/extension/content.js.map +0 -1
- package/dist/extension/index.d.ts +0 -7
- package/dist/extension/index.d.ts.map +0 -1
- package/dist/extension/index.js +0 -7
- package/dist/extension/index.js.map +0 -1
- package/dist/extension/pagebridge.d.ts +0 -6
- package/dist/extension/pagebridge.d.ts.map +0 -1
- package/dist/extension/pagebridge.js +0 -42
- package/dist/extension/pagebridge.js.map +0 -1
- package/dist/extension/permissions.d.ts +0 -26
- package/dist/extension/permissions.d.ts.map +0 -1
- package/dist/extension/permissions.js +0 -28
- package/dist/extension/permissions.js.map +0 -1
- package/dist/extension/popup.d.ts +0 -5
- package/dist/extension/popup.d.ts.map +0 -1
- package/dist/extension/popup.js +0 -26
- package/dist/extension/popup.js.map +0 -1
- package/dist/extension/protocol.d.ts +0 -58
- package/dist/extension/protocol.d.ts.map +0 -1
- package/dist/extension/protocol.js +0 -101
- package/dist/extension/protocol.js.map +0 -1
- package/dist/extension/serviceworker.d.ts +0 -25
- package/dist/extension/serviceworker.d.ts.map +0 -1
- package/dist/extension/serviceworker.js +0 -102
- package/dist/extension/serviceworker.js.map +0 -1
- package/dist/extension/worker.d.ts +0 -28
- package/dist/extension/worker.d.ts.map +0 -1
- package/dist/extension/worker.js +0 -22
- package/dist/extension/worker.js.map +0 -1
- package/dist/format/check.d.ts +0 -8
- package/dist/format/check.d.ts.map +0 -1
- package/dist/format/check.js +0 -38
- package/dist/format/check.js.map +0 -1
- package/dist/library/public.d.ts.map +0 -1
- package/dist/library/public.js.map +0 -1
- package/dist/mcp/browser.d.ts +0 -9
- package/dist/mcp/browser.d.ts.map +0 -1
- package/dist/mcp/browser.js +0 -13
- package/dist/mcp/browser.js.map +0 -1
- package/dist/mcp/server.d.ts +0 -35
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/mcp/server.js +0 -40
- package/dist/mcp/server.js.map +0 -1
- package/dist/mcp/transport.d.ts +0 -7
- package/dist/mcp/transport.d.ts.map +0 -1
- package/dist/mcp/transport.js +0 -17
- package/dist/mcp/transport.js.map +0 -1
- package/dist/memory/bridge.d.ts +0 -14
- package/dist/memory/bridge.d.ts.map +0 -1
- package/dist/memory/bridge.js +0 -16
- package/dist/memory/bridge.js.map +0 -1
- package/dist/memory/engine.d.ts +0 -38
- package/dist/memory/engine.d.ts.map +0 -1
- package/dist/memory/engine.js +0 -109
- package/dist/memory/engine.js.map +0 -1
- package/dist/memory/modes.d.ts +0 -43
- package/dist/memory/modes.d.ts.map +0 -1
- package/dist/memory/modes.js +0 -66
- package/dist/memory/modes.js.map +0 -1
- package/dist/memory/objects.d.ts +0 -21
- package/dist/memory/objects.d.ts.map +0 -1
- package/dist/memory/objects.js +0 -20
- package/dist/memory/objects.js.map +0 -1
- package/dist/memory/planner.d.ts +0 -66
- package/dist/memory/planner.d.ts.map +0 -1
- package/dist/memory/planner.js +0 -108
- package/dist/memory/planner.js.map +0 -1
- package/dist/memory/targets.d.ts +0 -78
- package/dist/memory/targets.d.ts.map +0 -1
- package/dist/memory/targets.js +0 -29
- package/dist/memory/targets.js.map +0 -1
- package/dist/memory/transforms.d.ts +0 -19
- package/dist/memory/transforms.d.ts.map +0 -1
- package/dist/memory/transforms.js +0 -14
- package/dist/memory/transforms.js.map +0 -1
- package/dist/modes/matrix.d.ts +0 -23
- package/dist/modes/matrix.d.ts.map +0 -1
- package/dist/modes/matrix.js +0 -18
- package/dist/modes/matrix.js.map +0 -1
- package/dist/modes/modes.d.ts +0 -33
- package/dist/modes/modes.d.ts.map +0 -1
- package/dist/modes/modes.js +0 -15
- package/dist/modes/modes.js.map +0 -1
- package/dist/modes/resolve.d.ts +0 -96
- package/dist/modes/resolve.d.ts.map +0 -1
- package/dist/modes/resolve.js +0 -48
- package/dist/modes/resolve.js.map +0 -1
- package/dist/observability/metrics.d.ts +0 -14
- package/dist/observability/metrics.d.ts.map +0 -1
- package/dist/observability/metrics.js +0 -18
- package/dist/observability/metrics.js.map +0 -1
- package/dist/packager/manifest.d.ts +0 -66
- package/dist/packager/manifest.d.ts.map +0 -1
- package/dist/packager/manifest.js +0 -94
- package/dist/packager/manifest.js.map +0 -1
- package/dist/packager/publish.d.ts +0 -51
- package/dist/packager/publish.d.ts.map +0 -1
- package/dist/packager/publish.js +0 -18
- package/dist/packager/publish.js.map +0 -1
- package/dist/packager/targetcli.d.ts +0 -7
- package/dist/packager/targetcli.d.ts.map +0 -1
- package/dist/packager/targetcli.js +0 -22
- package/dist/packager/targetcli.js.map +0 -1
- package/dist/persistence/adapter.d.ts +0 -5
- package/dist/persistence/adapter.d.ts.map +0 -1
- package/dist/persistence/adapter.js +0 -11
- package/dist/persistence/adapter.js.map +0 -1
- package/dist/persistence/drizzle.d.ts +0 -2
- package/dist/persistence/drizzle.d.ts.map +0 -1
- package/dist/persistence/drizzle.js +0 -12
- package/dist/persistence/drizzle.js.map +0 -1
- package/dist/persistence/memory.d.ts +0 -2
- package/dist/persistence/memory.d.ts.map +0 -1
- package/dist/persistence/memory.js +0 -27
- package/dist/persistence/memory.js.map +0 -1
- package/dist/persistence/migrations.d.ts +0 -19
- package/dist/persistence/migrations.d.ts.map +0 -1
- package/dist/persistence/migrations.js +0 -13
- package/dist/persistence/migrations.js.map +0 -1
- package/dist/persistence/prisma.d.ts +0 -2
- package/dist/persistence/prisma.d.ts.map +0 -1
- package/dist/persistence/prisma.js +0 -25
- package/dist/persistence/prisma.js.map +0 -1
- package/dist/persistence/schema.d.ts +0 -63
- package/dist/persistence/schema.d.ts.map +0 -1
- package/dist/persistence/schema.js +0 -28
- package/dist/persistence/schema.js.map +0 -1
- package/dist/persistence/sql.d.ts +0 -3
- package/dist/persistence/sql.d.ts.map +0 -1
- package/dist/persistence/sql.js +0 -37
- package/dist/persistence/sql.js.map +0 -1
- package/dist/protocol/blocks.d.ts +0 -10
- package/dist/protocol/blocks.d.ts.map +0 -1
- package/dist/protocol/blocks.js +0 -26
- package/dist/protocol/blocks.js.map +0 -1
- package/dist/protocol/json.d.ts +0 -6
- package/dist/protocol/json.d.ts.map +0 -1
- package/dist/protocol/json.js +0 -6
- package/dist/protocol/json.js.map +0 -1
- package/dist/protocol/ndjson.d.ts +0 -3
- package/dist/protocol/ndjson.d.ts.map +0 -1
- package/dist/protocol/ndjson.js +0 -20
- package/dist/protocol/ndjson.js.map +0 -1
- package/dist/protocol/sse.d.ts +0 -7
- package/dist/protocol/sse.d.ts.map +0 -1
- package/dist/protocol/sse.js +0 -25
- package/dist/protocol/sse.js.map +0 -1
- package/dist/proxy/pool.d.ts +0 -9
- package/dist/proxy/pool.d.ts.map +0 -1
- package/dist/proxy/pool.js +0 -27
- package/dist/proxy/pool.js.map +0 -1
- package/dist/queue/idempotency.d.ts +0 -10
- package/dist/queue/idempotency.d.ts.map +0 -1
- package/dist/queue/idempotency.js +0 -13
- package/dist/queue/idempotency.js.map +0 -1
- package/dist/queue/persistent.d.ts +0 -14
- package/dist/queue/persistent.d.ts.map +0 -1
- package/dist/queue/persistent.js +0 -66
- package/dist/queue/persistent.js.map +0 -1
- package/dist/queue/queue.d.ts +0 -7
- package/dist/queue/queue.d.ts.map +0 -1
- package/dist/queue/queue.js +0 -55
- package/dist/queue/queue.js.map +0 -1
- package/dist/queue/saga.d.ts +0 -5
- package/dist/queue/saga.d.ts.map +0 -1
- package/dist/queue/saga.js +0 -20
- package/dist/queue/saga.js.map +0 -1
- package/dist/release/assets.d.ts +0 -144
- package/dist/release/assets.d.ts.map +0 -1
- package/dist/release/assets.js +0 -157
- package/dist/release/assets.js.map +0 -1
- package/dist/release/evidence.d.ts +0 -92
- package/dist/release/evidence.d.ts.map +0 -1
- package/dist/release/evidence.js +0 -148
- package/dist/release/evidence.js.map +0 -1
- package/dist/release/verify.d.ts +0 -12
- package/dist/release/verify.d.ts.map +0 -1
- package/dist/release/verify.js +0 -112
- package/dist/release/verify.js.map +0 -1
- package/dist/runners/chain.d.ts +0 -125
- package/dist/runners/chain.d.ts.map +0 -1
- package/dist/runners/chain.js +0 -95
- package/dist/runners/chain.js.map +0 -1
- package/dist/runners/health.d.ts +0 -36
- package/dist/runners/health.d.ts.map +0 -1
- package/dist/runners/health.js +0 -26
- package/dist/runners/health.js.map +0 -1
- package/dist/runners/heartbeat.d.ts +0 -23
- package/dist/runners/heartbeat.d.ts.map +0 -1
- package/dist/runners/heartbeat.js +0 -29
- package/dist/runners/heartbeat.js.map +0 -1
- package/dist/runners/inprocess.d.ts +0 -17
- package/dist/runners/inprocess.d.ts.map +0 -1
- package/dist/runners/inprocess.js +0 -20
- package/dist/runners/inprocess.js.map +0 -1
- package/dist/runners/scheduler.d.ts +0 -5
- package/dist/runners/scheduler.d.ts.map +0 -1
- package/dist/runners/scheduler.js +0 -19
- package/dist/runners/scheduler.js.map +0 -1
- package/dist/runtime/abort.d.ts +0 -8
- package/dist/runtime/abort.d.ts.map +0 -1
- package/dist/runtime/abort.js +0 -13
- package/dist/runtime/abort.js.map +0 -1
- package/dist/runtime/compatibility.d.ts +0 -37
- package/dist/runtime/compatibility.d.ts.map +0 -1
- package/dist/runtime/compatibility.js +0 -10
- package/dist/runtime/compatibility.js.map +0 -1
- package/dist/runtime/detect.d.ts +0 -13
- package/dist/runtime/detect.d.ts.map +0 -1
- package/dist/runtime/detect.js +0 -18
- package/dist/runtime/detect.js.map +0 -1
- package/dist/runtime/engine.d.ts +0 -20
- package/dist/runtime/engine.d.ts.map +0 -1
- package/dist/runtime/engine.js +0 -61
- package/dist/runtime/engine.js.map +0 -1
- package/dist/runtime/retry.d.ts +0 -19
- package/dist/runtime/retry.d.ts.map +0 -1
- package/dist/runtime/retry.js +0 -54
- package/dist/runtime/retry.js.map +0 -1
- package/dist/runtime/worker.d.ts +0 -10
- package/dist/runtime/worker.d.ts.map +0 -1
- package/dist/runtime/worker.js +0 -25
- package/dist/runtime/worker.js.map +0 -1
- package/dist/scrape/cache.d.ts +0 -45
- package/dist/scrape/cache.d.ts.map +0 -1
- package/dist/scrape/cache.js +0 -45
- package/dist/scrape/cache.js.map +0 -1
- package/dist/scrape/crawl.d.ts +0 -47
- package/dist/scrape/crawl.d.ts.map +0 -1
- package/dist/scrape/crawl.js +0 -114
- package/dist/scrape/crawl.js.map +0 -1
- package/dist/scrape/extract.d.ts +0 -63
- package/dist/scrape/extract.d.ts.map +0 -1
- package/dist/scrape/extract.js +0 -47
- package/dist/scrape/extract.js.map +0 -1
- package/dist/scrape/normalize.d.ts +0 -52
- package/dist/scrape/normalize.d.ts.map +0 -1
- package/dist/scrape/normalize.js +0 -102
- package/dist/scrape/normalize.js.map +0 -1
- package/dist/scrape/robots.d.ts +0 -37
- package/dist/scrape/robots.d.ts.map +0 -1
- package/dist/scrape/robots.js +0 -71
- package/dist/scrape/robots.js.map +0 -1
- package/dist/scrape/schema.d.ts +0 -23
- package/dist/scrape/schema.d.ts.map +0 -1
- package/dist/scrape/schema.js +0 -92
- package/dist/scrape/schema.js.map +0 -1
- package/dist/scrape/scraper.d.ts +0 -6
- package/dist/scrape/scraper.d.ts.map +0 -1
- package/dist/scrape/scraper.js +0 -46
- package/dist/scrape/scraper.js.map +0 -1
- package/dist/scrape/semantic.d.ts +0 -25
- package/dist/scrape/semantic.d.ts.map +0 -1
- package/dist/scrape/semantic.js +0 -27
- package/dist/scrape/semantic.js.map +0 -1
- package/dist/server/node.d.ts +0 -7
- package/dist/server/node.d.ts.map +0 -1
- package/dist/server/node.js.map +0 -1
- package/dist/sessions/file.d.ts +0 -25
- package/dist/sessions/file.d.ts.map +0 -1
- package/dist/sessions/file.js +0 -13
- package/dist/sessions/file.js.map +0 -1
- package/dist/sessions/replay.d.ts +0 -9
- package/dist/sessions/replay.d.ts.map +0 -1
- package/dist/sessions/replay.js +0 -70
- package/dist/sessions/replay.js.map +0 -1
- package/dist/sessions/store.d.ts +0 -25
- package/dist/sessions/store.d.ts.map +0 -1
- package/dist/sessions/store.js +0 -13
- package/dist/sessions/store.js.map +0 -1
- package/dist/storage/adapter.d.ts +0 -5
- package/dist/storage/adapter.d.ts.map +0 -1
- package/dist/storage/adapter.js +0 -11
- package/dist/storage/adapter.js.map +0 -1
- package/dist/storage/cache.d.ts +0 -23
- package/dist/storage/cache.d.ts.map +0 -1
- package/dist/storage/cache.js +0 -79
- package/dist/storage/cache.js.map +0 -1
- package/dist/storage/checksum.d.ts +0 -3
- package/dist/storage/checksum.d.ts.map +0 -1
- package/dist/storage/checksum.js +0 -19
- package/dist/storage/checksum.js.map +0 -1
- package/dist/storage/chunked.d.ts +0 -21
- package/dist/storage/chunked.d.ts.map +0 -1
- package/dist/storage/chunked.js +0 -67
- package/dist/storage/chunked.js.map +0 -1
- package/dist/storage/content.d.ts +0 -24
- package/dist/storage/content.d.ts.map +0 -1
- package/dist/storage/content.js +0 -44
- package/dist/storage/content.js.map +0 -1
- package/dist/storage/filehosting.d.ts +0 -2
- package/dist/storage/filehosting.d.ts.map +0 -1
- package/dist/storage/filehosting.js +0 -24
- package/dist/storage/filehosting.js.map +0 -1
- package/dist/storage/githubcontents.d.ts +0 -2
- package/dist/storage/githubcontents.d.ts.map +0 -1
- package/dist/storage/githubcontents.js +0 -29
- package/dist/storage/githubcontents.js.map +0 -1
- package/dist/storage/index.d.ts +0 -12
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/index.js +0 -12
- package/dist/storage/index.js.map +0 -1
- package/dist/storage/local.d.ts +0 -2
- package/dist/storage/local.d.ts.map +0 -1
- package/dist/storage/local.js +0 -72
- package/dist/storage/local.js.map +0 -1
- package/dist/storage/memory.d.ts +0 -6
- package/dist/storage/memory.d.ts.map +0 -1
- package/dist/storage/memory.js +0 -36
- package/dist/storage/memory.js.map +0 -1
- package/dist/storage/pool.d.ts +0 -95
- package/dist/storage/pool.d.ts.map +0 -1
- package/dist/storage/pool.js +0 -202
- package/dist/storage/pool.js.map +0 -1
- package/dist/storage/s3compatible.d.ts +0 -3
- package/dist/storage/s3compatible.d.ts.map +0 -1
- package/dist/storage/s3compatible.js +0 -70
- package/dist/storage/s3compatible.js.map +0 -1
- package/dist/storage/sync.d.ts +0 -47
- package/dist/storage/sync.d.ts.map +0 -1
- package/dist/storage/sync.js +0 -75
- package/dist/storage/sync.js.map +0 -1
- package/dist/surfaces/adapters.d.ts +0 -97
- package/dist/surfaces/adapters.d.ts.map +0 -1
- package/dist/surfaces/adapters.js +0 -50
- package/dist/surfaces/adapters.js.map +0 -1
- package/dist/surfaces/controls.d.ts +0 -18
- package/dist/surfaces/controls.d.ts.map +0 -1
- package/dist/surfaces/controls.js +0 -45
- package/dist/surfaces/controls.js.map +0 -1
- package/dist/surfaces/manifest.d.ts +0 -68
- package/dist/surfaces/manifest.d.ts.map +0 -1
- package/dist/surfaces/manifest.js +0 -42
- package/dist/surfaces/manifest.js.map +0 -1
- package/dist/surfaces/n8n.d.ts +0 -25
- package/dist/surfaces/n8n.d.ts.map +0 -1
- package/dist/surfaces/n8n.js +0 -31
- package/dist/surfaces/n8n.js.map +0 -1
- package/dist/surfaces/operations.d.ts +0 -32
- package/dist/surfaces/operations.d.ts.map +0 -1
- package/dist/surfaces/operations.js +0 -53
- package/dist/surfaces/operations.js.map +0 -1
- package/dist/surfaces/requirements.d.ts +0 -29
- package/dist/surfaces/requirements.d.ts.map +0 -1
- package/dist/surfaces/requirements.js +0 -50
- package/dist/surfaces/requirements.js.map +0 -1
- package/dist/surfaces/targets.d.ts +0 -196
- package/dist/surfaces/targets.d.ts.map +0 -1
- package/dist/surfaces/targets.js +0 -27
- package/dist/surfaces/targets.js.map +0 -1
- package/dist/webhook/delivery.d.ts +0 -18
- package/dist/webhook/delivery.d.ts.map +0 -1
- package/dist/webhook/delivery.js +0 -36
- package/dist/webhook/delivery.js.map +0 -1
- package/dist/webhook/receiver.d.ts +0 -26
- package/dist/webhook/receiver.d.ts.map +0 -1
- package/dist/webhook/receiver.js +0 -24
- package/dist/webhook/receiver.js.map +0 -1
- package/dist/webhook/signature.d.ts +0 -3
- package/dist/webhook/signature.d.ts.map +0 -1
- package/dist/webhook/signature.js +0 -7
- package/dist/webhook/signature.js.map +0 -1
- package/dist/workflow/manifest.d.ts +0 -22
- package/dist/workflow/manifest.d.ts.map +0 -1
- package/dist/workflow/manifest.js +0 -21
- package/dist/workflow/manifest.js.map +0 -1
- package/dist/workflow/registry.d.ts +0 -7
- package/dist/workflow/registry.d.ts.map +0 -1
- package/dist/workflow/registry.js +0 -18
- package/dist/workflow/registry.js.map +0 -1
- package/dist/workflow/templates.d.ts +0 -6
- package/dist/workflow/templates.d.ts.map +0 -1
- package/dist/workflow/templates.js +0 -18
- package/dist/workflow/templates.js.map +0 -1
- package/dist/workflow/triggers.d.ts +0 -64
- package/dist/workflow/triggers.d.ts.map +0 -1
- package/dist/workflow/triggers.js +0 -99
- package/dist/workflow/triggers.js.map +0 -1
- package/docs/logs/.gitkeep +0 -0
- package/docs/plans/00.index.md +0 -50
- package/docs/plans/01.architecture.md +0 -86
- package/docs/plans/02.research.computer.use.md +0 -58
- package/docs/plans/03.research.captcha.bypass.md +0 -68
- package/docs/plans/04.research.sandbox.ai.md +0 -52
- package/docs/plans/05.capture.platform.md +0 -57
- package/docs/plans/06.dependencies.md +0 -97
- package/docs/plans/07.captcha.test.page.md +0 -41
- package/docs/plans/08.production.infra.md +0 -70
- package/docs/plans/09.database.schema.md +0 -121
- package/docs/plans/10.cloudinary.storage.md +0 -57
- package/docs/plans/11.movement.logs.json.md +0 -72
- package/docs/plans/12.research.atlas.agent.browser.md +0 -79
- package/docs/plans/13.research.anti.detection.md +0 -898
- package/docs/plans/14.research.proxy.md +0 -1495
- package/docs/plans/15.research.retry.rate.limit.md +0 -1958
- package/docs/plans/16.research.crawling.md +0 -1417
- package/docs/plans/17.research.caching.md +0 -1610
- package/docs/plans/18.research.content.extraction.md +0 -1952
- package/docs/plans/19.research.errors.events.md +0 -1523
- package/docs/plans/20.research.zod.validation.md +0 -1350
- package/docs/plans/21.research.batch.concurrency.md +0 -1888
- package/docs/plans/22.research.universal.runtime.md +0 -944
- package/docs/plans/23.research.ai.integration.md +0 -1465
- package/docs/plans/24.research.memory.persistence.md +0 -1979
- package/docs/plans/25.research.server.api.md +0 -342
- package/docs/plans/26.research.compilation.md +0 -249
- package/docs/plans/27.research.html.parsing.md +0 -251
- package/docs/plans/28.action.plan.md +0 -50
- package/docs/plans/29.api.reference.md +0 -174
- package/docs/plans/30.architecture.plan.md +0 -94
- package/docs/plans/31.auditoria.dados.md +0 -163
- package/docs/plans/32.bots.automacao.computacional.md +0 -214
- package/docs/plans/33.bots.codigo.revisao.md +0 -220
- package/docs/plans/34.bots.seguranca.cicd.md +0 -366
- package/docs/plans/35.comparativo.concorrencia.md +0 -464
- package/docs/plans/36.computational.memory.md +0 -340
- package/docs/plans/37.deploystrategy.md +0 -394
- package/docs/plans/38.flow.md +0 -155
- package/docs/plans/39.multi.platform.bot.md +0 -252
- package/docs/plans/40.npm.publish.md +0 -250
- package/docs/plans/41.o.que.falta.md +0 -407
- package/docs/plans/42.pesquisa.concorrencia.md +0 -721
- package/docs/plans/43.plan.universal.architecture.md +0 -496
- package/docs/plans/44.reference.md +0 -100
- package/docs/plans/45.robotarchitecture.md +0 -237
- package/docs/plans/46.scdnintegration.md +0 -284
- package/docs/plans/47.multiforge.readme.md +0 -129
- package/docs/plans/48.theory.v4.repo.os.md +0 -152
- package/docs/plans/49.third.party.infra.md +0 -12
- package/docs/plans/50.file.as.compute.md +0 -39
- package/docs/plans/51.architecture.virtual.processor.md +0 -80
- package/docs/plans/52.manifesto.v8.md +0 -11
- package/docs/plans/58.cdn.list.md +0 -23
- package/docs/plans/59.sql.frameworks.md +0 -33
- package/docs/plans/60.sql.thirdparty.md +0 -26
- package/docs/plans/61.objective.multiforge.md +0 -63
- package/docs/plans/62.huggingface.upload.md +0 -26
- package/docs/plans/63.kaggle.upload.md +0 -24
- package/docs/plans/64.npm.storage.md +0 -30
- package/docs/plans/65.rclone.terabox.md +0 -32
- package/docs/plans/66.buckets.and.models.todo.md +0 -14
- package/docs/plans/67.database.todo.md +0 -13
- package/docs/plans/68.deploy.packages.todo.md +0 -12
- package/docs/plans/69.report.human.operator.md +0 -133
- package/docs/plans/70.report.brain2qwerty.ems.md +0 -135
- package/docs/plans/71.report.hd.infinito.vram.md +0 -155
- package/docs/plans/72.plan.hd.infinito.node.md +0 -146
- package/docs/plans/73.plan.scifi.repos.md +0 -125
- package/docs/plans/74.000.manifesto.v8.flat.2..md +0 -11
- package/docs/plans/README.md +0 -489
- package/docs/plans/aggregate_platforms.mjs +0 -146
- package/docs/plans/examplesession.json +0 -36
- package/docs/plans/missing-facts.md +0 -192
- package/docs/plans/models.md +0 -64
- package/docs/plans/organize.cjs +0 -270
- package/docs/plans/platforms.md +0 -2887
- package/docs/plans/sites.md +0 -31322
- package/docs/sources/farm.py +0 -117
- package/docs/sources/html/saddle1.html +0 -132
- package/docs/sources/html/saddle2.html +0 -157
- package/docs/sources/html/saddle3.html +0 -119
- package/docs/sources/html/saddle4.html +0 -144
- package/docs/sources/html/saddle5.html +0 -72
- package/docs/sources/html/saddle6.html +0 -171
- package/docs/sources/html/saddle7.html +0 -236
- package/docs/sources/saddle.ts +0 -74
- package/docs/sources/schema.prisma +0 -88
- package/docs/sources/script.sh +0 -64
- package/docs/sources/workflows.yml +0 -458
- package/docs/talks1/_body.txt +0 -14
- package/docs/talks1/_index.md +0 -15
- package/docs/talks1/_screenshot.png +0 -0
- package/docs/talks1/assistant-01.md +0 -5
- package/docs/talks1/assistant-02.md +0 -5
- package/docs/talks1/assistant-03.md +0 -531
- package/docs/talks1/assistant-04.md +0 -26
- package/docs/talks1/assistant-05.md +0 -774
- package/docs/talks1/assistant-06.md +0 -1718
- package/docs/talks1/scrape-share.cjs +0 -185
- package/docs/talks1/scrape-share.ts +0 -183
- package/docs/talks1/user-01.md +0 -3
- package/docs/talks1/user-02.md +0 -3
- package/docs/talks1/user-03.md +0 -88
- package/docs/talks1/user-04.md +0 -3
- package/docs/talks1/user-05.md +0 -3
- package/docs/talks1/user-06.md +0 -88
- package/docs/talks1/user-07.md +0 -88
- package/docs/talks2/_body.txt +0 -14
- package/docs/talks2/_index.md +0 -16
- package/docs/talks2/_screenshot.png +0 -0
- package/docs/talks2/assistant-01.md +0 -5
- package/docs/talks2/assistant-02.md +0 -5
- package/docs/talks2/assistant-03.md +0 -424
- package/docs/talks2/assistant-04.md +0 -598
- package/docs/talks2/assistant-05.md +0 -1280
- package/docs/talks2/assistant-06.md +0 -1227
- package/docs/talks2/assistant-07.md +0 -1252
- package/docs/talks2/user-01.md +0 -3
- package/docs/talks2/user-02.md +0 -3
- package/docs/talks2/user-03.md +0 -88
- package/docs/talks2/user-04.md +0 -88
- package/docs/talks2/user-05.md +0 -88
- package/docs/talks2/user-06.md +0 -88
- package/docs/talks2/user-07.md +0 -3
- package/docs/talks3/_body.txt +0 -467
- package/docs/talks3/_index.md +0 -10
- package/docs/talks3/_screenshot.png +0 -0
- package/docs/talks3/assistant-01.md +0 -417
- package/docs/talks3/assistant-02.md +0 -417
- package/docs/talks3/assistant-03.md +0 -29
- package/docs/talks3/assistant-04.md +0 -727
- package/docs/talks3/user-01.md +0 -88
- package/docs/talks3/user-02.md +0 -88
- package/docs/talks3/user-03.md +0 -3
- package/docs/talks3/user-04.md +0 -3
- package/docs/talks4/_body.txt +0 -14
- package/docs/talks4/_index.md +0 -12
- package/docs/talks4/_screenshot.png +0 -0
- package/docs/talks4/assistant-01.md +0 -5
- package/docs/talks4/assistant-02.md +0 -5
- package/docs/talks4/assistant-03.md +0 -35
- package/docs/talks4/assistant-04.md +0 -512
- package/docs/talks4/assistant-05.md +0 -599
- package/docs/talks4/user-01.md +0 -3
- package/docs/talks4/user-02.md +0 -3
- package/docs/talks4/user-03.md +0 -88
- package/docs/talks4/user-04.md +0 -88
- package/docs/talks4/user-05.md +0 -7
- package/docs/talks5/_body.txt +0 -14
- package/docs/talks5/_index.md +0 -13
- package/docs/talks5/_screenshot.png +0 -0
- package/docs/talks5/assistant-01.md +0 -5
- package/docs/talks5/assistant-02.md +0 -5
- package/docs/talks5/assistant-03.md +0 -690
- package/docs/talks5/assistant-04.md +0 -758
- package/docs/talks5/assistant-05.md +0 -974
- package/docs/talks5/user-01.md +0 -3
- package/docs/talks5/user-02.md +0 -3
- package/docs/talks5/user-03.md +0 -105
- package/docs/talks5/user-04.md +0 -105
- package/docs/talks5/user-05.md +0 -63
- package/docs/talks5/user-06.md +0 -105
- package/docs/talks6/_body.txt +0 -14
- package/docs/talks6/_index.md +0 -9
- package/docs/talks6/_screenshot.png +0 -0
- package/docs/talks6/assistant-01.md +0 -5
- package/docs/talks6/assistant-02.md +0 -5
- package/docs/talks6/assistant-03.md +0 -1499
- package/docs/talks6/user-01.md +0 -3
- package/docs/talks6/user-02.md +0 -3
- package/docs/talks6/user-03.md +0 -88
- package/docs/talks6/user-04.md +0 -88
- package/docs/talks7/_body.txt +0 -14
- package/docs/talks7/_index.md +0 -10
- package/docs/talks7/_screenshot.png +0 -0
- package/docs/talks7/assistant-01.md +0 -5
- package/docs/talks7/assistant-02.md +0 -5
- package/docs/talks7/assistant-03.md +0 -523
- package/docs/talks7/assistant-04.md +0 -617
- package/docs/talks7/user-01.md +0 -3
- package/docs/talks7/user-02.md +0 -3
- package/docs/talks7/user-03.md +0 -105
- package/docs/talks7/user-04.md +0 -67
- package/docs/talks8/conversa1.txt +0 -1322
- package/docs/talks8/conversa2.txt +0 -237
- package/docs/talks9/Beyond the Obvious_ 50 Plataformas Auto-Hospedadas de Forja de C/303/263digo para Al/303/251m de Gitea e GitLab.md" +0 -174
- package/docs/talks9/De NPM a Multi-Linguagem_ Uma Arquitetura T/303/251cnica para a Execu/303/247/303/243o Integrada de C/303/263digo no Ecossistema Node.js.md" +0 -59
- package/docs/talks9/De NPM a VMs Virtuais_ Uma An/303/241lise Arquitet/303/264nica para a Realiza/303/247/303/243o do Ciclo de Vida do Projeto SADDLE.md" +0 -91
- package/docs/talks9/Mapeamento da Engrenagem Computacional_ Uma Arquitetura para Execu/303/247/303/243o Isolada e Persist/303/252ncia em Ambientes Distribu/303/255dos.md" +0 -116
- package/docs/talks9/O Cen/303/241rio Pr/303/241tico do SADDLE_ Uma An/303/241lise de Viabilidade e Modelo de Ciclo de Vida Integrado.md" +0 -128
- package/docs/talks9/README (2).md +0 -489
- package/docs/talks9/README.md +0 -198
- package/docs/talks9/Viabilidade do Saddle_ Uma An/303/241lise T/303/251cnica da Transforma/303/247/303/243o de Armazenamento Remoto em Mem/303/263ria Computacional.md" +0 -80
- package/docs/talks9/conversa.txt +0 -544
- package/docs/talks9/other (2).md +0 -39
- package/docs/talks9/other.md +0 -57
- package/docs/talks9/outro.txt +0 -24
- /package/{extension/README.md → docs/extension.md} +0 -0
|
@@ -0,0 +1,1187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* virtualization.ts — kernel level virtualization surface for saddle v6.
|
|
3
|
+
*
|
|
4
|
+
* the module merges four sources identified by the merge map (T7):
|
|
5
|
+
* - qemu-wrapper.ts: the full "turbo" qemu 11.1.0 argv builder with
|
|
6
|
+
* DiamondRapids cpu model, TDX and SEV-SNP guest objects, OVMF secure
|
|
7
|
+
* boot, io_uring drives and the venus virtio-gpu device
|
|
8
|
+
* - passage.ts: the network passage stack with six modes (direct, bridge,
|
|
9
|
+
* nat, overlayVxlan, zeroTrust, latencyOptimization) built on OVS
|
|
10
|
+
* 3.7.1, DPDK 26.07.0, XDP at 10 Mpps, libbpf 1.6.0 and cilium/ebpf
|
|
11
|
+
* v0.21.0, macvtap (bridge/vepa/private/passthrough), ipvlan (l2/l3/l3s),
|
|
12
|
+
* SR-IOV VF passthrough, WireGuard namespaces and io_uring ZCRX
|
|
13
|
+
* - mttg.ts: the cgroups v2 multi-tenant thread group controller (cpu.weight
|
|
14
|
+
* 1-10000, cpu.max quota/period/burst, cpuset, memory.high/max, io.weight,
|
|
15
|
+
* pids.max) with the EEVDF 6.6, BORE 0-39 and sched_ext 6.12 scheduler
|
|
16
|
+
* notes, PSI, DAMON and CRIU live migration context
|
|
17
|
+
* - mttggrid: the Mttg work-stealing grid ported from forge.cpp because
|
|
18
|
+
* architect.ts imports createGrid/MTTG_MAX that previously existed only
|
|
19
|
+
* in the C++ binary (gap flagged by the merge map)
|
|
20
|
+
*
|
|
21
|
+
* naming warning preserved from the map: MTTCG (qemu multi-thread TCG, one
|
|
22
|
+
* host thread per vCPU) and MTTG (multi-tenant thread groups, this file)
|
|
23
|
+
* are unrelated concepts with similar acronyms and must never be merged.
|
|
24
|
+
*
|
|
25
|
+
* qemu argv hierarchy documented across the repository: buildqemucmd in
|
|
26
|
+
* this file is the complete "turbo" argv (TDX/SEV/vfio romfile/venus);
|
|
27
|
+
* qemuargv in index.ts is the lean plan argv; qemuruntime.buildcommand in
|
|
28
|
+
* orchestrator.ts is the runtime strategy argv; qemu_argv in forge.cpp is
|
|
29
|
+
* the C++ emitter. all four stay, each with a different role.
|
|
30
|
+
*
|
|
31
|
+
* contexts (25): qemuopts, buildqemucmd, qemuversioncheck, passagemode,
|
|
32
|
+
* passagebridge, passagesriov, passagemacvtap, passageipvlan, passageoverlay,
|
|
33
|
+
* passagezerotrust, passagelatencyopt, ebpfprogram, tenantqos, cgrouproot,
|
|
34
|
+
* tenantcgroupbuilder, createtenant, cpumaxqos, eevdfinfo, boreinfo,
|
|
35
|
+
* schedextinfo, psidamoninfo, criumigration/checkpoint (the v3-B1 append:
|
|
36
|
+
* criu planner, file snapshot, uffd restore, diff snapshots, live
|
|
37
|
+
* migration), mttggrid, idmapped (v3-B1 kernel gap), virtualizationcore
|
|
38
|
+
* bridge (buildmemorybackendargs + kvmcapnames)
|
|
39
|
+
*
|
|
40
|
+
* patterns: builder (tenantcgroupbuilder), namespace modules as plain
|
|
41
|
+
* function groups. rules: lowercase identifiers, english jsdoc third
|
|
42
|
+
* person, no emoji, try/catch catcher on every fallible path, node:*
|
|
43
|
+
* built-ins only, never a hardcoded localhost address.
|
|
44
|
+
*/
|
|
45
|
+
import { execFileSync } from 'node:child_process';
|
|
46
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
47
|
+
import { availableParallelism, cpus } from 'node:os';
|
|
48
|
+
import { join } from 'node:path';
|
|
49
|
+
/** safe identifier validator: blocks shell metacharacters and path
|
|
50
|
+
* traversal sequences so user-provided names can never reach a shell
|
|
51
|
+
* or escape the intended filesystem scope. */
|
|
52
|
+
function issafeid(value, max = 64) {
|
|
53
|
+
return (typeof value === 'string' &&
|
|
54
|
+
value.length > 0 &&
|
|
55
|
+
value.length <= max &&
|
|
56
|
+
/^[A-Za-z0-9._-]+$/.test(value));
|
|
57
|
+
}
|
|
58
|
+
/** safe cgroup controller filename: no slashes, no dots-only, no traversal. */
|
|
59
|
+
function issafecgroupfile(value) {
|
|
60
|
+
return (typeof value === 'string' &&
|
|
61
|
+
value.length > 0 &&
|
|
62
|
+
value.length <= 128 &&
|
|
63
|
+
/^[A-Za-z0-9._-]+(\.\w+)+$|^[A-Za-z0-9._-]+$/.test(value));
|
|
64
|
+
}
|
|
65
|
+
/* ------------------------------------------------------------------ */
|
|
66
|
+
/* context: buildqemucmd (qemu 11.1.0 full turbo argv) */
|
|
67
|
+
/* ------------------------------------------------------------------ */
|
|
68
|
+
/**
|
|
69
|
+
* builds the complete turbo qemu 11.1.0 argv. the default cpu model is
|
|
70
|
+
* DiamondRapids with host-phys-bits=true, hidden=1 and the NV43FIX
|
|
71
|
+
* hypervisor vendor id that keeps nvidia drivers alive inside the guest;
|
|
72
|
+
* the machine boots q35 with smm on and kernel-irqchip split; memory uses
|
|
73
|
+
* a preallocating ram backend bound to numa node 0; vfio devices carry
|
|
74
|
+
* romfile/rombar/x-vga and disable_idle_d3; the disk uses the io_uring
|
|
75
|
+
* aio engine; the virtio-gpu device enables the venus native context
|
|
76
|
+
* (qemu 11.x); the guest objects enable TDX (sept-ve-disabled) and
|
|
77
|
+
* SEV-SNP (cbitpos=51, reduced-phys-bits=1) confidential computing.
|
|
78
|
+
*/
|
|
79
|
+
export function buildqemucmd(opts) {
|
|
80
|
+
try {
|
|
81
|
+
const cpumodel = opts.cpuModel ?? 'DiamondRapids';
|
|
82
|
+
const args = [
|
|
83
|
+
'/usr/bin/qemu-system-x86_64',
|
|
84
|
+
'-enable-kvm',
|
|
85
|
+
'-machine',
|
|
86
|
+
opts.machine ?? 'q35,smm=on,accel=kvm,kernel-irqchip=split',
|
|
87
|
+
'-cpu',
|
|
88
|
+
`${cpumodel},host-phys-bits=true,hidden=1,hv_vendor_id=NV43FIX,kvm=off,+avx512f,+avx512bw,+pdpe1gb`,
|
|
89
|
+
'-m',
|
|
90
|
+
String(opts.memMB),
|
|
91
|
+
'-smp',
|
|
92
|
+
`${opts.vcpu},sockets=1,cores=${Math.max(1, Math.floor(opts.vcpu / 2))},threads=2`,
|
|
93
|
+
'-object',
|
|
94
|
+
`memory-backend-ram,id=ram0,size=${opts.memMB}M,prealloc=yes,share=no`,
|
|
95
|
+
'-numa',
|
|
96
|
+
'node,nodeid=0,memdev=ram0',
|
|
97
|
+
'-device',
|
|
98
|
+
'virtio-balloon-pci,id=balloon0',
|
|
99
|
+
];
|
|
100
|
+
if (opts.vfioPCI !== undefined) {
|
|
101
|
+
for (const bdf of opts.vfioPCI) {
|
|
102
|
+
args.push('-device', `vfio-pci,host=${bdf},multifunction=on,romfile=/usr/share/kvm/vbios/${bdf}.rom,rombar=1,x-vga=on,disable_idle_d3=1`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const bridge = opts.bridge ?? 'br0';
|
|
106
|
+
args.push('-netdev', `bridge,br=${bridge},id=net0`, '-device', 'virtio-net-pci,netdev=net0,vhost=on,mq=8,vectors=10', '-monitor', `unix:${opts.monitorSock ?? '/run/vhe/vm.sock'},server,nowait`, '-qmp', `unix:${opts.qmpSock ?? '/run/vhe/vm.qmp'},server,nowait`, '-vga', 'none', '-nographic', '-drive', 'if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE_4M.secboot.fd', '-drive', 'if=pflash,format=raw,file=/var/lib/vhe/OVMF_VARS.fd', '-drive', 'file=/var/lib/vhe/disk.qcow2,format=qcow2,cache=none,aio=io_uring,if=virtio', '-device', 'virtio-gpu-pci,venus=true,hostmem=8G', '-object', 'tdx-guest,sept-ve-disabled=true', '-object', 'sev-snp-guest,cbitpos=51,reduced-phys-bits=1');
|
|
107
|
+
return args;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
throw new Error(`buildqemucmd failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/* ------------------------------------------------------------------ */
|
|
114
|
+
/* context: qemuversioncheck */
|
|
115
|
+
/* ------------------------------------------------------------------ */
|
|
116
|
+
/** returns the verified qemu release banner pinned by the engine. */
|
|
117
|
+
export function qemuversioncheck() {
|
|
118
|
+
return '11.1.0 (3200 commits, 285 authors, 12 CVE hardening) - 2026-08-12';
|
|
119
|
+
}
|
|
120
|
+
/* ------------------------------------------------------------------ */
|
|
121
|
+
/* context: passagebridge (linux bridge + OVS 3.7.1) */
|
|
122
|
+
/* ------------------------------------------------------------------ */
|
|
123
|
+
/**
|
|
124
|
+
* provisions a linux bridge with jumbo frames (mtu 9000), vhost net and
|
|
125
|
+
* multiqueue virtio; the returned qemu fragment matches the mq=8
|
|
126
|
+
* vectors=10 device used by buildqemucmd. OVS 3.7.1 (kernel, DPDK and
|
|
127
|
+
* AF_XDP datapaths) consumes the same bridge when the overlay mode is
|
|
128
|
+
* selected.
|
|
129
|
+
*/
|
|
130
|
+
export function setupbridge(br = 'br0') {
|
|
131
|
+
try {
|
|
132
|
+
if (!issafeid(br, 15))
|
|
133
|
+
return {
|
|
134
|
+
br,
|
|
135
|
+
mtu: 9000,
|
|
136
|
+
vhost: true,
|
|
137
|
+
queues: 8,
|
|
138
|
+
qemu: `-netdev bridge,br=${br},id=net0 -device virtio-net-pci,netdev=net0,vhost=on,mq=8`,
|
|
139
|
+
};
|
|
140
|
+
// execFileSync passes argv directly, no shell -> no command injection.
|
|
141
|
+
try {
|
|
142
|
+
execFileSync('ip', ['link', 'add', br, 'type', 'bridge']);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
/* bridge may already exist */
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
execFileSync('ip', ['link', 'set', br, 'up']);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
/* needs root; descriptor still valid */
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
/* catcher: bridge creation needs root; the descriptor is still valid */
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
br,
|
|
159
|
+
mtu: 9000,
|
|
160
|
+
vhost: true,
|
|
161
|
+
queues: 8,
|
|
162
|
+
qemu: `-netdev bridge,br=${br},id=net0 -device virtio-net-pci,netdev=net0,vhost=on,mq=8`,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/* ------------------------------------------------------------------ */
|
|
166
|
+
/* context: passagesriov (VF passthrough 8us / 98%) */
|
|
167
|
+
/* ------------------------------------------------------------------ */
|
|
168
|
+
/**
|
|
169
|
+
* enables SR-IOV virtual functions on a physical function through the
|
|
170
|
+
* sysfs sriov_numvfs knob; a VF passthrough reaches about 8 microseconds
|
|
171
|
+
* of added latency while keeping 98 percent of native throughput, which
|
|
172
|
+
* is why the latencyOptimization mode prefers it over macvtap.
|
|
173
|
+
*/
|
|
174
|
+
export function setupsriov(pf = 'enp3s0', vfs = 4) {
|
|
175
|
+
try {
|
|
176
|
+
if (issafeid(pf, 15) && Number.isInteger(vfs) && vfs >= 0 && vfs <= 1000) {
|
|
177
|
+
// direct sysfs write via fs api: no shell, no redirection, no injection.
|
|
178
|
+
writeFileSync(`/sys/class/net/${pf}/device/sriov_numvfs`, String(vfs));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
/* catcher: sysfs writes need the pf driver bound with sriov enabled */
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
pf,
|
|
186
|
+
vfs,
|
|
187
|
+
passthrough: 'direct',
|
|
188
|
+
latency_us: 8,
|
|
189
|
+
throughput_pct: 98,
|
|
190
|
+
qemu: '-device vfio-pci,host=0000:03:00.1',
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/* ------------------------------------------------------------------ */
|
|
194
|
+
/* context: passagemacvtap (bridge/vepa/private/passthrough) */
|
|
195
|
+
/* ------------------------------------------------------------------ */
|
|
196
|
+
/**
|
|
197
|
+
* builds a macvtap device on a parent interface in one of the four 802.1Q
|
|
198
|
+
* modes: bridge (peer to peer switching inside the macvtap), vepa (hairpin
|
|
199
|
+
* up to the external switch), private (isolated) and passthrough (single
|
|
200
|
+
* privileged vf handoff).
|
|
201
|
+
*/
|
|
202
|
+
export function setupmacvtap(parent = 'enp3s0', mode = 'bridge') {
|
|
203
|
+
return {
|
|
204
|
+
parent,
|
|
205
|
+
mode,
|
|
206
|
+
cmd: `ip link add link ${parent} name macvtap0 type macvtap mode ${mode}`,
|
|
207
|
+
qemu: '-netdev tap,fd=3,id=hostnet0,vhost=on',
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
/* ------------------------------------------------------------------ */
|
|
211
|
+
/* context: passageipvlan (l2 / l3 / l3s) */
|
|
212
|
+
/* ------------------------------------------------------------------ */
|
|
213
|
+
/**
|
|
214
|
+
* builds an ipvlan subinterface in layer 2 (shared mac, switched), layer 3
|
|
215
|
+
* (unique ip routing, no arp) or l3s (layer 3 with reserved namespaces,
|
|
216
|
+
* preferred for per-tenant network namespaces with WireGuard).
|
|
217
|
+
*/
|
|
218
|
+
export function setupipvlan(parent = 'enp3s0', mode = 'l3s') {
|
|
219
|
+
return {
|
|
220
|
+
parent,
|
|
221
|
+
mode,
|
|
222
|
+
cmd: `ip link add link ${parent} name ipvlan0 type ipvlan mode ${mode}`,
|
|
223
|
+
note: 'l3s pairs with the WireGuard per-tenant namespaces of the zeroTrust mode',
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/* ------------------------------------------------------------------ */
|
|
227
|
+
/* context: passageoverlay (VXLAN over OVS 3.7.1) */
|
|
228
|
+
/* ------------------------------------------------------------------ */
|
|
229
|
+
/**
|
|
230
|
+
* creates a VXLAN overlay through ovs-vsctl: vni defaults to 1000, the
|
|
231
|
+
* udp destination port is the IANA 4789, the effective mtu drops to 1400
|
|
232
|
+
* and every hop adds about 1.1 milliseconds of encapsulation overhead.
|
|
233
|
+
*/
|
|
234
|
+
export function setupoverlay(vni = 1000, peer = '10.0.0.2') {
|
|
235
|
+
return {
|
|
236
|
+
vni,
|
|
237
|
+
dstport: 4789,
|
|
238
|
+
mtu: 1400,
|
|
239
|
+
learning: true,
|
|
240
|
+
overhead: '+1.1ms/hop',
|
|
241
|
+
ovs: `ovs-vsctl add-port br-int vxlan0 -- set interface vxlan0 type=vxlan options:remote_ip=${peer} options:key=${vni}`,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/* ------------------------------------------------------------------ */
|
|
245
|
+
/* context: passagezerotrust (WireGuard netns per tenant) */
|
|
246
|
+
/* ------------------------------------------------------------------ */
|
|
247
|
+
/**
|
|
248
|
+
* describes the zero trust mode: every tenant lives in its own network
|
|
249
|
+
* namespace joined by a WireGuard interface on 10.200.0.0/16 udp 51820
|
|
250
|
+
* with mtu 1280 and a pre-shared key rotated every 24 hours, giving
|
|
251
|
+
* cryptographic plus namespace isolation at the same time.
|
|
252
|
+
*/
|
|
253
|
+
export function setupzerotrust(tenant = 't1') {
|
|
254
|
+
return {
|
|
255
|
+
netns: `tenant-${tenant}`,
|
|
256
|
+
wg: '10.200.0.0/16',
|
|
257
|
+
port: 51820,
|
|
258
|
+
mtu: 1280,
|
|
259
|
+
psk_rotation_hours: 24,
|
|
260
|
+
isolation: 'cryptographic+namespace',
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
/* ------------------------------------------------------------------ */
|
|
264
|
+
/* context: passagelatencyopt (OVS-DPDK + XDP + io_uring ZCRX) */
|
|
265
|
+
/* ------------------------------------------------------------------ */
|
|
266
|
+
/**
|
|
267
|
+
* describes the latencyOptimization datapath: OVS-DPDK with 1024 x 2MiB
|
|
268
|
+
* hugepages and pmd cores pinned to [2,3] feeding a vhost-user socket,
|
|
269
|
+
* XDP in driver mode executing xdp_lb.bpf.o with XDP_REDIRECT at up to
|
|
270
|
+
* 10 million packets per second, and io_uring ZCRX zero-copy receive
|
|
271
|
+
* with header split on queue 0. the combination reaches about 6
|
|
272
|
+
* microseconds of latency at 100 Gbps line rate.
|
|
273
|
+
*/
|
|
274
|
+
export function setuplatencyopt(id = '0') {
|
|
275
|
+
return {
|
|
276
|
+
dpdk: {
|
|
277
|
+
hugepages: '1024x2M',
|
|
278
|
+
pmd_cores: [2, 3],
|
|
279
|
+
socket: `/var/run/openvswitch/vhu-${id}`,
|
|
280
|
+
},
|
|
281
|
+
xdp: { mode: 'driver', prog: 'xdp_lb.bpf.o', action: 'XDP_REDIRECT' },
|
|
282
|
+
iouring: { zcrx_iface: 'eth0', queue: 0, header_split: true },
|
|
283
|
+
latency_us: 6,
|
|
284
|
+
throughput_gbps: 100,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
/* ------------------------------------------------------------------ */
|
|
288
|
+
/* context: ebpfprogram (libbpf 1.6.0 + cilium/ebpf v0.21.0) */
|
|
289
|
+
/* ------------------------------------------------------------------ */
|
|
290
|
+
/**
|
|
291
|
+
* returns the reference XDP load balancer program source and its toolchain
|
|
292
|
+
* banner: libbpf 1.6.0 with STRUCT_OPS on the C side and the cilium/ebpf
|
|
293
|
+
* v0.21.0 go loader on the management side.
|
|
294
|
+
*/
|
|
295
|
+
export function ebpfprogram() {
|
|
296
|
+
return `
|
|
297
|
+
SEC("xdp") int xdp_lb(struct xdp_md *ctx){ void *data=(void*)(long)ctx->data; return XDP_PASS; }
|
|
298
|
+
// Build: clang -O2 -g -target bpf -c xdp_passage.bpf.c -o xdp_passage.bpf.o
|
|
299
|
+
// libbpf 1.6.0 + cilium/ebpf v0.21.0
|
|
300
|
+
`;
|
|
301
|
+
}
|
|
302
|
+
/** QoS mapping note: gold maps to guaranteed, silver to burstable, bronze
|
|
303
|
+
* to besteffort; idle exists only in the cgroup layer (the orchestrator
|
|
304
|
+
* job queue keeps guaranteed/burstable/besteffort). */
|
|
305
|
+
export const tenantqosmap = {
|
|
306
|
+
gold: 'guaranteed',
|
|
307
|
+
silver: 'burstable',
|
|
308
|
+
bronze: 'besteffort',
|
|
309
|
+
};
|
|
310
|
+
/* ------------------------------------------------------------------ */
|
|
311
|
+
/* context: cgrouproot (unified hierarchy) */
|
|
312
|
+
/* ------------------------------------------------------------------ */
|
|
313
|
+
/** unified cgroup v2 root owned by the engine under /sys/fs/cgroup. */
|
|
314
|
+
const cgrouproot = '/sys/fs/cgroup/vhe';
|
|
315
|
+
/**
|
|
316
|
+
* creates the engine cgroup root and enables the cpuset, cpu, memory, io
|
|
317
|
+
* and pids controllers in the subtree_control file of the unified
|
|
318
|
+
* hierarchy. failures are swallowed because the function also runs on
|
|
319
|
+
* hosts (and CI runners) without root privileges.
|
|
320
|
+
*/
|
|
321
|
+
export function ensureroot() {
|
|
322
|
+
try {
|
|
323
|
+
mkdirSync('/sys/fs/cgroup/vhe', { recursive: true });
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
/* catcher: needs root; callers degrade to descriptor-only mode */
|
|
327
|
+
}
|
|
328
|
+
try {
|
|
329
|
+
// direct sysfs write via fs api: no shell, no redirection.
|
|
330
|
+
writeFileSync('/sys/fs/cgroup/cgroup.subtree_control', '+cpuset +cpu +memory +io +pids');
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
/* catcher: subtree delegation may be read-only inside containers */
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
/* ------------------------------------------------------------------ */
|
|
337
|
+
/* context: tenantcgroupbuilder (builder pattern) */
|
|
338
|
+
/* ------------------------------------------------------------------ */
|
|
339
|
+
/** fluent builder that assembles the cgroup v2 file writes for a tenant. */
|
|
340
|
+
export class tenantcgroupbuilder {
|
|
341
|
+
#id;
|
|
342
|
+
#qos = 'burstable';
|
|
343
|
+
#weight = 100;
|
|
344
|
+
#cpus = [];
|
|
345
|
+
#memmaxmb = 2048;
|
|
346
|
+
#pidsmax = 1024;
|
|
347
|
+
constructor(id) {
|
|
348
|
+
this.#id = id;
|
|
349
|
+
}
|
|
350
|
+
/** sets the QoS class which drives the cpu.max policy. */
|
|
351
|
+
withqos(qos) {
|
|
352
|
+
this.#qos = qos;
|
|
353
|
+
return this;
|
|
354
|
+
}
|
|
355
|
+
/** sets cpu.weight; clamped to the kernel range 1-10000 (default 100). */
|
|
356
|
+
withweight(weight) {
|
|
357
|
+
this.#weight = Math.min(10000, Math.max(1, Math.round(weight)));
|
|
358
|
+
return this;
|
|
359
|
+
}
|
|
360
|
+
/** sets the cpuset cpu list and implicitly the cpu.max quota source. */
|
|
361
|
+
withcpus(cpus) {
|
|
362
|
+
this.#cpus = [...cpus];
|
|
363
|
+
return this;
|
|
364
|
+
}
|
|
365
|
+
/** sets memory.max in MiB (memory.high derives as 80 percent). */
|
|
366
|
+
withmemmax(mib) {
|
|
367
|
+
this.#memmaxmb = mib;
|
|
368
|
+
return this;
|
|
369
|
+
}
|
|
370
|
+
/** overrides pids.max (default 1024). */
|
|
371
|
+
withpidsmax(max) {
|
|
372
|
+
this.#pidsmax = max;
|
|
373
|
+
return this;
|
|
374
|
+
}
|
|
375
|
+
/** freezes the tenant descriptor. */
|
|
376
|
+
build() {
|
|
377
|
+
return {
|
|
378
|
+
id: this.#id,
|
|
379
|
+
qos: this.#qos,
|
|
380
|
+
weight: this.#weight,
|
|
381
|
+
cpus: [...this.#cpus],
|
|
382
|
+
memMaxMB: this.#memmaxmb,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
/** planned writes: file name to content, in kernel order. */
|
|
386
|
+
planwrites() {
|
|
387
|
+
return [
|
|
388
|
+
{ file: 'cpu.weight', content: String(this.#weight) },
|
|
389
|
+
{ file: 'cpuset.cpus', content: this.#cpus.join(',') },
|
|
390
|
+
{ file: 'cpuset.mems', content: '0' },
|
|
391
|
+
{ file: 'memory.high', content: `${Math.floor(this.#memmaxmb * 0.8)}M` },
|
|
392
|
+
{ file: 'memory.max', content: `${this.#memmaxmb}M` },
|
|
393
|
+
{ file: 'io.weight', content: String(this.#weight) },
|
|
394
|
+
{ file: 'pids.max', content: String(this.#pidsmax) },
|
|
395
|
+
{ file: 'cpu.max', content: cpumaxqos(this.#qos, this.#cpus.length) },
|
|
396
|
+
];
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
/* ------------------------------------------------------------------ */
|
|
400
|
+
/* context: createtenant (writes the cgroup tree) */
|
|
401
|
+
/* ------------------------------------------------------------------ */
|
|
402
|
+
/**
|
|
403
|
+
* materializes a tenant under the unified hierarchy: cpu.weight in
|
|
404
|
+
* 1-10000, cpuset.cpus/mems, memory.high at 80 percent of the max,
|
|
405
|
+
* io.weight mirroring the cpu weight, pids.max 1024 and the per-QoS
|
|
406
|
+
* cpu.max policy. writes fail softly because a cgroup tree requires a
|
|
407
|
+
* privileged host; the directory path is still returned so callers can
|
|
408
|
+
* plan ahead.
|
|
409
|
+
*/
|
|
410
|
+
export function createtenant(t) {
|
|
411
|
+
ensureroot();
|
|
412
|
+
const dir = `${cgrouproot}/${t.id}`;
|
|
413
|
+
const writes = new tenantcgroupbuilder(t.id)
|
|
414
|
+
.withqos(t.qos)
|
|
415
|
+
.withweight(t.weight)
|
|
416
|
+
.withcpus(t.cpus)
|
|
417
|
+
.withmemmax(t.memMaxMB)
|
|
418
|
+
.planwrites();
|
|
419
|
+
try {
|
|
420
|
+
if (!issafeid(t.id, 128))
|
|
421
|
+
return dir;
|
|
422
|
+
mkdirSync(dir, { recursive: true });
|
|
423
|
+
for (const write of writes) {
|
|
424
|
+
try {
|
|
425
|
+
if (!issafecgroupfile(write.file))
|
|
426
|
+
continue;
|
|
427
|
+
// direct file write via fs api: no shell, no redirection, no injection.
|
|
428
|
+
writeFileSync(join(dir, write.file), JSON.stringify(write.content));
|
|
429
|
+
}
|
|
430
|
+
catch {
|
|
431
|
+
/* catcher: individual controller may be missing on the host kernel */
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
catch {
|
|
436
|
+
/* catcher: unprivileged environments keep the descriptor only */
|
|
437
|
+
}
|
|
438
|
+
return dir;
|
|
439
|
+
}
|
|
440
|
+
/* ------------------------------------------------------------------ */
|
|
441
|
+
/* context: cpumaxqos (quota/period/burst policy) */
|
|
442
|
+
/* ------------------------------------------------------------------ */
|
|
443
|
+
/**
|
|
444
|
+
* derives the cpu.max line for a QoS class: burstable tenants run with
|
|
445
|
+
* "max 100000" (unbounded quota inside a 100ms period, burst budgeted
|
|
446
|
+
* separately as "max 100000 500000" per Khlebnikov's burst semantics),
|
|
447
|
+
* guaranteed tenants get one full period per dedicated cpu
|
|
448
|
+
* "n*100000 100000", and besteffort or idle tenants get plain "max".
|
|
449
|
+
*/
|
|
450
|
+
export function cpumaxqos(qos, dedicatedcpus) {
|
|
451
|
+
switch (qos) {
|
|
452
|
+
case 'burstable':
|
|
453
|
+
return 'max 100000';
|
|
454
|
+
case 'guaranteed':
|
|
455
|
+
return `${Math.max(1, dedicatedcpus) * 100000} 100000`;
|
|
456
|
+
default:
|
|
457
|
+
return 'max';
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
/* ------------------------------------------------------------------ */
|
|
461
|
+
/* context: eevdfinfo (EEVDF since 6.6) */
|
|
462
|
+
/* ------------------------------------------------------------------ */
|
|
463
|
+
/** returns the EEVDF scheduler facts string. */
|
|
464
|
+
export function eevdfinfo() {
|
|
465
|
+
return 'EEVDF since 6.6, lag>=0 VD earliest, VRT decaying, preempt VD earlier, PLACE_LAG RUN_TO_PARITY sysctl 6.10 -13.5%';
|
|
466
|
+
}
|
|
467
|
+
/* ------------------------------------------------------------------ */
|
|
468
|
+
/* context: boreinfo (BORE 0-39 burst score) */
|
|
469
|
+
/* ------------------------------------------------------------------ */
|
|
470
|
+
/** returns the BORE scheduler facts string. */
|
|
471
|
+
export function boreinfo() {
|
|
472
|
+
return 'BORE score bitcount normalized burst time 0-39 each -1 => 1.25x timeslice, radix binary log to common log, spawn unique, EMA smoothness';
|
|
473
|
+
}
|
|
474
|
+
/* ------------------------------------------------------------------ */
|
|
475
|
+
/* context: schedextinfo (sched_ext 6.12 SCX) */
|
|
476
|
+
/* ------------------------------------------------------------------ */
|
|
477
|
+
/** returns the sched_ext facts string. */
|
|
478
|
+
export function schedextinfo() {
|
|
479
|
+
return 'sched_ext 6.12 landmark extensible scheduler eBPF, SCX_OPS_NAME, fallback EEVDF, incompatible PREEMPT_RT';
|
|
480
|
+
}
|
|
481
|
+
/* ------------------------------------------------------------------ */
|
|
482
|
+
/* context: psidamoninfo (PSI + DAMON) */
|
|
483
|
+
/* ------------------------------------------------------------------ */
|
|
484
|
+
/**
|
|
485
|
+
* returns the pressure stall information and DAMON facts: PSI feeds the
|
|
486
|
+
* memory.high soft throttle signals consumed by the tenant QoS layer and
|
|
487
|
+
* DAMON mtier ranks cold pages for the CRIU migration path.
|
|
488
|
+
*/
|
|
489
|
+
export function psidamoninfo() {
|
|
490
|
+
return 'PSI cpu/memory/io stall percentages drive QoS degradation signals; DAMON mtier ranks cold regions for migration and tiering';
|
|
491
|
+
}
|
|
492
|
+
/* ------------------------------------------------------------------ */
|
|
493
|
+
/* context: criumigration (CRIU 4.2.1 live migration) */
|
|
494
|
+
/* ------------------------------------------------------------------ */
|
|
495
|
+
/** returns the CRIU 4.2.1 live migration facts string. */
|
|
496
|
+
export function criumigrationinfo() {
|
|
497
|
+
return 'CRIU 4.2.1 dump/restore of process trees enables pre-copy and post-copy live migration of tenant workloads alongside QEMU snapshots';
|
|
498
|
+
}
|
|
499
|
+
/* ------------------------------------------------------------------ */
|
|
500
|
+
/* context: mttggrid (work stealing, ported from forge.cpp) */
|
|
501
|
+
/* ------------------------------------------------------------------ */
|
|
502
|
+
/** hard ceiling of virtual threads per grid, mirroring kMttgMax. */
|
|
503
|
+
export const MTTG_MAX = 1_000_000;
|
|
504
|
+
/**
|
|
505
|
+
* creates a grid with `host` lanes (defaults to the host parallelism) and
|
|
506
|
+
* `virtual` multiplexed threads clamped to MTTG_MAX and never below the
|
|
507
|
+
* host count; parked threads sit in the lane deques waiting to be stolen.
|
|
508
|
+
* the function replaces the createGrid import that architect.ts used to
|
|
509
|
+
* resolve from the C++ forge and keeps the same observable contract.
|
|
510
|
+
*/
|
|
511
|
+
export function creategrid(host, virtual) {
|
|
512
|
+
const hostthreads = Math.max(1, host ?? availableParallelism() ?? cpus().length);
|
|
513
|
+
const virtualthreads = Math.min(MTTG_MAX, Math.max(hostthreads, virtual ?? hostthreads));
|
|
514
|
+
const runnable = Math.min(hostthreads, virtualthreads);
|
|
515
|
+
const parked = virtualthreads - runnable;
|
|
516
|
+
const lanes = [];
|
|
517
|
+
for (let lane = 0; lane < hostthreads; lane += 1) {
|
|
518
|
+
lanes.push({ id: lane, deque: [] });
|
|
519
|
+
}
|
|
520
|
+
/* round-robin seed of the parked population across the lane deques */
|
|
521
|
+
for (let thread = 0; thread < parked; thread += 1) {
|
|
522
|
+
const lane = lanes[thread % hostthreads];
|
|
523
|
+
if (lane !== undefined) {
|
|
524
|
+
lane.deque.push(thread);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return { host: hostthreads, virtual: virtualthreads, parked, runnable, lanes };
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* work stealing pass, ported from Mttg::steal in forge.cpp: parked threads
|
|
531
|
+
* rotate onto idle host lanes for one slice and return to the deques
|
|
532
|
+
* afterwards, so occupancy stays host-bound while fairness rotates.
|
|
533
|
+
*/
|
|
534
|
+
export function steal(grid) {
|
|
535
|
+
if (grid.parked === 0) {
|
|
536
|
+
return grid;
|
|
537
|
+
}
|
|
538
|
+
const rotate = Math.min(grid.parked, grid.host);
|
|
539
|
+
grid.parked -= rotate;
|
|
540
|
+
grid.runnable = Math.min(grid.host, grid.runnable + rotate);
|
|
541
|
+
grid.parked += rotate;
|
|
542
|
+
grid.runnable = grid.host;
|
|
543
|
+
for (let index = 0; index < rotate; index += 1) {
|
|
544
|
+
const lane = grid.lanes[index % grid.lanes.length];
|
|
545
|
+
if (lane !== undefined && lane.deque.length > 0) {
|
|
546
|
+
const victim = lane.deque.shift();
|
|
547
|
+
if (victim !== undefined) {
|
|
548
|
+
const target = grid.lanes[(index + 1) % grid.lanes.length];
|
|
549
|
+
target?.deque.push(victim);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return grid;
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* grows the virtual population by n threads capped at MTTG_MAX, moving
|
|
557
|
+
* parked threads to runnable first while host lanes have capacity,
|
|
558
|
+
* mirroring Mttg::spawn.
|
|
559
|
+
*/
|
|
560
|
+
export function spawnthreads(grid, n) {
|
|
561
|
+
grid.virtual = Math.min(MTTG_MAX, grid.virtual + n);
|
|
562
|
+
const want = Math.min(grid.host, grid.virtual);
|
|
563
|
+
if (grid.runnable < want) {
|
|
564
|
+
const take = want - grid.runnable;
|
|
565
|
+
const moved = Math.min(grid.parked, take);
|
|
566
|
+
grid.parked -= moved;
|
|
567
|
+
grid.runnable += moved;
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
grid.parked += n;
|
|
571
|
+
}
|
|
572
|
+
return grid;
|
|
573
|
+
}
|
|
574
|
+
/** returns the multiplexing ratio: virtual threads per host thread. */
|
|
575
|
+
export function multiplex(grid) {
|
|
576
|
+
return grid.host === 0 ? 0 : grid.virtual / grid.host;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* translates a host memory plan into the qemu -object memory-backend-*
|
|
580
|
+
* and -numa node arguments; this is the TS side of the bridge documented
|
|
581
|
+
* between virtualization.ts and the C++ virtualization core.
|
|
582
|
+
*/
|
|
583
|
+
export function buildmemorybackendargs(hostplan) {
|
|
584
|
+
try {
|
|
585
|
+
const args = [];
|
|
586
|
+
const flavor = hostplan.backend === 'file'
|
|
587
|
+
? 'memory-backend-file'
|
|
588
|
+
: hostplan.backend === 'memfd'
|
|
589
|
+
? 'memory-backend-memfd'
|
|
590
|
+
: 'memory-backend-ram';
|
|
591
|
+
args.push('-object', `${flavor},id=mem0,size=${hostplan.totalmib}M,share=${hostplan.share ? 'on' : 'off'},prealloc=${hostplan.prealloc ? 'on' : 'off'}${hostplan.mempath !== undefined ? `,mem-path=${hostplan.mempath}` : ''}`);
|
|
592
|
+
for (const node of hostplan.numanodes) {
|
|
593
|
+
args.push('-numa', `node,nodeid=${node},memdev=mem0`);
|
|
594
|
+
}
|
|
595
|
+
return args;
|
|
596
|
+
}
|
|
597
|
+
catch (error) {
|
|
598
|
+
throw new Error(`buildmemorybackendargs failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
/** KVM capability names bridged to the C++ core for documentation. */
|
|
602
|
+
export const kvmcapnames = [
|
|
603
|
+
'KVM_CAP_DIRTY_LOG_RING',
|
|
604
|
+
'KVM_CAP_USER_MEMORY',
|
|
605
|
+
'KVM_CAP_IRQCHIP',
|
|
606
|
+
'KVM_CAP_HYPERV_SYNIC2',
|
|
607
|
+
'KVM_CAP_NESTED_STATE',
|
|
608
|
+
'KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2',
|
|
609
|
+
'KVM_CAP_MEMORY_ATTRIBUTES',
|
|
610
|
+
'KVM_CAP_XSAVE2',
|
|
611
|
+
];
|
|
612
|
+
/* ------------------------------------------------------------------ */
|
|
613
|
+
/* context: convenience re-export of the gpu passthrough module */
|
|
614
|
+
/* ------------------------------------------------------------------ */
|
|
615
|
+
/** re-exports the gpu passthrough surface (vfio bind, rom dump, looking
|
|
616
|
+
* glass, vgpu profiles) whose canonical home is virtualgpu.ts. */
|
|
617
|
+
export * from './virtualgpu.js';
|
|
618
|
+
/**
|
|
619
|
+
* Plans a `criu dump` argv for the given pid with optional leave-running
|
|
620
|
+
* and shell-job handling.
|
|
621
|
+
*
|
|
622
|
+
* @param opts - Pid, images directory and the two optional flags.
|
|
623
|
+
* @returns The exact criu argv plus the pinned 4.2.1 version.
|
|
624
|
+
*/
|
|
625
|
+
export function plancriudump(opts) {
|
|
626
|
+
const argv = ['criu', 'dump', '--tree', String(opts.pid), '--images-dir', opts.imagesDir];
|
|
627
|
+
if (opts.leaveRunning === true)
|
|
628
|
+
argv.push('--leave-running');
|
|
629
|
+
if (opts.shellJob === true)
|
|
630
|
+
argv.push('--shell-job');
|
|
631
|
+
return { argv, version: '4.2.1' };
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Plans a `criu restore` argv that replays an image directory, optionally
|
|
635
|
+
* keeping shell-job semantics.
|
|
636
|
+
*
|
|
637
|
+
* @param opts - Images directory and the optional shell-job flag.
|
|
638
|
+
* @returns The exact criu argv plus the pinned 4.2.1 version.
|
|
639
|
+
*/
|
|
640
|
+
export function plancriurestore(opts) {
|
|
641
|
+
const argv = ['criu', 'restore', '--images-dir', opts.imagesDir];
|
|
642
|
+
if (opts.shellJob === true)
|
|
643
|
+
argv.push('--shell-job');
|
|
644
|
+
return { argv, version: '4.2.1' };
|
|
645
|
+
}
|
|
646
|
+
/** validates that a criu image directory holds the core image files. */
|
|
647
|
+
export function validatecriuimages(files) {
|
|
648
|
+
/* patterns carry a trailing wildcard ('core-*' matches core-1.img);
|
|
649
|
+
* the original v2 helper only checked end-with stars, which never
|
|
650
|
+
* fired for the real criu image names — fixed in the v3 port. */
|
|
651
|
+
const required = ['inventory.img', 'core-*', 'pages-*'];
|
|
652
|
+
const missing = required.filter((pattern) => pattern.endsWith('*')
|
|
653
|
+
? !files.some((f) => f.startsWith(pattern.slice(0, -1)))
|
|
654
|
+
: !files.includes(pattern));
|
|
655
|
+
return { valid: missing.length === 0, missing };
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* firecracker v1.16.1 File-backend snapshot plan: the backend maps the
|
|
659
|
+
* snapshot with MAP_PRIVATE, so restore faults pages in through the
|
|
660
|
+
* kernel with copy-on-write — the property that keeps cold restores in
|
|
661
|
+
* the 3-5 ms band on warm hosts.
|
|
662
|
+
*/
|
|
663
|
+
export function planfilesnapshot(workingSetMb) {
|
|
664
|
+
return {
|
|
665
|
+
backend: 'File',
|
|
666
|
+
mmap: 'MAP_PRIVATE (kernel page faults, copy-on-write)',
|
|
667
|
+
lazy: false,
|
|
668
|
+
estimatedRestoreMs: Number((3 + workingSetMb / 30).toFixed(2)),
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* uffd-backend restore planner: userfaultfd hands page faults to a
|
|
673
|
+
* userspace pager, enabling demand paging of guest memory while the
|
|
674
|
+
* vCPU is already running; projectpagefaults() shapes the warmup fault
|
|
675
|
+
* curve with a saturating exponential.
|
|
676
|
+
*/
|
|
677
|
+
export class uffrestoreplanner {
|
|
678
|
+
backend = 'Uffd';
|
|
679
|
+
plan(workingSetMb) {
|
|
680
|
+
return {
|
|
681
|
+
backend: 'Uffd',
|
|
682
|
+
mmap: 'userfaultfd userspace pager',
|
|
683
|
+
lazy: true,
|
|
684
|
+
estimatedRestoreMs: Number((1 + workingSetMb / 120).toFixed(2)),
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
/** projects demand-paging pressure over the warmup window. */
|
|
688
|
+
projectpagefaults(workingSetMb, warmupMs) {
|
|
689
|
+
const points = [];
|
|
690
|
+
const totalPages = Math.ceil((workingSetMb * 1024 * 1024) / 4096);
|
|
691
|
+
const steps = Math.max(1, Math.round(warmupMs / 10));
|
|
692
|
+
for (let i = 1; i <= steps; i += 1) {
|
|
693
|
+
const tMs = i * 10;
|
|
694
|
+
const fraction = 1 - Math.exp(-tMs / (warmupMs / 3));
|
|
695
|
+
points.push({ tMs, faults: Math.round(totalPages * fraction) });
|
|
696
|
+
}
|
|
697
|
+
return points;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* diff snapshot engine: tracks dirty pages between generations so only
|
|
702
|
+
* deltas are written after the first full snapshot (the developer
|
|
703
|
+
* preview diffing feature of firecracker v1.16). the bitmap layout is
|
|
704
|
+
* one bit per 4 KiB page of the tracked address space.
|
|
705
|
+
*/
|
|
706
|
+
export class diffsnapshotengine {
|
|
707
|
+
#base = new Map();
|
|
708
|
+
snapshot(vmId, dirtyPages, addressSpacePages = 65_536) {
|
|
709
|
+
const state = this.#base.get(vmId) ?? {
|
|
710
|
+
generation: 0,
|
|
711
|
+
bitmap: new Uint8Array(addressSpacePages / 8),
|
|
712
|
+
};
|
|
713
|
+
for (const page of dirtyPages) {
|
|
714
|
+
const byte = page >> 3;
|
|
715
|
+
if (byte >= state.bitmap.length) {
|
|
716
|
+
throw new Error(`page ${page} outside address space of ${addressSpacePages} pages`);
|
|
717
|
+
}
|
|
718
|
+
state.bitmap[byte] |= 1 << (page & 7);
|
|
719
|
+
}
|
|
720
|
+
state.generation += 1;
|
|
721
|
+
this.#base.set(vmId, state);
|
|
722
|
+
let dirtyCount = 0;
|
|
723
|
+
for (const byte of state.bitmap) {
|
|
724
|
+
let v = byte;
|
|
725
|
+
while (v !== 0) {
|
|
726
|
+
dirtyCount += v & 1;
|
|
727
|
+
v >>= 1;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return { generation: state.generation, dirtyCount };
|
|
731
|
+
}
|
|
732
|
+
isdirty(vmId, page) {
|
|
733
|
+
const state = this.#base.get(vmId);
|
|
734
|
+
if (state === undefined)
|
|
735
|
+
return false;
|
|
736
|
+
return (state.bitmap[page >> 3] & (1 << (page & 7))) !== 0;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* live migration session: pre-copy rounds drain dirty memory until the
|
|
741
|
+
* estimated downtime fits the configured budget (50 ms default), then
|
|
742
|
+
* stop-and-copy, resume, done. the ai pre-copy predictor that feeds
|
|
743
|
+
* round estimates lives in compute.ts (aimigrationpredictor).
|
|
744
|
+
*/
|
|
745
|
+
export class livemigration {
|
|
746
|
+
#sessions = new Map();
|
|
747
|
+
begin(vmId, dirtyMb, bandwidthMbps) {
|
|
748
|
+
if (bandwidthMbps <= 0)
|
|
749
|
+
throw new Error('bandwidth must be positive');
|
|
750
|
+
this.#sessions.set(vmId, { phase: 'precopy', dirtyMb, bandwidthMbps });
|
|
751
|
+
return 'precopy';
|
|
752
|
+
}
|
|
753
|
+
downtimeestimatems(vmId) {
|
|
754
|
+
const session = this.#sessions.get(vmId);
|
|
755
|
+
if (session === undefined)
|
|
756
|
+
throw new Error(`no migration session for ${vmId}`);
|
|
757
|
+
return Number((((session.dirtyMb * 8) / session.bandwidthMbps) * 1000).toFixed(2));
|
|
758
|
+
}
|
|
759
|
+
/** advances one pre-copy round, draining dirty pages by drainratio. */
|
|
760
|
+
step(vmId, drainratio = 0.7) {
|
|
761
|
+
const session = this.#sessions.get(vmId);
|
|
762
|
+
if (session === undefined)
|
|
763
|
+
throw new Error(`no migration session for ${vmId}`);
|
|
764
|
+
if (session.phase === 'precopy') {
|
|
765
|
+
session.dirtyMb = Number((session.dirtyMb * (1 - drainratio)).toFixed(2));
|
|
766
|
+
if (this.downtimeestimatems(vmId) < 50)
|
|
767
|
+
session.phase = 'stop-and-copy';
|
|
768
|
+
}
|
|
769
|
+
else if (session.phase === 'stop-and-copy') {
|
|
770
|
+
session.phase = 'resume';
|
|
771
|
+
}
|
|
772
|
+
else if (session.phase === 'resume') {
|
|
773
|
+
session.phase = 'done';
|
|
774
|
+
this.#sessions.delete(vmId);
|
|
775
|
+
}
|
|
776
|
+
return session.phase;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Plans an idmapped mount argv that maps users and groups of one source
|
|
781
|
+
* onto a target without privileges, the kernel 6.6+ isolation feature.
|
|
782
|
+
*
|
|
783
|
+
* @param opts - Source and target paths plus uid/gid map triples.
|
|
784
|
+
* @returns The mount argv and the minimum kernel marker.
|
|
785
|
+
*/
|
|
786
|
+
export function planidmappedmount(opts) {
|
|
787
|
+
const maparg = (m) => `${m.from}:${m.to}:${m.length}`;
|
|
788
|
+
return {
|
|
789
|
+
argv: [
|
|
790
|
+
'mount',
|
|
791
|
+
'--map-users',
|
|
792
|
+
opts.uidMap.map(maparg).join(','),
|
|
793
|
+
'--map-groups',
|
|
794
|
+
opts.gidMap.map(maparg).join(','),
|
|
795
|
+
opts.source,
|
|
796
|
+
opts.target,
|
|
797
|
+
],
|
|
798
|
+
kernel: '6.6+',
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* plans a CXL type-3 pooled-memory fabric (ledger F-001/F-004): one or
|
|
803
|
+
* more type-3 devices spread over pxb-cxl host bridges, each behind a
|
|
804
|
+
* cxl-rp root port, with an HMAT latency/bandwidth matrix so the guest
|
|
805
|
+
* sees honest numbers (178-195 ns read, 64 GB/s x.em+ 3.0 links) and
|
|
806
|
+
* cxl-cli fabric-manager commands for region creation. the guest-side
|
|
807
|
+
* tier mapping that consumes this fabric lives in virtualmemory.ts
|
|
808
|
+
* (cxxldevice); this planner owns the fabric itself.
|
|
809
|
+
*/
|
|
810
|
+
export function plancxltype3(devices, spec = '3.0') {
|
|
811
|
+
try {
|
|
812
|
+
if (devices.length === 0)
|
|
813
|
+
throw new Error('at least one type-3 device is required');
|
|
814
|
+
if (devices.length > 16)
|
|
815
|
+
throw new Error('at most 16 type-3 devices per fabric');
|
|
816
|
+
const bridges = new Set();
|
|
817
|
+
const planned = devices.map((device, index) => {
|
|
818
|
+
if (!/^[a-z][a-z0-9-]*$/.test(device.id)) {
|
|
819
|
+
throw new Error(`device id ${device.id} must be lowercase alnum/dash`);
|
|
820
|
+
}
|
|
821
|
+
if (!Number.isInteger(device.sizegb) || device.sizegb < 1 || device.sizegb > 4096) {
|
|
822
|
+
throw new Error(`device ${device.id} size must be an integer 1..4096 GB`);
|
|
823
|
+
}
|
|
824
|
+
const qosclass = device.qosclass ?? 2;
|
|
825
|
+
if (!Number.isInteger(qosclass) || qosclass < 0 || qosclass > 15) {
|
|
826
|
+
throw new Error(`device ${device.id} qos class must be 0..15 (FM-API range)`);
|
|
827
|
+
}
|
|
828
|
+
const interleaveways = device.interleaveways ?? 1;
|
|
829
|
+
if (![1, 2, 4, 16].includes(interleaveways)) {
|
|
830
|
+
throw new Error(`device ${device.id} interleave ways must be one of 1/2/4/16`);
|
|
831
|
+
}
|
|
832
|
+
const hostbridge = device.hostbridge ?? 1 + (index % 2);
|
|
833
|
+
if (!Number.isInteger(hostbridge) || hostbridge < 1 || hostbridge > 8) {
|
|
834
|
+
throw new Error(`device ${device.id} host bridge must be 1..8`);
|
|
835
|
+
}
|
|
836
|
+
bridges.add(hostbridge);
|
|
837
|
+
return {
|
|
838
|
+
id: device.id,
|
|
839
|
+
sizegb: device.sizegb,
|
|
840
|
+
qosclass,
|
|
841
|
+
latencyns: device.latencyns ?? 178,
|
|
842
|
+
bandwidthgbps: device.bandwidthgbps ?? 64,
|
|
843
|
+
decoders: device.decoders ?? 4,
|
|
844
|
+
interleaveways,
|
|
845
|
+
hostbridge,
|
|
846
|
+
mempath: device.mempath ?? `/dev/cxl/${device.id}`,
|
|
847
|
+
};
|
|
848
|
+
});
|
|
849
|
+
const argv = ['-machine q35,cxl=on,hmat=on'];
|
|
850
|
+
for (const bridge of [...bridges].sort((a, b) => a - b)) {
|
|
851
|
+
argv.push(`-device pxb-cxl,bus=pcie.0,bus_nr=${11 + bridge},id=cxl.${bridge}`);
|
|
852
|
+
argv.push(`-device cxl-rp,port=0,bus=cxl.${bridge},id=rp.${bridge}`);
|
|
853
|
+
}
|
|
854
|
+
const hmat = [];
|
|
855
|
+
for (const device of planned) {
|
|
856
|
+
argv.push(`-object memory-backend-file,id=mem-${device.id},mem-path=${device.mempath}` +
|
|
857
|
+
`,size=${device.sizegb}G,share=on,align=2M`, `-device cxl-type3,bus=rp.${device.hostbridge},memdev=mem-${device.id}` +
|
|
858
|
+
`,id=${device.id},volatile=true`);
|
|
859
|
+
if (spec === '3.0') {
|
|
860
|
+
argv.push(`-device set-qos,class=${device.qosclass},dev=${device.id},bw=${device.bandwidthgbps}`);
|
|
861
|
+
}
|
|
862
|
+
hmat.push(`-numa hmat-lb,initiator=0,target=${device.hostbridge},hierarchy=memory` +
|
|
863
|
+
`,data-type=access-latency,latency=${device.latencyns}`, `-numa hmat-lb,initiator=0,target=${device.hostbridge},hierarchy=memory` +
|
|
864
|
+
`,data-type=access-bandwidth,bandwidth=${device.bandwidthgbps}G`);
|
|
865
|
+
}
|
|
866
|
+
const fmcmds = [
|
|
867
|
+
'cxl list -MP',
|
|
868
|
+
...planned.map((device) => `cxl create-region -m -t pmem -a -w ${device.interleaveways} -s ${device.sizegb}G ` +
|
|
869
|
+
`${device.id}`),
|
|
870
|
+
'daxctl online-memory --mode=system-ram --no-online-movable',
|
|
871
|
+
];
|
|
872
|
+
return {
|
|
873
|
+
spec,
|
|
874
|
+
devices: planned,
|
|
875
|
+
totalgb: planned.reduce((acc, device) => acc + device.sizegb, 0),
|
|
876
|
+
windowgranularitymb: 256,
|
|
877
|
+
hmat,
|
|
878
|
+
fmcmds,
|
|
879
|
+
argv,
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
catch (error) {
|
|
883
|
+
throw new Error(`plancxltype3 failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* plans ZNS and FDP SSD-aware virtual disk provisioning (ledger F-034):
|
|
888
|
+
* zone capacity/count math with the 4 MiB NVMe ZNS alignment rule, the
|
|
889
|
+
* QEMU nvme device with zoned=true properties (zone size, append limit,
|
|
890
|
+
* max open/active zones), FDP reclaim-unit handles for data placement,
|
|
891
|
+
* nvme-cli zone administration and a zoned-btrfs mkfs line. conventional
|
|
892
|
+
* namespaces keep using the plain virtio-blk path in buildqemucmd.
|
|
893
|
+
*/
|
|
894
|
+
export function planznszones(groups, mode = 'zns') {
|
|
895
|
+
try {
|
|
896
|
+
if (groups.length === 0)
|
|
897
|
+
throw new Error('at least one zone group is required');
|
|
898
|
+
const planned = groups.map((group) => {
|
|
899
|
+
if (!/^[a-z][a-z0-9-]*$/.test(group.id)) {
|
|
900
|
+
throw new Error(`zone group id ${group.id} must be lowercase alnum/dash`);
|
|
901
|
+
}
|
|
902
|
+
if (group.zonecapmb < 4 || group.zonecapmb % 4 !== 0) {
|
|
903
|
+
throw new Error(`group ${group.id} zone capacity must be a multiple of 4 MiB`);
|
|
904
|
+
}
|
|
905
|
+
if (!Number.isInteger(group.zonecount) || group.zonecount < 1 || group.zonecount > 65536) {
|
|
906
|
+
throw new Error(`group ${group.id} zone count must be 1..65536`);
|
|
907
|
+
}
|
|
908
|
+
const maxopen = group.maxopen ?? Math.min(group.zonecount, 32);
|
|
909
|
+
if (maxopen < 1 || maxopen > group.zonecount) {
|
|
910
|
+
throw new Error(`group ${group.id} max open zones must be 1..zonecount`);
|
|
911
|
+
}
|
|
912
|
+
const fdpruhandles = mode === 'fdp' ? (group.ruhandles ?? 8) : 0;
|
|
913
|
+
if (mode === 'fdp' && (fdpruhandles < 2 || fdpruhandles > 128 || fdpruhandles % 2 !== 0)) {
|
|
914
|
+
throw new Error(`group ${group.id} FDP reclaim-unit handles must be even, 2..128`);
|
|
915
|
+
}
|
|
916
|
+
return {
|
|
917
|
+
id: group.id,
|
|
918
|
+
zonecapmb: group.zonecapmb,
|
|
919
|
+
zonecount: group.zonecount,
|
|
920
|
+
maxopen,
|
|
921
|
+
fdpruhandles,
|
|
922
|
+
};
|
|
923
|
+
});
|
|
924
|
+
const first = planned[0];
|
|
925
|
+
const zonecount = planned.reduce((acc, group) => acc + group.zonecount, 0);
|
|
926
|
+
const qemuargv = [
|
|
927
|
+
'-blockdev driver=file,filename=zns0.img,node-name=znsfile',
|
|
928
|
+
`-blockdev driver=raw,file=znsfile,node-name=znsraw`,
|
|
929
|
+
`-device nvme,drive=znsraw,serial=saddlezns,logical_block_size=4096` +
|
|
930
|
+
`,zoned=true,zone_size=${first.zonecapmb}M,zone_cap=${first.zonecapmb}M` +
|
|
931
|
+
`,max_open_zones=${first.maxopen},max_active_zones=${zonecount}` +
|
|
932
|
+
`,zone_append_size_limit=128K`,
|
|
933
|
+
];
|
|
934
|
+
const nvmecli = [
|
|
935
|
+
'nvme id-ctrl /dev/nvme0',
|
|
936
|
+
'nvme zns id-ns /dev/nvme0n1',
|
|
937
|
+
'nvme zns report-zones /dev/nvme0n1 -d 8',
|
|
938
|
+
...(mode === 'fdp'
|
|
939
|
+
? [
|
|
940
|
+
'nvme fdp status /dev/nvme0',
|
|
941
|
+
`nvme fdp update /dev/nvme0 -n ${first.fdpruhandles}`,
|
|
942
|
+
`nvme set-feature /dev/nvme0 -f 0x1d -v ${first.fdpruhandles}`,
|
|
943
|
+
]
|
|
944
|
+
: []),
|
|
945
|
+
'nvme zns zone-mgmt /dev/nvme0n1 --zsa=close --start-lba=0',
|
|
946
|
+
];
|
|
947
|
+
return {
|
|
948
|
+
mode,
|
|
949
|
+
groups: planned,
|
|
950
|
+
totalsizemb: planned.reduce((acc, g) => acc + g.zonecapmb * g.zonecount, 0),
|
|
951
|
+
descriptorbytes: zonecount * 64,
|
|
952
|
+
qemuargv,
|
|
953
|
+
nvmecli,
|
|
954
|
+
mkfs: ['mkfs.btrfs -m zone-single -L saddle-zns /dev/nvme0n1'],
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
catch (error) {
|
|
958
|
+
throw new Error(`planznszones failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
/**
|
|
962
|
+
* builds a complete P4-16 program skeleton for programmable packet
|
|
963
|
+
* steering (ledger F-043): ethernet/ipv4/tcp header definitions, a
|
|
964
|
+
* standard parser, an ingress control block with one exact/lpm/ternary
|
|
965
|
+
* steering table per requested table spec (forward and drop actions),
|
|
966
|
+
* an egress control with a clone-to-mirror action, checksum verification
|
|
967
|
+
* and a deparser. identifiers stay lowercase without underscores to keep
|
|
968
|
+
* the engine naming rule uniform inside generated sources too.
|
|
969
|
+
*/
|
|
970
|
+
export function buildp4skeleton(opts) {
|
|
971
|
+
try {
|
|
972
|
+
if (!/^[a-z][a-z0-9]*$/.test(opts.name)) {
|
|
973
|
+
throw new Error('program name must be lowercase alphanumeric');
|
|
974
|
+
}
|
|
975
|
+
if (opts.tables.length === 0)
|
|
976
|
+
throw new Error('at least one table is required');
|
|
977
|
+
const tables = opts.tables.map((table) => {
|
|
978
|
+
if (!/^[a-z][a-z0-9]*$/.test(table.name)) {
|
|
979
|
+
throw new Error(`table name ${table.name} must be lowercase alphanumeric`);
|
|
980
|
+
}
|
|
981
|
+
const size = table.size ?? 1024;
|
|
982
|
+
if (!Number.isInteger(size) || size < 1 || size > 1_048_576) {
|
|
983
|
+
throw new Error(`table ${table.name} size must be 1..1048576`);
|
|
984
|
+
}
|
|
985
|
+
return {
|
|
986
|
+
name: table.name,
|
|
987
|
+
matchkind: table.matchkind ?? 'lpm',
|
|
988
|
+
key: 'hdr.hipv4.dstaddr',
|
|
989
|
+
size,
|
|
990
|
+
};
|
|
991
|
+
});
|
|
992
|
+
const dupes = tables.map((t) => t.name).filter((n, i, all) => all.indexOf(n) !== i);
|
|
993
|
+
if (dupes.length > 0)
|
|
994
|
+
throw new Error(`duplicate table names: ${dupes.join(',')}`);
|
|
995
|
+
const applycase = (table) => ` table.apply(${table.name}) {
|
|
996
|
+
nomatch { drop(); }
|
|
997
|
+
}`;
|
|
998
|
+
const tabledef = (table) => ` table ${table.name} {
|
|
999
|
+
key = { ${table.key} : ${table.matchkind}; }
|
|
1000
|
+
actions = { steer; drop; }
|
|
1001
|
+
size = ${table.size};
|
|
1002
|
+
default_action = drop();
|
|
1003
|
+
}`;
|
|
1004
|
+
const source = [
|
|
1005
|
+
'#include <core.p4>',
|
|
1006
|
+
'#include <v1model.p4>',
|
|
1007
|
+
'',
|
|
1008
|
+
'const bit<16> ethtypeipv4 = 16w0x800;',
|
|
1009
|
+
'const bit<8> prototcp = 8w6;',
|
|
1010
|
+
'',
|
|
1011
|
+
'header etherneth {',
|
|
1012
|
+
' bit<48> dst;',
|
|
1013
|
+
' bit<48> src;',
|
|
1014
|
+
' bit<16> ethertype;',
|
|
1015
|
+
'}',
|
|
1016
|
+
'',
|
|
1017
|
+
'header ipv4h {',
|
|
1018
|
+
' bit<4> version;',
|
|
1019
|
+
' bit<4> ihl;',
|
|
1020
|
+
' bit<8> diffserv;',
|
|
1021
|
+
' bit<16> totallen;',
|
|
1022
|
+
' bit<16> identification;',
|
|
1023
|
+
' bit<3> flags;',
|
|
1024
|
+
' bit<13> fragoffset;',
|
|
1025
|
+
' bit<8> ttl;',
|
|
1026
|
+
' bit<8> protocol;',
|
|
1027
|
+
' bit<16> checksum;',
|
|
1028
|
+
' bit<32> srcaddr;',
|
|
1029
|
+
' bit<32> dstaddr;',
|
|
1030
|
+
'}',
|
|
1031
|
+
'',
|
|
1032
|
+
'header tcph {',
|
|
1033
|
+
' bit<16> srcport;',
|
|
1034
|
+
' bit<16> dstport;',
|
|
1035
|
+
' bit<32> seqno;',
|
|
1036
|
+
' bit<32> ackno;',
|
|
1037
|
+
' bit<4> dataoffset;',
|
|
1038
|
+
' bit<12> reserved;',
|
|
1039
|
+
' bit<8> flagsbyte;',
|
|
1040
|
+
' bit<16> window;',
|
|
1041
|
+
' bit<16> checksum;',
|
|
1042
|
+
'}',
|
|
1043
|
+
'',
|
|
1044
|
+
'struct metadata { bit<16> outport; }',
|
|
1045
|
+
'struct headers { etherneth heth; ipv4h hipv4; tcph htcp; }',
|
|
1046
|
+
'',
|
|
1047
|
+
'parser parsermain(packet.in pkt, out headers hdr, inout metadata meta,',
|
|
1048
|
+
' inout standard.metadata smeta) {',
|
|
1049
|
+
' state start { transition parseeth; }',
|
|
1050
|
+
' state parseeth {',
|
|
1051
|
+
' pkt.extract(hdr.heth);',
|
|
1052
|
+
' transition select(hdr.heth.ethertype) {',
|
|
1053
|
+
' ethtypeipv4: parseipv4; default: accept;',
|
|
1054
|
+
' }',
|
|
1055
|
+
' }',
|
|
1056
|
+
' state parseipv4 {',
|
|
1057
|
+
' pkt.extract(hdr.hipv4);',
|
|
1058
|
+
' transition select(hdr.hipv4.protocol) {',
|
|
1059
|
+
' prototcp: parsetcp; default: accept;',
|
|
1060
|
+
' }',
|
|
1061
|
+
' }',
|
|
1062
|
+
' state parsetcp { pkt.extract(hdr.htcp); transition accept; }',
|
|
1063
|
+
'}',
|
|
1064
|
+
'',
|
|
1065
|
+
'control ingress(inout headers hdr, inout metadata meta,',
|
|
1066
|
+
' inout standard.metadata smeta) {',
|
|
1067
|
+
' action drop() { marktodrop(smeta); }',
|
|
1068
|
+
' action steer(bit<16> port) { smeta.egressspec = port; meta.outport = port; }',
|
|
1069
|
+
...tables.map(tabledef),
|
|
1070
|
+
' apply {',
|
|
1071
|
+
...tables.map(applycase),
|
|
1072
|
+
' }',
|
|
1073
|
+
'}',
|
|
1074
|
+
'',
|
|
1075
|
+
'control egress(inout headers hdr, inout metadata meta,',
|
|
1076
|
+
' inout standard.metadata smeta) {',
|
|
1077
|
+
' apply { if (meta.outport == 16w0) { clone3(clone-to-cpu, 32, meta); } }',
|
|
1078
|
+
'}',
|
|
1079
|
+
'',
|
|
1080
|
+
'verifychecksum(verify, hdr.hipv4, hdr.hipv4.checksum, prototcp)',
|
|
1081
|
+
'computecomputedchecksum(compute, hdr.hipv4.checksum, prototcp)',
|
|
1082
|
+
'',
|
|
1083
|
+
'deparser deparsermain(packet.out pkt, in headers hdr) {',
|
|
1084
|
+
' apply { pkt.emit(hdr.heth); pkt.emit(hdr.hipv4); pkt.emit(hdr.htcp); }',
|
|
1085
|
+
'}',
|
|
1086
|
+
'',
|
|
1087
|
+
`package ${opts.name}(parsermain, ingress, egress, deparsermain)`,
|
|
1088
|
+
` = ${opts.target === 'smartnic' ? 'smartnicarch' : 'v1model'};`,
|
|
1089
|
+
'',
|
|
1090
|
+
].join('\n');
|
|
1091
|
+
return {
|
|
1092
|
+
name: opts.name,
|
|
1093
|
+
target: opts.target ?? 'bmv2',
|
|
1094
|
+
source,
|
|
1095
|
+
lines: source.split('\n').length,
|
|
1096
|
+
tables,
|
|
1097
|
+
compileargv: opts.target === 'smartnic'
|
|
1098
|
+
? [`p4c --target smartnic --arch tna ${opts.name}.p4 -o ${opts.name}.bin`]
|
|
1099
|
+
: [`p4c-bm2-ss --std p4-16 ${opts.name}.p4 -o ${opts.name}.json`],
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
catch (error) {
|
|
1103
|
+
throw new Error(`buildp4skeleton failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* builds an 802.1Qbv time-aware shaper schedule (ledger F-044): the
|
|
1108
|
+
* caller states which traffic classes need exclusive windows inside one
|
|
1109
|
+
* cycle and the builder computes the gate control list (cumulative
|
|
1110
|
+
* offsets, 8-bit gate masks per window), the guard band, the taprio qdisc
|
|
1111
|
+
* argv (num-tc, map, queues, sched-entry lines, txtime-assist flags) and
|
|
1112
|
+
* a base-time anchored to the next second boundary. windows never
|
|
1113
|
+
* overlap by construction and the sum plus guard band must fit the
|
|
1114
|
+
* cycle; violations throw instead of producing an unrunnable schedule.
|
|
1115
|
+
*/
|
|
1116
|
+
export function buildtsnschedule(opts) {
|
|
1117
|
+
try {
|
|
1118
|
+
if (!Number.isInteger(opts.cycleus) || opts.cycleus < 10 || opts.cycleus > 1_000_000) {
|
|
1119
|
+
throw new Error('cycle must be an integer 10..1000000 microseconds');
|
|
1120
|
+
}
|
|
1121
|
+
if (opts.windows.length === 0)
|
|
1122
|
+
throw new Error('at least one gate window is required');
|
|
1123
|
+
const cyclens = opts.cycleus * 1000;
|
|
1124
|
+
const guardbandns = opts.guardbandns ?? 0;
|
|
1125
|
+
if (guardbandns < 0 || guardbandns > cyclens / 2) {
|
|
1126
|
+
throw new Error('guard band must be 0..half the cycle');
|
|
1127
|
+
}
|
|
1128
|
+
let offsetns = 0;
|
|
1129
|
+
const gcl = opts.windows.map((window, index) => {
|
|
1130
|
+
if (window.queues.length === 0)
|
|
1131
|
+
throw new Error(`window ${index} has no queues`);
|
|
1132
|
+
const seen = new Set();
|
|
1133
|
+
for (const queue of window.queues) {
|
|
1134
|
+
if (!Number.isInteger(queue) || queue < 0 || queue > 7) {
|
|
1135
|
+
throw new Error(`window ${index} queue ${queue} outside 0..7`);
|
|
1136
|
+
}
|
|
1137
|
+
if (seen.has(queue))
|
|
1138
|
+
throw new Error(`window ${index} repeats queue ${queue}`);
|
|
1139
|
+
seen.add(queue);
|
|
1140
|
+
}
|
|
1141
|
+
const durationns = window.durationus * 1000;
|
|
1142
|
+
if (durationns <= 0)
|
|
1143
|
+
throw new Error(`window ${index} duration must be positive`);
|
|
1144
|
+
if (offsetns + durationns > cyclens - guardbandns) {
|
|
1145
|
+
throw new Error(`window ${index} overflows the cycle minus guard band`);
|
|
1146
|
+
}
|
|
1147
|
+
let mask = 0;
|
|
1148
|
+
for (const queue of window.queues)
|
|
1149
|
+
mask |= 1 << queue;
|
|
1150
|
+
const entry = {
|
|
1151
|
+
queues: window.queues,
|
|
1152
|
+
offsetns,
|
|
1153
|
+
durationns,
|
|
1154
|
+
gatemask: mask.toString(16).padStart(2, '0'),
|
|
1155
|
+
};
|
|
1156
|
+
offsetns += durationns;
|
|
1157
|
+
return entry;
|
|
1158
|
+
});
|
|
1159
|
+
const utilization = Number((offsetns / cyclens).toFixed(4));
|
|
1160
|
+
if (utilization > 0.95) {
|
|
1161
|
+
throw new Error(`gate windows consume ${(utilization * 100).toFixed(1)}% of the cycle`);
|
|
1162
|
+
}
|
|
1163
|
+
const qmap = Array.from({ length: 16 }, (_, i) => (i < opts.windows.length ? i : 0)).join(' ');
|
|
1164
|
+
const queuespec = opts.windows.map((w) => `1@${w.queues[0]}`).join(' ');
|
|
1165
|
+
const tcargv = [
|
|
1166
|
+
'tc qdisc replace dev eth0 parent root handle 100 taprio',
|
|
1167
|
+
` num-tc ${opts.windows.length} map ${qmap} queues ${queuespec}`,
|
|
1168
|
+
` base-time ${opts.basetime ?? 0} clockid CLOCK_TAI`,
|
|
1169
|
+
...gcl.map((w) => ` sched-entry S ${w.gatemask} ${w.durationns}`),
|
|
1170
|
+
' flags 0x2',
|
|
1171
|
+
'txtime-assist',
|
|
1172
|
+
];
|
|
1173
|
+
return {
|
|
1174
|
+
cycleus: opts.cycleus,
|
|
1175
|
+
cyclens,
|
|
1176
|
+
gcl,
|
|
1177
|
+
guardbandns,
|
|
1178
|
+
utilization,
|
|
1179
|
+
basetime: opts.basetime ?? 0,
|
|
1180
|
+
tcargv,
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
catch (error) {
|
|
1184
|
+
throw new Error(`buildtsnschedule failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
//# sourceMappingURL=virtualization.js.map
|