Skip to content

Commit 74a847d

Browse files
committed
krunkit: support SSHOverVsock and replace SSH-based guestagent connection with vsock
Signed-off-by: Ansuman Sahoo <anshumansahoo500@gmail.com>
1 parent 4c791f1 commit 74a847d

2 files changed

Lines changed: 113 additions & 6 deletions

File tree

pkg/driver/krunkit/krunkit_darwin_arm64.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"strconv"
1515

1616
"github.com/docker/go-units"
17+
"github.com/inetaf/tcpproxy"
1718
"github.com/lima-vm/go-qcow2reader/image/raw"
1819
"github.com/sirupsen/logrus"
1920

@@ -47,6 +48,12 @@ func Cmdline(inst *limatype.Instance) (*exec.Cmd, error) {
4748
// First virtio-blk device is the boot disk
4849
"--device", fmt.Sprintf("virtio-blk,path=%s,format=raw", filepath.Join(inst.Dir, filenames.Disk)),
4950
"--device", fmt.Sprintf("virtio-blk,path=%s", filepath.Join(inst.Dir, filenames.CIDataISO)),
51+
"--device", fmt.Sprintf("virtio-vsock,port=%d,socketURL=%s,connect", vSockPort, filepath.Join(inst.Dir, filenames.GuestAgentSock)),
52+
}
53+
54+
if inst.Config.SSH.OverVsock != nil && *inst.Config.SSH.OverVsock {
55+
sshVsockPath := filepath.Join(inst.Dir, sshVsockSock)
56+
args = append(args, "--device", fmt.Sprintf("virtio-vsock,port=22,socketURL=%s,connect", sshVsockPath))
5057
}
5158

5259
// Add additional disks
@@ -205,3 +212,50 @@ func startUsernet(ctx context.Context, inst *limatype.Instance) (*usernet.Client
205212
subnetIP, _, err := net.ParseCIDR(networks.SlirpNetwork)
206213
return usernet.NewClient(endpointSock, subnetIP), cancel, err
207214
}
215+
216+
func startVsockForwarder(ctx context.Context, unixSockPath, hostAddress string) error {
217+
// Test if the vsock port is open
218+
conn, err := net.Dial("unix", unixSockPath)
219+
if err != nil {
220+
return err
221+
}
222+
conn.Close()
223+
224+
var lc net.ListenConfig
225+
l, err := lc.Listen(ctx, "tcp", hostAddress)
226+
if err != nil {
227+
return err
228+
}
229+
go func() {
230+
<-ctx.Done()
231+
l.Close()
232+
}()
233+
logrus.Infof("Started krunkit vsock forwarder: %s -> %s", hostAddress, unixSockPath)
234+
go func() {
235+
defer l.Close()
236+
for {
237+
conn, err := l.Accept()
238+
if err != nil {
239+
if errors.Is(err, net.ErrClosed) {
240+
return
241+
}
242+
logrus.WithError(err).Errorf("krunkit vsock forwarder accept error: %v", err)
243+
} else {
244+
p := tcpproxy.DialProxy{
245+
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
246+
var d net.Dialer
247+
return d.DialContext(ctx, "unix", unixSockPath)
248+
},
249+
}
250+
go p.HandleConn(conn)
251+
}
252+
select {
253+
case <-ctx.Done():
254+
return
255+
default:
256+
continue
257+
}
258+
}
259+
}()
260+
return nil
261+
}

pkg/driver/krunkit/krunkit_driver_darwin_arm64.go

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"os"
1313
"os/exec"
1414
"path/filepath"
15+
"strconv"
1516
"strings"
1617
"syscall"
1718
"time"
@@ -30,6 +31,11 @@ import (
3031
"github.com/lima-vm/lima/v2/pkg/ptr"
3132
)
3233

34+
const (
35+
vSockPort = 2222
36+
sshVsockSock = "ssh-vsock.sock"
37+
)
38+
3339
type LimaKrunkitDriver struct {
3440
Instance *limatype.Instance
3541
SSHLocalPort int
@@ -64,8 +70,8 @@ func (l *LimaKrunkitDriver) CreateDisk(ctx context.Context) error {
6470
}
6571

6672
func (l *LimaKrunkitDriver) Start(ctx context.Context) (chan error, error) {
67-
if l.Instance.Config.SSH.OverVsock != nil && *l.Instance.Config.SSH.OverVsock {
68-
logrus.Warn(".ssh.overVsock is not implemented yet for krunkit driver")
73+
if err := l.cleanupStaleSockets(); err != nil {
74+
logrus.WithError(err).Warn("Failed to clean up stale krunkit sockets before start")
6975
}
7076

7177
var err error
@@ -112,7 +118,27 @@ func (l *LimaKrunkitDriver) Start(ctx context.Context) (chan error, error) {
112118
l.krunkitWaitCh <- krunkitCmd.Wait()
113119
}()
114120

115-
err = l.usernetClient.ConfigureDriver(ctx, l.Instance, l.SSHLocalPort)
121+
usernetSSHLocalPort := l.SSHLocalPort
122+
useSSHOverVsock := l.Instance.Config.SSH.OverVsock != nil && *l.Instance.Config.SSH.OverVsock
123+
124+
if !useSSHOverVsock {
125+
logrus.Info("ssh.overVsock is false, using usernet forwarder for SSH")
126+
} else if err := l.usernetClient.WaitOpeningSSHPort(ctx, l.Instance); err == nil {
127+
hostAddress := net.JoinHostPort(l.Instance.SSHAddress, strconv.Itoa(usernetSSHLocalPort))
128+
sshVsockPath := filepath.Join(l.Instance.Dir, sshVsockSock)
129+
if err := startVsockForwarder(ctx, sshVsockPath, hostAddress); err == nil {
130+
logrus.Infof("Detected SSH server is listening on the vsock port; changed %s to proxy for the vsock port", hostAddress)
131+
usernetSSHLocalPort = 0 // disable gvisor ssh port forwarding
132+
} else {
133+
logrus.WithError(err).WithField("hostAddress", hostAddress).
134+
Debugf("Failed to start vsock forwarder (systemd is older than v256?)")
135+
logrus.Info("SSH server does not seem to be running on vsock port, using usernet forwarder")
136+
}
137+
} else {
138+
logrus.WithError(err).Warn("Failed to wait for the guest SSH server to become available, falling back to usernet forwarder")
139+
}
140+
141+
err = l.usernetClient.ConfigureDriver(ctx, l.Instance, usernetSSHLocalPort)
116142
if err != nil {
117143
l.krunkitWaitCh <- fmt.Errorf("failed to configure usernet: %w", err)
118144
}
@@ -216,6 +242,10 @@ func (l *LimaKrunkitDriver) FillConfig(_ context.Context, cfg *limatype.LimaYAML
216242

217243
cfg.VMType = ptr.Of(vmType)
218244

245+
if cfg.SSH.OverVsock == nil {
246+
cfg.SSH.OverVsock = ptr.Of(cfg.OS != nil && *cfg.OS == limatype.LINUX)
247+
}
248+
219249
return validateConfig(cfg)
220250
}
221251

@@ -260,6 +290,7 @@ func (l *LimaKrunkitDriver) Create(_ context.Context) error {
260290
func (l *LimaKrunkitDriver) Info() driver.Info {
261291
var info driver.Info
262292
info.Name = vmType
293+
info.VsockPort = vSockPort
263294
if l.Instance != nil && l.Instance.Dir != "" {
264295
info.InstanceDir = l.Instance.Dir
265296
}
@@ -277,7 +308,7 @@ func (l *LimaKrunkitDriver) SSHAddress(_ context.Context) (string, error) {
277308
}
278309

279310
func (l *LimaKrunkitDriver) ForwardGuestAgent() bool {
280-
return true
311+
return false
281312
}
282313

283314
func (l *LimaKrunkitDriver) Delete(_ context.Context) error {
@@ -324,10 +355,32 @@ func (l *LimaKrunkitDriver) Unregister(_ context.Context) error {
324355
return nil
325356
}
326357

327-
func (l *LimaKrunkitDriver) GuestAgentConn(_ context.Context) (net.Conn, string, error) {
328-
return nil, "unix", nil
358+
func (l *LimaKrunkitDriver) GuestAgentConn(ctx context.Context) (net.Conn, string, error) {
359+
var d net.Dialer
360+
conn, err := d.DialContext(ctx, "unix", filepath.Join(l.Instance.Dir, filenames.GuestAgentSock))
361+
return conn, "unix", err
329362
}
330363

331364
func (l *LimaKrunkitDriver) AdditionalSetupForSSH(_ context.Context) error {
332365
return nil
333366
}
367+
368+
// Currently, Krunkit does not clean-up the vsock unix socket when the VM stops
369+
// Issue: https://github.com/containers/krunkit/issues/101
370+
func (l *LimaKrunkitDriver) cleanupStaleSockets() error {
371+
if l.Instance == nil || l.Instance.Dir == "" {
372+
return nil
373+
}
374+
375+
var errs []error
376+
for _, sock := range []string{
377+
filepath.Join(l.Instance.Dir, filenames.GuestAgentSock),
378+
filepath.Join(l.Instance.Dir, sshVsockSock),
379+
} {
380+
if err := os.RemoveAll(sock); err != nil {
381+
errs = append(errs, fmt.Errorf("failed to remove socket %q: %w", sock, err))
382+
}
383+
}
384+
385+
return errors.Join(errs...)
386+
}

0 commit comments

Comments
 (0)