Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
lima-vm
GitHub Repository: lima-vm/lima
Path: blob/master/pkg/driver/krunkit/krunkit_darwin_arm64.go
2632 views
1
// SPDX-FileCopyrightText: Copyright The Lima Authors
2
// SPDX-License-Identifier: Apache-2.0
3
4
package krunkit
5
6
import (
7
"context"
8
"errors"
9
"fmt"
10
"net"
11
"os"
12
"os/exec"
13
"path/filepath"
14
"strconv"
15
16
"github.com/docker/go-units"
17
"github.com/lima-vm/go-qcow2reader/image/raw"
18
"github.com/sirupsen/logrus"
19
20
"github.com/lima-vm/lima/v2/pkg/driver/vz"
21
"github.com/lima-vm/lima/v2/pkg/imgutil/proxyimgutil"
22
"github.com/lima-vm/lima/v2/pkg/limatype"
23
"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
24
"github.com/lima-vm/lima/v2/pkg/limayaml"
25
"github.com/lima-vm/lima/v2/pkg/networks"
26
"github.com/lima-vm/lima/v2/pkg/networks/usernet"
27
"github.com/lima-vm/lima/v2/pkg/store"
28
)
29
30
const logLevelInfo = "3"
31
32
// Cmdline constructs the command line arguments for krunkit based on the instance configuration.
33
func Cmdline(inst *limatype.Instance) (*exec.Cmd, error) {
34
memBytes, err := units.RAMInBytes(*inst.Config.Memory)
35
if err != nil {
36
return nil, err
37
}
38
39
args := []string{
40
// Memory in MiB
41
"--memory", strconv.FormatInt(memBytes/units.MiB, 10),
42
"--cpus", fmt.Sprintf("%d", *inst.Config.CPUs),
43
"--device", fmt.Sprintf("virtio-serial,logFilePath=%s", filepath.Join(inst.Dir, filenames.SerialLog)),
44
"--krun-log-level", logLevelInfo,
45
"--restful-uri", "none://",
46
47
// First virtio-blk device is the boot disk
48
"--device", fmt.Sprintf("virtio-blk,path=%s,format=raw", filepath.Join(inst.Dir, filenames.DiffDisk)),
49
"--device", fmt.Sprintf("virtio-blk,path=%s", filepath.Join(inst.Dir, filenames.CIDataISO)),
50
}
51
52
// Add additional disks
53
if len(inst.Config.AdditionalDisks) > 0 {
54
ctx := context.Background()
55
diskUtil := proxyimgutil.NewDiskUtil(ctx)
56
for _, d := range inst.Config.AdditionalDisks {
57
disk, derr := store.InspectDisk(d.Name, d.FSType)
58
if derr != nil {
59
return nil, fmt.Errorf("failed to load disk %q: %w", d.Name, derr)
60
}
61
if disk.Instance != "" {
62
return nil, fmt.Errorf("failed to run attach disk %q, in use by instance %q", disk.Name, disk.Instance)
63
}
64
if lerr := disk.Lock(inst.Dir); lerr != nil {
65
return nil, fmt.Errorf("failed to lock disk %q: %w", d.Name, lerr)
66
}
67
extraDiskPath := filepath.Join(disk.Dir, filenames.DataDisk)
68
logrus.Infof("Mounting disk %q on %q", disk.Name, disk.MountPoint)
69
if cerr := diskUtil.Convert(ctx, raw.Type, extraDiskPath, extraDiskPath, nil, true); cerr != nil {
70
return nil, fmt.Errorf("failed to convert extra disk %q to raw: %w", extraDiskPath, cerr)
71
}
72
args = append(args, "--device", fmt.Sprintf("virtio-blk,path=%s,format=raw", extraDiskPath))
73
}
74
}
75
76
// Network commands
77
networkArgs, err := buildNetworkArgs(inst)
78
if err != nil {
79
return nil, fmt.Errorf("failed to build network arguments: %w", err)
80
}
81
82
// File sharing commands
83
if *inst.Config.MountType == limatype.VIRTIOFS {
84
for _, mount := range inst.Config.Mounts {
85
if _, err := os.Stat(mount.Location); errors.Is(err, os.ErrNotExist) {
86
if err := os.MkdirAll(mount.Location, 0o750); err != nil {
87
return nil, err
88
}
89
}
90
tag := limayaml.MountTag(mount.Location, *mount.MountPoint)
91
mountArg := fmt.Sprintf("virtio-fs,sharedDir=%s,mountTag=%s", mount.Location, tag)
92
args = append(args, "--device", mountArg)
93
}
94
}
95
96
args = append(args, networkArgs...)
97
cmd := exec.CommandContext(context.Background(), vmType, args...)
98
99
return cmd, nil
100
}
101
102
func buildNetworkArgs(inst *limatype.Instance) ([]string, error) {
103
var args []string
104
105
// Configure default usernetwork with limayaml.MACAddress(inst.Dir) for eth0 interface
106
firstUsernetIndex := limayaml.FirstUsernetIndex(inst.Config)
107
if firstUsernetIndex == -1 {
108
// slirp network using gvisor netstack
109
krunkitSock, err := usernet.SockWithDirectory(inst.Dir, "", usernet.FDSock)
110
if err != nil {
111
return nil, err
112
}
113
client, err := vz.PassFDToUnix(krunkitSock)
114
if err != nil {
115
return nil, err
116
}
117
118
args = append(args, "--device", fmt.Sprintf("virtio-net,type=unixgram,fd=%d,mac=%s", client.Fd(), limayaml.MACAddress(inst.Dir)))
119
}
120
121
for _, nw := range inst.Networks {
122
var sock string
123
var mac string
124
if nw.Lima != "" {
125
nwCfg, err := networks.LoadConfig()
126
if err != nil {
127
return nil, err
128
}
129
switch nw.Lima {
130
case networks.ModeUserV2:
131
sock, err = usernet.Sock(nw.Lima, usernet.QEMUSock)
132
if err != nil {
133
return nil, err
134
}
135
mac = limayaml.MACAddress(inst.Dir)
136
case networks.ModeShared, networks.ModeBridged:
137
socketVMNetInstalled, err := nwCfg.IsDaemonInstalled(networks.SocketVMNet)
138
if err != nil {
139
return nil, err
140
}
141
if !socketVMNetInstalled {
142
return nil, errors.New("socket_vmnet is not installed")
143
}
144
sock, err = networks.Sock(nw.Lima)
145
if err != nil {
146
return nil, err
147
}
148
mac = nw.MACAddress
149
default:
150
return nil, fmt.Errorf("invalid network spec %+v", nw)
151
}
152
} else if nw.Socket != "" {
153
sock = nw.Socket
154
mac = nw.MACAddress
155
} else {
156
return nil, fmt.Errorf("invalid network spec %+v", nw)
157
}
158
159
device := fmt.Sprintf("virtio-net,type=unixstream,path=%s,mac=%s", sock, mac)
160
args = append(args, "--device", device)
161
}
162
163
if len(args) == 0 {
164
return args, errors.New("no socket_vmnet networks defined")
165
}
166
167
return args, nil
168
}
169
170
func startUsernet(ctx context.Context, inst *limatype.Instance) (*usernet.Client, context.CancelFunc, error) {
171
if firstUsernetIndex := limayaml.FirstUsernetIndex(inst.Config); firstUsernetIndex != -1 {
172
return usernet.NewClientByName(inst.Config.Networks[firstUsernetIndex].Lima), nil, nil
173
}
174
// Start a in-process gvisor-tap-vsock
175
endpointSock, err := usernet.SockWithDirectory(inst.Dir, "", usernet.EndpointSock)
176
if err != nil {
177
return nil, nil, err
178
}
179
krunkitSock, err := usernet.SockWithDirectory(inst.Dir, "", usernet.FDSock)
180
if err != nil {
181
return nil, nil, err
182
}
183
os.RemoveAll(endpointSock)
184
os.RemoveAll(krunkitSock)
185
ctx, cancel := context.WithCancel(ctx)
186
err = usernet.StartGVisorNetstack(ctx, &usernet.GVisorNetstackOpts{
187
MTU: 1500,
188
Endpoint: endpointSock,
189
FdSocket: krunkitSock,
190
Async: true,
191
DefaultLeases: map[string]string{
192
networks.SlirpIPAddress: limayaml.MACAddress(inst.Dir),
193
},
194
Subnet: networks.SlirpNetwork,
195
})
196
if err != nil {
197
defer cancel()
198
return nil, nil, err
199
}
200
subnetIP, _, err := net.ParseCIDR(networks.SlirpNetwork)
201
return usernet.NewClient(endpointSock, subnetIP), cancel, err
202
}
203
204