Skip to content

Commit 2e09014

Browse files
authored
Add support for snapshot memory backend (#495)
* Add support for memory backend - Pull in upstream swagger definitions for SnapshotLoadParams and MemoryBackend - Run `go generate` - Update Snapshot config to allow setting MemBackend - Forward the MemBackend through to the Firecracker client Signed-off-by: Brandon Duffany <brandon@buildbuddy.io> * Adjust MemoryBackend API and add test Signed-off-by: Brandon Duffany <brandon@buildbuddy.io> * Bump firecracker version to v1.4.0 Signed-off-by: Brandon Duffany <brandon@buildbuddy.io> * Address PR feedback Signed-off-by: Brandon Duffany <brandon@buildbuddy.io> * Fix test Signed-off-by: Brandon Duffany <brandon@buildbuddy.io> --------- Signed-off-by: Brandon Duffany <brandon@buildbuddy.io>
1 parent 48a995f commit 2e09014

File tree

8 files changed

+279
-15
lines changed

8 files changed

+279
-15
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ JAILER_BIN=$(FC_TEST_DATA_PATH)/jailer-main
2828
UID = $(shell id -u)
2929
GID = $(shell id -g)
3030

31-
firecracker_version=v1.0.0
31+
firecracker_version=v1.4.0
3232

3333
# The below files are needed and can be downloaded from the internet
3434
release_url=https://github.com/firecracker-microvm/firecracker/releases/download/$(firecracker_version)/firecracker-$(firecracker_version)-$(arch).tgz

client/models/memory_backend.go

Lines changed: 131 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/models/snapshot_load_params.go

Lines changed: 19 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/swagger.yaml

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,25 @@ definitions:
953953
maximum: 32
954954
description: Number of vCPUs (either 1 or an even number)
955955

956+
MemoryBackend:
957+
type: object
958+
required:
959+
- backend_type
960+
- backend_path
961+
properties:
962+
backend_type:
963+
type: string
964+
enum:
965+
- File
966+
- Uffd
967+
backend_path:
968+
type: string
969+
description: Based on 'backend_type' it is either
970+
1) Path to the file that contains the guest memory to be loaded
971+
2) Path to the UDS where a process is listening for a UFFD initialization
972+
control payload and open file descriptor that it can use to serve this
973+
process's guest memory page faults
974+
956975
Metrics:
957976
type: object
958977
description:
@@ -1090,8 +1109,10 @@ definitions:
10901109

10911110
SnapshotLoadParams:
10921111
type: object
1112+
description:
1113+
Defines the configuration used for handling snapshot resume. Exactly one of
1114+
the two `mem_*` fields must be present in the body of the request.
10931115
required:
1094-
- mem_file_path
10951116
- snapshot_path
10961117
properties:
10971118
enable_diff_snapshots:
@@ -1100,7 +1121,16 @@ definitions:
11001121
Enable support for incremental (diff) snapshots by tracking dirty guest pages.
11011122
mem_file_path:
11021123
type: string
1103-
description: Path to the file that contains the guest memory to be loaded.
1124+
description:
1125+
Path to the file that contains the guest memory to be loaded.
1126+
This parameter has been deprecated and is only allowed if
1127+
`mem_backend` is not present.
1128+
mem_backend:
1129+
$ref: "#/definitions/MemoryBackend"
1130+
description:
1131+
Configuration for the backend that handles memory load. If this field
1132+
is specified, `mem_file_path` is forbidden. Either `mem_backend` or
1133+
`mem_file_path` must be present at a time.
11041134
snapshot_path:
11051135
type: string
11061136
description: Path to the file that contains the microVM state to be loaded.

machine.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ type Config struct {
172172
}
173173

174174
func (cfg *Config) hasSnapshot() bool {
175-
return cfg.Snapshot.MemFilePath != "" || cfg.Snapshot.SnapshotPath != ""
175+
return cfg.Snapshot.GetMemBackendPath() != "" || cfg.Snapshot.SnapshotPath != ""
176176
}
177177

178178
// Validate will ensure that the required fields are set and that
@@ -235,7 +235,7 @@ func (cfg *Config) ValidateLoadSnapshot() error {
235235
return fmt.Errorf("socket %s already exists", cfg.SocketPath)
236236
}
237237

238-
if _, err := os.Stat(cfg.Snapshot.MemFilePath); err != nil {
238+
if _, err := os.Stat(cfg.Snapshot.GetMemBackendPath()); err != nil {
239239
return err
240240
}
241241

@@ -649,7 +649,7 @@ func (m *Machine) startVMM(ctx context.Context) error {
649649
return nil
650650
}
651651

652-
//StopVMM stops the current VMM.
652+
// StopVMM stops the current VMM.
653653
func (m *Machine) StopVMM() error {
654654
return m.stopVMM()
655655
}
@@ -1171,7 +1171,8 @@ func (m *Machine) CreateSnapshot(ctx context.Context, memFilePath, snapshotPath
11711171
// loadSnapshot loads a snapshot of the VM
11721172
func (m *Machine) loadSnapshot(ctx context.Context, snapshot *SnapshotConfig) error {
11731173
snapshotParams := &models.SnapshotLoadParams{
1174-
MemFilePath: &snapshot.MemFilePath,
1174+
MemFilePath: snapshot.MemFilePath,
1175+
MemBackend: snapshot.MemBackend,
11751176
SnapshotPath: &snapshot.SnapshotPath,
11761177
EnableDiffSnapshots: snapshot.EnableDiffSnapshots,
11771178
ResumeVM: snapshot.ResumeVM,

machine_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,6 +2125,61 @@ func TestLoadSnapshot(t *testing.T) {
21252125
require.NoError(t, err)
21262126
},
21272127
},
2128+
{
2129+
name: "TestLoadSnapshotWithMemoryBackend",
2130+
createSnapshot: func(ctx context.Context, machineLogger *logrus.Logger, socketPath, memPath, snapPath string) {
2131+
// Create a snapshot
2132+
cfg := createValidConfig(t, socketPath+".create")
2133+
m, err := NewMachine(ctx, cfg, func(m *Machine) {
2134+
// Rewriting m.cmd partially wouldn't work since Cmd has
2135+
// some unexported members
2136+
args := m.cmd.Args[1:]
2137+
m.cmd = exec.Command(getFirecrackerBinaryPath(), args...)
2138+
}, WithLogger(logrus.NewEntry(machineLogger)))
2139+
require.NoError(t, err)
2140+
2141+
err = m.Start(ctx)
2142+
require.NoError(t, err)
2143+
2144+
err = m.PauseVM(ctx)
2145+
require.NoError(t, err)
2146+
2147+
err = m.CreateSnapshot(ctx, memPath, snapPath)
2148+
require.NoError(t, err)
2149+
2150+
err = m.StopVMM()
2151+
require.NoError(t, err)
2152+
},
2153+
2154+
loadSnapshot: func(ctx context.Context, machineLogger *logrus.Logger, socketPath, memPath, snapPath string) {
2155+
// Note that many fields are not necessary when loading a snapshot
2156+
cfg := Config{
2157+
SocketPath: socketPath + ".load",
2158+
Drives: []models.Drive{
2159+
{
2160+
DriveID: String("root"),
2161+
IsRootDevice: Bool(true),
2162+
IsReadOnly: Bool(true),
2163+
PathOnHost: String(testRootfs),
2164+
},
2165+
},
2166+
}
2167+
2168+
m, err := NewMachine(ctx, cfg, func(m *Machine) {
2169+
// Rewriting m.cmd partially wouldn't work since Cmd has
2170+
// some unexported members
2171+
args := m.cmd.Args[1:]
2172+
m.cmd = exec.Command(getFirecrackerBinaryPath(), args...)
2173+
}, WithLogger(logrus.NewEntry(machineLogger)), WithSnapshot("", snapPath, WithMemoryBackend("File", memPath)))
2174+
require.NoError(t, err)
2175+
2176+
err = m.Start(ctx)
2177+
require.NoError(t, err)
2178+
2179+
err = m.StopVMM()
2180+
require.NoError(t, err)
2181+
},
2182+
},
21282183
{
21292184
name: "TestLoadSnapshot without create",
21302185
createSnapshot: func(ctx context.Context, machineLogger *logrus.Logger, socketPath, memPath, snapPath string) {

opts.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package firecracker
1616
import (
1717
"os/exec"
1818

19+
"github.com/firecracker-microvm/firecracker-go-sdk/client/models"
1920
"github.com/sirupsen/logrus"
2021
)
2122

@@ -53,6 +54,14 @@ func WithProcessRunner(cmd *exec.Cmd) Opt {
5354
type WithSnapshotOpt func(*SnapshotConfig)
5455

5556
// WithSnapshot will allow for the machine to start using a given snapshot.
57+
//
58+
// If using the UFFD memory backend, the memFilePath may be empty (it is
59+
// ignored), and instead the UFFD socket should be specified using
60+
// MemoryBackendType, as in the following example:
61+
//
62+
// WithSnapshot(
63+
// "", snapshotPath,
64+
// WithMemoryBackend(models.MemoryBackendBackendTypeUffd, "uffd.sock"))
5665
func WithSnapshot(memFilePath, snapshotPath string, opts ...WithSnapshotOpt) Opt {
5766
return func(m *Machine) {
5867
m.Cfg.Snapshot.MemFilePath = memFilePath
@@ -66,3 +75,18 @@ func WithSnapshot(memFilePath, snapshotPath string, opts ...WithSnapshotOpt) Opt
6675
m.Handlers.FcInit = loadSnapshotHandlerList
6776
}
6877
}
78+
79+
// WithMemoryBackend sets the memory backend to the given type, using the given
80+
// backing file path (a regular file for "File" type, or a UFFD socket path for
81+
// "Uffd" type).
82+
//
83+
// Note that if MemFilePath is already configured for the snapshot config, it
84+
// will be ignored, and the backendPath specified here will be used instead.
85+
func WithMemoryBackend(backendType, backendPath string) WithSnapshotOpt {
86+
return func(cfg *SnapshotConfig) {
87+
cfg.MemBackend = &models.MemoryBackend{
88+
BackendType: String(backendType),
89+
BackendPath: String(backendPath),
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)