Firecracker config always emits an empty `vsock` device (omitempty no-op on struct field)

Open Beginner friendly
#811 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
88/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
go

Research direction

Start in pkg/unikontainers/hypervisors/firecracker.go, inspecting the FirecrackerConfig.VSock field and the vsock setup in BuildExecCmd. Reproduce the JSON output for non-vAccel and vAccel cases, then verify that the former omits vsock while the latter retains its complete configuration.

Written by the indexing model from the issue text.

Description

enhancement HW accel Monitors

Description

When generating the Firecracker JSON config, the vsock device is always written into the config, even when vAccel/vsock is not in use. The FirecrackerConfig.VSock field is tagged json:"vsock,omitempty", but omitempty has no effect on a struct value in Go's encoding/json a struct is never considered "empty" so the key is always marshalled.

As a result, every non-vAccel Firecracker boot emits:

"vsock":{"guest_cid":0,"uds_path":"","vsock_id":""}

This is an invalid/meaningless vsock device: guest CID 0 is reserved (valid guest CIDs start at 3) and uds_path is empty. The code intends the opposite, the field is only populated under if args.VAccelType == "vsock" and tagged omitempty so the section should only appear when vAccel is configured.

Note: this is incorrect config generation, not a boot failure, Firecracker currently tolerates the empty section (the non-vAccel e2e tests pass on main). The issue is that the generated config contradicts the code's clear intent.

Relevant code: pkg/unikontainers/hypervisors/firecracker.go:

  • Line 76: VSock FirecrackerVSockDev \json:"vsock,omitempty"`` (struct value)
  • Lines 178-193: the vsock struct is left as its zero value unless args.VAccelType == "vsock", but is always assigned into the config.

The sibling NetIfs []FirecrackerNet field works correctly because omitempty does apply to empty slices. The same "don't emit config that isn't needed" issue was already fixed for the network section in #310 this is the same class of bug for vsock.

Introduced in commit 1c9c720 ("feat: add vAccel support to urunc").

System info

  • urunc version: 0.7.0 (also present on main)
  • Arch: any (config-generation logic, architecture-independent)
  • VMM: Firecracker
  • Unikernel: any (reproduces for any Firecracker guest not using vAccel)

Steps to reproduce

The bug is deterministic and can be shown without running Firecracker, since it's purely in JSON config generation.

  1. Run any non-vAccel Firecracker container (e.g. a hello/nginx Firecracker image) and inspect the generated config (the "Firecracker json config" debug log line). The vsock key is present with guest_cid: 0 and an empty uds_path.

  2. Minimal standalone reproduction of the marshalling behaviour:

    package main

    import (
        "encoding/json"
        "fmt"
    )

    type VSockDev struct {
        GuestCID int    `json:"guest_cid"`
        UDSPath  string `json:"uds_path"`
        VSockID  string `json:"vsock_id"`
    }
    type Config struct {
        VSock VSockDev `json:"vsock,omitempty"`
    }

    func main() {
        b, _ := json.Marshal(Config{}) // no vAccel -> zero value
        fmt.Println(string(b))
    }
Output: `{"vsock":{"guest_cid":0,"uds_path":"","vsock_id":""}}`
Expected with a working `omitempty`: `{}`

Suggested fix

Make VSock a pointer so omitempty takes effect, and only set it in the vAccel branch:

// struct
VSock *FirecrackerVSockDev `json:"vsock,omitempty"`

// in BuildExecCmd
var FCVSockDev *FirecrackerVSockDev
if args.VAccelType == "vsock" {
    FCVSockDev = &FirecrackerVSockDev{ ... }
}
// leave nil otherwise -> vsock key omitted

Verified: with the pointer change, the no-vsock case marshals to {}, and the vAccel case still emits the full vsock section.

Dominant language
Go
Stars
298
Forks
202
Avg merge
2d 18h
Merged PRs (30d)
28

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from urunc-dev/urunc

All issues in urunc-dev/urunc

Similar issues

More Go issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.