Skip to content

feat(unikernels): pass OCI rlimits to urunit config#558

Open
namansh70747 wants to merge 2 commits into
urunc-dev:mainfrom
namansh70747:feat-rlimits
Open

feat(unikernels): pass OCI rlimits to urunit config#558
namansh70747 wants to merge 2 commits into
urunc-dev:mainfrom
namansh70747:feat-rlimits

Conversation

@namansh70747
Copy link
Copy Markdown

@namansh70747 namansh70747 commented Apr 12, 2026

Description

Forward OCI process.rlimits into the generated URUNIT_CONFIG used
for Linux unikernels, so the guest init process (urunit) can enforce
resource limits via setrlimit(2) before starting the target application.

The URUNIT_CONFIG is passed as an initrd to the guest VM and parsed
by urunit from the UCS block. Each rlimit entry is serialized as a
RLIMIT:TYPE:SOFT:HARD line, following the same pattern used for
UID, GID, and WD introduced in #308.

urunc reads u.Spec.Process.Rlimits, stores them in a new
Rlimits []specs.POSIXRlimit field in types.ProcessConfig, and
serializes them in buildUrunitConfig(). The companion urunit PR
that parses and applies these entries via setrlimit(2) before
privilege drop is nubificus/urunit#14.

The implementation was developed independently, with reference to #353
for understanding the existing issue scope.

Related issues

How was this tested?

Executed in a Lima ARM64 VM (macOS host, Docker installed inside VM).

Build and install:

make clean && make && sudo make install && urunc --version
image

Lint:

make lint
image

Unit tests:

go test -v -count=1 ./pkg/unikontainers/unikernels/
image

go vet:

go vet ./pkg/unikontainers/...
image

LLM usage

N/A

Checklist

  • I have read the contribution guide.
  • The linter passes locally (make lint).
  • The e2e tests of at least one tool pass locally (make test_ctr,
    make test_nerdctl, make test_docker, make test_crictl).
    (Lima VM does not expose /dev/kvm, so HVT-backed tests are blocked. The three Qemu-linux
    Ctr tests were run against a custom image with the feat_rlimits urunit binary — all passed.
    attached in comments)
  • If LLMs were used: I have read the llm policy.

Signed-off-by: Naman Sharma namsh70747@gmail.com
Signed-off-by: Sankalp sankalp25103@gmail.com

Copilot AI review requested due to automatic review settings April 12, 2026 15:46
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 12, 2026

Deploy Preview for urunc canceled.

Name Link
🔨 Latest commit b8cff40
🔍 Latest deploy log https://app.netlify.com/projects/urunc/deploys/6a1d4f63196921000839f678

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR forwards OCI process.rlimits into the generated urunit.conf for Linux unikernels so urunit can apply resource limits before starting the target application.

Changes:

  • Extend types.ProcessConfig with Rlimits []specs.POSIXRlimit and populate it from the OCI spec during Exec().
  • Emit one RLIMIT:TYPE:SOFT:HARD line per rlimit in Linux.buildUrunitConfig().
  • Add unit tests around buildUrunitConfig() rlimit serialization.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pkg/unikontainers/unikontainers.go Plumbs OCI Process.Rlimits into the per-guest ProcessConfig.
pkg/unikontainers/unikernels/linux.go Serializes ProcessConfig.Rlimits into urunit.conf as RLIMIT: lines.
pkg/unikontainers/unikernels/linux_test.go Adds tests covering rlimit presence/placement in generated config.
pkg/unikontainers/types/types.go Adds Rlimits field to ProcessConfig and imports OCI runtime-spec types.
.github/linters/urunc-dict.txt Updates linter dictionary for new rlimits/Rlimits tokens.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/linters/urunc-dict.txt Outdated
ESRCH
Prafful
praffq No newline at end of file
praffqrlimits
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The custom dictionary entry appears to have accidentally concatenated two words: praffqrlimits. This won’t whitelist the intended lowercase rlimits token (and also removes the previous praffq entry). Split this into separate lines so rlimits is present as its own dictionary word (and keep/remove praffq intentionally).

Suggested change
praffqrlimits
praffq
rlimits

Copilot uses AI. Check for mistakes.
Comment on lines +39 to +44
l := newTestLinux(nil)
conf := l.buildUrunitConfig()
t.Logf("generated urunit.conf:\n%s", conf)

if strings.Contains(conf, "RLIMIT:") {
t.Fatalf("expected no RLIMIT lines, got:\n%s", conf)
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions unit tests for both nil and empty rlimit slices, but the “no rlimits” test only covers nil. Add an explicit empty-slice case (e.g., []specs.POSIXRlimit{}) to ensure empty-but-non-nil input also produces no RLIMIT: lines.

Suggested change
l := newTestLinux(nil)
conf := l.buildUrunitConfig()
t.Logf("generated urunit.conf:\n%s", conf)
if strings.Contains(conf, "RLIMIT:") {
t.Fatalf("expected no RLIMIT lines, got:\n%s", conf)
tests := []struct {
name string
rlimits []specs.POSIXRlimit
}{
{name: "nil", rlimits: nil},
{name: "empty", rlimits: []specs.POSIXRlimit{}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
l := newTestLinux(tt.rlimits)
conf := l.buildUrunitConfig()
t.Logf("generated urunit.conf:\n%s", conf)
if strings.Contains(conf, "RLIMIT:") {
t.Fatalf("expected no RLIMIT lines, got:\n%s", conf)
}
})

Copilot uses AI. Check for mistakes.
namansh70747 pushed a commit to namansh70747/urunit that referenced this pull request Apr 13, 2026
Parse RLIMIT:TYPE:SOFT:HARD entries from the UCS block and apply them
via setrlimit(2) before privilege drop in setup_exec_env().

The type string (e.g. RLIMIT_NOFILE) is resolved to a POSIX resource
integer using a static lookup table. Limits are stored in two parallel
dynamically allocated arrays inside struct process_config: rlimits[]
for the struct rlimit values and rlimit_resources[] for the resource
integers. Both are freed on cleanup.

This is the urunit side of the OCI rlimits feature. The urunc side
that serializes these entries is in urunc-dev/urunc#558.

Signed-off-by: namansh70747 <namansh70747@gmail.com>
namansh70747 pushed a commit to namansh70747/urunit that referenced this pull request Apr 13, 2026
Parse RLIMIT:TYPE:SOFT:HARD entries from the UCS block and apply them
via setrlimit(2) before privilege drop in setup_exec_env().

The type string (e.g. RLIMIT_NOFILE) is resolved to a POSIX resource
integer using a static lookup table. Limits are stored in two parallel
dynamically allocated arrays inside struct process_config: rlimits[]
for the struct rlimit values and rlimit_resources[] for the resource
integers. Both are freed on cleanup.

This is the urunit side of the OCI rlimits feature. The urunc side
that serializes these entries is in urunc-dev/urunc#558.

Signed-off-by: namansh70747 <namansh70747@gmail.com>
namansh70747 added a commit to namansh70747/urunit that referenced this pull request Apr 13, 2026
Parse RLIMIT:TYPE:SOFT:HARD entries from the UCS block and apply them
via setrlimit(2) before privilege drop in setup_exec_env().

The type string (e.g. RLIMIT_NOFILE) is resolved to a POSIX resource
integer using a static lookup table. Limits are stored in two parallel
dynamically allocated arrays inside struct process_config: rlimits[]
for the struct rlimit values and rlimit_resources[] for the resource
integers. Both are freed on cleanup.

This is the urunit side of the OCI rlimits feature. The urunc side
that serializes these entries is in urunc-dev/urunc#558.

Signed-off-by: namansh70747 <namansh70747@gmail.com>
@namansh70747
Copy link
Copy Markdown
Author

Companion urunit PR is now open: nubificus/urunit#14

@cmainas
Copy link
Copy Markdown
Contributor

cmainas commented Apr 13, 2026

Hello @namansh70747 ,

thank you for this PR. Two things:

  • Please do not overwrite the PR template. Can you please edit your description to follow the PR template?
  • If you have used any code or ideas from the referenced PR, please add the author of the PR as co-author or add another Signed-off with the information of the user.

@namansh70747
Copy link
Copy Markdown
Author

Hi @cmainas, thank you for the feedback.

I have updated the description to follow the PR template.
For the referenced PR #353, I have added a Signed-off-by for the author
as the implementation was developed independently with reference to that PR
for understanding the issue scope.

@cmainas
Copy link
Copy Markdown
Contributor

cmainas commented Apr 14, 2026

Hello @namansh70747 ,

is there any reason for not running the tests and linter locally?


block := conf[ucs : uce+4]
want := "RLIMIT:RLIMIT_NOFILE:1024:4096\n"
if !strings.Contains(block, want) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency, I’d suggest using the assert package from testify, as this is how assertions are handled in other tests.

}
}

func TestBuildUrunitConfigPrintFull(t *testing.T) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this isn’t making any assertions, so I’m not sure it’s worth keeping. It also seems the logic is already covered by the tests above, so we could consider removing it.

@namansh70747
Copy link
Copy Markdown
Author

Hello @cmainas,
At first, Docker wasn’t set up in my Lima VM, so make lint wasn’t working on my side. I’ve fixed that now and ran everything locally:

  • make lint → no issues
  • go test ./pkg/unikontainers/unikernels/... → all tests passed
  • go vet ./pkg/unikontainers/... → clean

I’ve also added screenshots of it in the updated PR description.

@cmainas
Copy link
Copy Markdown
Contributor

cmainas commented Apr 14, 2026

Hello @cmainas, At first, Docker wasn’t set up in my Lima VM, so make lint wasn’t working on my side. I’ve fixed that now and ran everything locally:

* make lint → no issues

* go test ./pkg/unikontainers/unikernels/... → all tests passed

* go vet ./pkg/unikontainers/... → clean

I’ve also added screenshots of it in the updated PR description.

Hello @namansh70747 ,

thank you for running the linter. However, the tests you reference are the unit tests. We also have some end-to-end tests that can be executed with make e2etest. I am worried that if you were not able to run the e2e tests, it would not be possible to test the changes in this PR. Have you performed an end-to-end test using this PR and the PR from the urunit you reference?

@namansh70747
Copy link
Copy Markdown
Author

Hello @cmainas, At first, Docker wasn’t set up in my Lima VM, so make lint wasn’t working on my side. I’ve fixed that now and ran everything locally:

* make lint → no issues

* go test ./pkg/unikontainers/unikernels/... → all tests passed

* go vet ./pkg/unikontainers/... → clean

I’ve also added screenshots of it in the updated PR description.

Hello @namansh70747 ,

thank you for running the linter. However, the tests you reference are the unit tests. We also have some end-to-end tests that can be executed with make e2etest. I am worried that if you were not able to run the e2e tests, it would not be possible to test the changes in this PR. Have you performed an end-to-end test using this PR and the PR from the urunit you reference?

Hi, thank you for the feedback.

I have performed end-to-end testing for this PR. Since the changes touch the Linux unikernel path (specifically buildUrunitConfig in linux.go and the Rlimits field in types.go), I focused my e2e validation on the Ctr Qemu-linux test cases, which exercise exactly that code path.

To also verify the urunit side (the PR I referenced), I built the urunit_static binary from my feat_rlimits branch (~/urunit-feat_rlimits/dist/), copied it into a build context at /tmp/urunit-ctx/urunit, and used a two-line Dockerfile (FROM harbor.nbfc.io/nubificus/urunc/hello-world-qemu-linux-initrd:latest / COPY urunit /urunit) to embed it. I then ran sudo docker build, sudo docker save, and sudo nerdctl -n default load to get the custom image into containerd. The load output confirmed Loaded image: harbor.nbfc.io/nubificus/urunc/hello-world-qemu-linux-initrd:latest with digest sha256:8fc09402c504..., and a follow-up nerdctl images verified that same digest was present locally before any test ran.

I ran the tests with URUNC_LOCAL_IMAGES=1 to ensure the suite used my locally loaded image instead of pulling from the registry. This flag is backed by a guard I added at the top of commonPull() in tests/e2e/common.go — when os.Getenv("URUNC_LOCAL_IMAGES") == "1", the function returns nil immediately without pulling. The Pulling image: lines visible in the logs are the test suite's standard logging behavior and fire even when the actual pull is skipped, so the locally loaded image with digest 8fc09402c504 was the one running inside the VM throughout.

The three tests I ran against the custom image are attached to this comment:

  • Ctr unikernel containers Qemu-linux-hello-world — passed
  • Ctr unikernel containers Qemu-linux-read-file-virtiofs — passed
  • Ctr unikernel containers Qemu-linux-environment-setup-create-initrd — passed

All 3 passed, 0 failed.

Regarding the remaining test cases in the suite: the HVT tests fail due to a pre-existing seccomp filter stacking issue unrelated to this change (reproducible on the main branch as well), and the Qemu-unikraft/Firecracker-unikraft tests do not go through buildUrunitConfig so they are not affected by this PR. The three Qemu-linux cases are the only ones in the suite that exercise exactly that code path — a broader run skipping only Hvt and Qemu-unikraft confirmed 11 passed with 0 failed, showing the non-KVM-dependent subset of the matrix is clean. The full make e2etest suite requires a bare-metal Linux host with /dev/kvm for the full matrix, which is not available in my Lima VM on macOS — this is noted in the PR checklist.

Let me know if you need any additional information.


Test run summary

Test output page 1

image

@namansh70747 namansh70747 requested a review from IrvingMg April 26, 2026 08:49
@cmainas
Copy link
Copy Markdown
Contributor

cmainas commented Apr 27, 2026

Hello @namansh70747 ,

thank you for the extra information and the tests you executed.

To also verify the urunit side (the PR I referenced), I built the urunit_static binary from my feat_rlimits branch (~/urunit-feat_rlimits/dist/), copied it into a build context at /tmp/urunit-ctx/urunit, and used a two-line Dockerfile (FROM harbor.nbfc.io/nubificus/urunc/hello-world-qemu-linux-initrd:latest / COPY urunit /urunit) to embed it. I then ran sudo docker build, sudo docker save, and sudo nerdctl -n default load to get the custom image into containerd. The load output confirmed Loaded image: harbor.nbfc.io/nubificus/urunc/hello-world-qemu-linux-initrd:latest with digest sha256:8fc09402c504..., and a follow-up nerdctl images verified that same digest was present locally before any test ran.

Just a note, the Linux images in the tests that do not end in raw (e.g. initrd) do not use the container's rootfs as the rootfs for the sandbox, therefore the COPY inside the container's rootfs will not replace the urunit binary.

Regarding the remaining test cases in the suite: the HVT tests fail due to a pre-existing seccomp filter stacking issue unrelated to this change (reproducible on the main branch as well),

We need to open a new issue for this.

and the Qemu-unikraft/Firecracker-unikraft tests do not go through buildUrunitConfig so they are not affected by this PR. The three Qemu-linux cases are the only ones in the suite that exercise exactly that code path — a broader run skipping only Hvt and Qemu-unikraft confirmed 11 passed with 0 failed, showing the non-KVM-dependent subset of the matrix is clean.
The full make e2etest suite requires a bare-metal Linux host with /dev/kvm for the full matrix, which is not available in my Lima VM on macOS — this is noted in the PR checklist.

I am not sure what you mean non-KVM dependent. Qemu uses KVM too.

Let me know if you need any additional information.

The above tests showcase that the changes in this PR do not break the existing functionality of urunc. However, I am still unsure if these changes have been tested end-to-end and make sure that urunit receives the rlimit information and sets them correctly. I am sorry for pushing back on this, but before submitting new changes, we need to make sure that these changes are actually working.

@namansh70747
Copy link
Copy Markdown
Author

namansh70747 commented May 2, 2026

End-to-end Verification of rlimit Support

Hi, thank you for the detailed review and for pushing back — it led to a much
more thorough verification. Below is concrete evidence for the full path:
ctr run --rlimit-nofile → OCI spec → uruncurunit config →
setrlimit(2) inside the VM.


1. E2E Test Suite: 3 Passed, 0 Failed

Running make e2etest filtered to qemu-linux (the only specs that exercise
the buildUrunitConfig path):

image

These three specs drive the exact code path from Exec()
buildUrunitConfig() → urunit inside QEMU.


2. OCI Spec Confirms rlimits Are Wired In

sudo ctr -n default run --rm \
  --runtime io.containerd.urunc.v2 \
  --snapshotter devmapper \
  --rlimit-nofile 1024:4096 \
  --dump-config /tmp/oci-spec.json \
  harbor.nbfc.io/nubificus/urunc/hello-exec-env-qemu-linux-raw:rlimits-test \
  rlimits-test-container5 2>/dev/null || true

cat /tmp/oci-spec.json | python3 -m json.tool | grep -A 20 "rlimits\|Rlimit"

Output:

"rlimits": [
    {
        "type": "RLIMIT_NOFILE",
        "hard": 4096,
        "soft": 1024
    }
],
"noNewPrivileges": true
image

The OCI spec correctly carries the requested limits before urunc even touches them.


3. urunc Source Threads rlimits Into the urunit Config

grep -n "buildUrunitConfig\|Rlimits\|ProcConfig" \
  pkg/unikontainers/unikernels/linux.go \
  pkg/unikontainers/unikontainers.go
image

u.Spec.Process.Rlimits is read directly from the OCI spec (verified in step 2)
and written into procAttrs, which is then passed as ProcConf to
buildUrunitConfig(). The loop at line 317 iterates every rlimit entry and
encodes it into the urunit config that is embedded into the initrd or written to
the rootfs before QEMU starts.


4. urunit Binary on feat_rlimits Contains the rlimit Implementation

strings /home/namansharma.guest/urunit/dist/urunit_static | grep -i "rlimit\|setrlimit"
image

To further confirm the feat_rlimits urunit is different from the base image
urunit, both layers were extracted from the rlimit-test image:

# Layer cc74c9a0 = base urunit (no rlimit support)
mkdir -p /tmp/urunit-base
tar xf blobs/sha256/cc74c9a069ac03b4f764b78e07cc98276ea44c5b6639805e7f2c02ce1f0fae20 \
  -C /tmp/urunit-base

# Layer f7605e4b = feat_rlimits urunit
mkdir -p /tmp/urunit-custom
tar xf blobs/sha256/f7605e4b33fbfe5dd53cb72b71ad02f1d66453cfc9d9b4bb88606c633fafda8f \
  -C /tmp/urunit-custom

strings /tmp/urunit-base/urunit | grep -i "rlimit" | head -3
# (no output)

strings /tmp/urunit-custom/urunit | grep -i "rlimit" | head -3
# RLIMIT_AS
# RLIMIT_CORE
# RLIMIT_CPU

diff /tmp/urunit-base/urunit /tmp/urunit-custom/urunit
# Binary files differ

The base layer urunit (cc74c9a0) produces no rlimit strings. The
feat_rlimits urunit (f7605e4b) contains all of them.

Note on initrd images: The rlimits-verify image used in step 5 is
hello-exec-env-qemu-linux-**raw**, so the container rootfs is the VM rootfs
and the embedded feat_rlimits urunit is what actually runs inside the VM.


5. Live In-VM Verification: rlimits Are Applied (Custom Build)

The rlimits-verify image runs /check_limits, a binary that calls getrlimit(2)
and prints the result.

Baseline — no rlimit flag

sudo ctr -n default run --rm \
  --runtime io.containerd.urunc.v2 \
  --snapshotter devmapper \
  harbor.nbfc.io/nubificus/urunc/hello-exec-env-qemu-linux-raw:rlimits-verify \
  rlimits-test-container8

With --rlimit-nofile 1024:4096

sudo ctr -n default run --rm \
  --runtime io.containerd.urunc.v2 \
  --snapshotter devmapper \
  --rlimit-nofile 1024:4096 \
  harbor.nbfc.io/nubificus/urunc/hello-exec-env-qemu-linux-raw:rlimits-verify \
  rlimits-verify-final2 2>&1 | tee /tmp/verify-final.log

grep "RLIMIT" /tmp/verify-final.log
image

The hard limit changed from 10244096 exactly as requested. This output
is from getrlimit(2) called inside the running QEMU VM by /check_limits,
confirming that urunit received the rlimit from the embedded config, parsed it,
and applied it via setrlimit(2) before handing control to the application.


6. End-to-End Demo: Baseline vs. With rlimit Flag

To make the propagation visually unambiguous, I ran both cases back-to-back
on the same machine with the same image.

Baseline — no --rlimit-nofile flag

sudo ctr -n default run --rm \
  --runtime io.containerd.urunc.v2 \
  --snapshotter devmapper \
  harbor.nbfc.io/nubificus/urunc/hello-exec-env-qemu-linux-raw:latest \
  rlimits-demo-baseline

The VM boots, urunit reads the config, finds no rlimit entries, and the
application runs with kernel defaults. No rlimit line appears because
urunit received an empty rlimits array — the config-to-call path simply has
nothing to apply.

With --rlimit-nofile 1024:4096

sudo ctr -n default run --rm \
  --runtime io.containerd.urunc.v2 \
  --snapshotter devmapper \
  --rlimit-nofile 1024:4096 \
  harbor.nbfc.io/nubificus/urunc/hello-exec-env-qemu-linux-raw:latest-patched \
  rlimits-demo-patched-latest 2>&1 | grep -E "UID:|rlimit|RLIMIT"

latest-patched is built from latest with only the feat_rlimits urunit
binary swapped in via COPY urunit_static /urunit — all other VM contents
(kernel, rootfs, app) are identical to latest. This isolates the urunit
change as the only variable.

Output:

image

Note: The urunit: applied rlimit resource N soft=X hard=Y line is a
temporary debug fprintf added to the feat_rlimits urunit binary solely to
make the verification observable in this comment — it is not part of the code
in this PR.

resource 7 is RLIMIT_NOFILE on Linux x86. The applied rlimit line is
printed by urunit immediately after setrlimit(2) returns successfully,
before setuid()/setgid(). The full path that produced this:

  1. ctr run --rlimit-nofile 1024:4096 → containerd sets
    process.rlimits = [{type: RLIMIT_NOFILE, soft: 1024, hard: 4096}]
    in the OCI spec
  2. urunc's Exec() reads u.Spec.Process.Rlimits and passes it through
    ProcessConfigbuildUrunitConfig(), which writes
    RLIMIT:RLIMIT_NOFILE:1024:4096 into the urunit config embedded in the initrd
  3. urunit parses that line in parse_process_config(), calls
    setrlimit(RLIMIT_NOFILE, {rlim_cur: 1024, rlim_max: 4096}) inside the VM
    before setuid()/setgid() (so it still has root privilege to raise
    the hard limit)
  4. urunit prints the confirmation line, confirming the kernel accepted the
    setrlimit(2) call

@cmainas
Copy link
Copy Markdown
Contributor

cmainas commented May 14, 2026

Hello @namansh70747 ,

thank you for testing it end-to-end.

The proposed solution does not follow the dummy protocol we have created for urunit. In more details, this proposal create lines in the form: RLIMIT: "rlimit_type":"soft limit:"hard limit"", while all other entries are in the form of :. Furthermore, urunc` already knows the number of rlimits and this should be written in the urunit configuration file to make parsing easier. Therefore, the protocol for passing rlimits should be:

RLS
NUM: <number of entries>
TYPE: <rlimit type>
SOFT: <value>
HARD: <value>
...
RLE

namansh70747 and others added 2 commits June 1, 2026 14:45
Serialize process.rlimits from the OCI spec into the URUNIT_CONFIG
file as RLIMIT:TYPE:SOFT:HARD lines inside the UCS block.

Fixes: urunc-dev#312

Signed-off-by: namansh70747 <namsh70747@gmail.com>
Signed-off-by: Sankalp <sankalp25103@gmail.com>
Follow mentor protocol: rlimits get own RLS/RLE block with NUM:<n> header.
Format:
  RLS
  NUM:<n>
  TYPE:<rlimit_type>
  SOFT:<soft>
  HARD:<hard>
  RLE

Block only emitted when rlimits present. Existing images unaffected.
Companion urunit change: namansh70747/urunit#14
Fixes urunc-dev#312

Signed-off-by: Naman Sharma <namsh70747@gmail.com>
@namansh70747
Copy link
Copy Markdown
Author

Hi @cmainas, thanks — done. The rlimits now follow the protocol you specified.

Format change. rlimits are no longer RLIMIT:TYPE:SOFT:HARD lines inside the UCS block. They're now their own RLS/RLE block with a NUM count, placed after UCE:

RLS
NUM:3
TYPE:RLIMIT_NOFILE
SOFT:1024
HARD:4096
TYPE:RLIMIT_NPROC
SOFT:512
HARD:1024
...
RLE

NUM is written first so urunit allocates the arrays exactly once. The block is only emitted when rlimits are present, so existing images produce byte-identical configs. urunit-side parsing was updated to match in nubificus/urunit#14 (parse_rlimit_config, wired between the UCS and UBS parsers).

End-to-end verification (Lima x86_64 VM, QEMU with /dev/kvm, raw image so the embedded feat_rlimits urunit is the one running inside the VM):

Single rlimit — full chain ctr --rlimit-nofile → OCI → urunc → RLS block → urunit → setrlimit(2), confirmed by getrlimit(2) inside the VM:

flag | reported inside VM -- | -- (none) | soft=1024 hard=1024 (default) --rlimit-nofile 1024:4096 | soft=1024 hard=4096 --rlimit-nofile 2048:8192 | soft=2048 hard=8192

Multiple types (exercises the NUM=3 parse loop) — /proc/self/limits read inside the VM after nerdctl --ulimit nofile=1234:5678 --ulimit nproc=99:198 --ulimit core=0:0:

Max core file size        0          0          bytes
Max processes             99         198        processes
Max open files            1234       5678       files

Every value matches what was requested — the kernel's own report confirms urunit parsed all three entries and applied each via setrlimit(2).

The Qemu-linux e2e specs that exercise buildUrunitConfig (read-file-virtiofs, environment-setup-create-initrd) pass. Full screenshot attached. I've also rebased onto current main and resolved the conflicts.

image image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pass rlimits to urunit

4 participants