Skip to content

Commit 9d284a6

Browse files
committed
support for libkrun using krunkit
Signed-off-by: Ansuman Sahoo <anshumansahoo500@gmail.com>
1 parent 9d5f469 commit 9d284a6

File tree

4 files changed

+477
-0
lines changed

4 files changed

+477
-0
lines changed

cmd/lima-driver-krunkit/main.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// SPDX-FileCopyrightText: Copyright The Lima Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package main
5+
6+
import (
7+
"context"
8+
9+
"github.com/lima-vm/lima/v2/pkg/driver/external/server"
10+
"github.com/lima-vm/lima/v2/pkg/driver/krunkit"
11+
)
12+
13+
// To be used as an external driver for Lima.
14+
func main() {
15+
server.Serve(context.Background(), krunkit.New())
16+
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
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/lima/v2/pkg/driver/vz"
18+
"github.com/lima-vm/lima/v2/pkg/imgutil/proxyimgutil"
19+
"github.com/lima-vm/lima/v2/pkg/iso9660util"
20+
"github.com/lima-vm/lima/v2/pkg/limatype"
21+
"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
22+
"github.com/lima-vm/lima/v2/pkg/limayaml"
23+
"github.com/lima-vm/lima/v2/pkg/networks"
24+
"github.com/lima-vm/lima/v2/pkg/networks/usernet"
25+
"github.com/sirupsen/logrus"
26+
)
27+
28+
const logLevelInfo = "3"
29+
30+
// Cmdline constructs the command line arguments for krunkit based on the instance configuration.
31+
func Cmdline(inst *limatype.Instance) (*exec.Cmd, error) {
32+
var args = []string{
33+
"--memory", strconv.Itoa(2048),
34+
"--cpus", fmt.Sprintf("%d", *inst.Config.CPUs),
35+
"--device", fmt.Sprintf("virtio-serial,logFilePath=%s", filepath.Join(inst.Dir, filenames.SerialLog)),
36+
"--krun-log-level", logLevelInfo,
37+
"--restful-uri", "none://",
38+
39+
// First virtio-blk device is the boot disk
40+
"--device", fmt.Sprintf("virtio-blk,path=%s,format=raw", filepath.Join(inst.Dir, filenames.DiffDisk)),
41+
"--device", fmt.Sprintf("virtio-blk,path=%s", filepath.Join(inst.Dir, filenames.CIDataISO)),
42+
}
43+
44+
networkArgs, err := buildNetworkArgs(inst)
45+
if err != nil {
46+
return nil, fmt.Errorf("failed to build network arguments: %w", err)
47+
}
48+
49+
if *inst.Config.MountType == limatype.VIRTIOFS {
50+
for i, mount := range inst.Config.Mounts {
51+
logrus.Infof("Mount: %+v", mount)
52+
if _, err := os.Stat(mount.Location); errors.Is(err, os.ErrNotExist) {
53+
if err := os.MkdirAll(mount.Location, 0o750); err != nil {
54+
return nil, err
55+
}
56+
}
57+
tag := fmt.Sprintf("mount%d", i)
58+
mountArg := fmt.Sprintf("virtio-fs,sharedDir=%s,mountTag=%s", mount.Location, tag)
59+
args = append(args, "--device", mountArg)
60+
}
61+
}
62+
63+
args = append(args, networkArgs...)
64+
cmd := exec.CommandContext(context.Background(), "krunkit", args...)
65+
66+
return cmd, nil
67+
}
68+
69+
func buildNetworkArgs(inst *limatype.Instance) ([]string, error) {
70+
var args []string
71+
72+
// Configure default usernetwork with limayaml.MACAddress(inst.Dir) for eth0 interface
73+
firstUsernetIndex := limayaml.FirstUsernetIndex(inst.Config)
74+
if firstUsernetIndex == -1 {
75+
// slirp network using gvisor netstack
76+
krunkitSock, err := usernet.SockWithDirectory(inst.Dir, "", usernet.FDSock)
77+
if err != nil {
78+
return nil, err
79+
}
80+
client, err := vz.PassFDToUnix(krunkitSock)
81+
if err != nil {
82+
return nil, err
83+
}
84+
85+
args = append(args, "--device", fmt.Sprintf("virtio-net,type=unixgram,fd=%d,mac=%s", client.Fd(), limayaml.MACAddress(inst.Dir)))
86+
}
87+
88+
for _, nw := range inst.Networks {
89+
var sock string
90+
var mac string
91+
if nw.Lima != "" {
92+
nwCfg, err := networks.LoadConfig()
93+
if err != nil {
94+
return nil, err
95+
}
96+
switch nw.Lima {
97+
case networks.ModeUserV2:
98+
sock, err = usernet.Sock(nw.Lima, usernet.QEMUSock)
99+
if err != nil {
100+
return nil, err
101+
}
102+
mac = limayaml.MACAddress(inst.Dir)
103+
case networks.ModeShared, networks.ModeBridged:
104+
socketVMNetInstalled, err := nwCfg.IsDaemonInstalled(networks.SocketVMNet)
105+
if err != nil {
106+
return nil, err
107+
}
108+
if !socketVMNetInstalled {
109+
return nil, errors.New("socket_vmnet is not installed")
110+
}
111+
sock, err = networks.Sock(nw.Lima)
112+
if err != nil {
113+
return nil, err
114+
}
115+
mac = nw.MACAddress
116+
default:
117+
return nil, fmt.Errorf("invalid network spec %+v", nw)
118+
}
119+
} else if nw.Socket != "" {
120+
sock = nw.Socket
121+
mac = nw.MACAddress
122+
} else {
123+
return nil, fmt.Errorf("invalid network spec %+v", nw)
124+
}
125+
126+
device := fmt.Sprintf("virtio-net,type=unixstream,path=%s,mac=%s", sock, mac)
127+
args = append(args, "--device", device)
128+
}
129+
130+
if len(args) == 0 {
131+
return args, fmt.Errorf("no socket_vment networks defined")
132+
}
133+
134+
return args, nil
135+
}
136+
137+
func EnsureDisk(ctx context.Context, inst *limatype.Instance) error {
138+
diffDisk := filepath.Join(inst.Dir, filenames.DiffDisk)
139+
if _, err := os.Stat(diffDisk); err == nil || !errors.Is(err, os.ErrNotExist) {
140+
// disk is already ensured
141+
return err
142+
}
143+
144+
diskUtil := proxyimgutil.NewDiskUtil(ctx)
145+
146+
baseDisk := filepath.Join(inst.Dir, filenames.BaseDisk)
147+
148+
diskSize, _ := units.RAMInBytes(*inst.Config.Disk)
149+
if diskSize == 0 {
150+
return nil
151+
}
152+
isBaseDiskISO, err := iso9660util.IsISO9660(baseDisk)
153+
if err != nil {
154+
return err
155+
}
156+
if isBaseDiskISO {
157+
// Create an empty data volume (sparse)
158+
diffDiskF, err := os.Create(diffDisk)
159+
if err != nil {
160+
return err
161+
}
162+
163+
err = diskUtil.MakeSparse(ctx, diffDiskF, 0)
164+
if err != nil {
165+
diffDiskF.Close()
166+
return fmt.Errorf("failed to create sparse diff disk %q: %w", diffDisk, err)
167+
}
168+
return diffDiskF.Close()
169+
}
170+
171+
// Krunkit also supports qcow2 disks but raw is faster to create and use.
172+
if err = diskUtil.ConvertToRaw(ctx, baseDisk, diffDisk, &diskSize, false); err != nil {
173+
return fmt.Errorf("failed to convert %q to a raw disk %q: %w", baseDisk, diffDisk, err)
174+
}
175+
return err
176+
}
177+
178+
func startUsernet(ctx context.Context, inst *limatype.Instance) (*usernet.Client, context.CancelFunc, error) {
179+
if firstUsernetIndex := limayaml.FirstUsernetIndex(inst.Config); firstUsernetIndex != -1 {
180+
return usernet.NewClientByName(inst.Config.Networks[firstUsernetIndex].Lima), nil, nil
181+
}
182+
// Start a in-process gvisor-tap-vsock
183+
endpointSock, err := usernet.SockWithDirectory(inst.Dir, "", usernet.EndpointSock)
184+
if err != nil {
185+
return nil, nil, err
186+
}
187+
krunkitSock, err := usernet.SockWithDirectory(inst.Dir, "", usernet.FDSock)
188+
if err != nil {
189+
return nil, nil, err
190+
}
191+
os.RemoveAll(endpointSock)
192+
os.RemoveAll(krunkitSock)
193+
ctx, cancel := context.WithCancel(ctx)
194+
err = usernet.StartGVisorNetstack(ctx, &usernet.GVisorNetstackOpts{
195+
MTU: 1500,
196+
Endpoint: endpointSock,
197+
FdSocket: krunkitSock,
198+
Async: true,
199+
DefaultLeases: map[string]string{
200+
networks.SlirpIPAddress: limayaml.MACAddress(inst.Dir),
201+
},
202+
Subnet: networks.SlirpNetwork,
203+
})
204+
if err != nil {
205+
defer cancel()
206+
return nil, nil, err
207+
}
208+
subnetIP, _, err := net.ParseCIDR(networks.SlirpNetwork)
209+
return usernet.NewClient(endpointSock, subnetIP), cancel, err
210+
}

0 commit comments

Comments
 (0)