Skip to content

Commit 0e0ec94

Browse files
authored
Merge pull request #2006 from afbjorklund/guestagent-unix
Restore guest agent unix socket functionality
2 parents 04e3886 + ab5ebb9 commit 0e0ec94

File tree

9 files changed

+91
-18
lines changed

9 files changed

+91
-18
lines changed

cmd/lima-guestagent/daemon_linux.go

+22-8
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"github.com/lima-vm/lima/pkg/guestagent"
1212
"github.com/lima-vm/lima/pkg/guestagent/api/server"
1313
"github.com/lima-vm/lima/pkg/guestagent/serialport"
14-
"github.com/lima-vm/lima/pkg/store/filenames"
1514
"github.com/mdlayher/vsock"
1615
"github.com/sirupsen/logrus"
1716
"github.com/spf13/cobra"
@@ -25,21 +24,23 @@ func newDaemonCommand() *cobra.Command {
2524
}
2625
daemonCommand.Flags().Duration("tick", 3*time.Second, "tick for polling events")
2726
daemonCommand.Flags().Int("vsock-port", 0, "use vsock server instead a UNIX socket")
27+
daemonCommand.Flags().String("virtio-port", "", "use virtio server instead a UNIX socket")
2828
return daemonCommand
2929
}
3030

3131
func daemonAction(cmd *cobra.Command, _ []string) error {
32+
socket := "/run/lima-guestagent.sock"
3233
tick, err := cmd.Flags().GetDuration("tick")
3334
if err != nil {
3435
return err
3536
}
36-
vSockPortOverride, err := cmd.Flags().GetInt("vsock-port")
37+
vSockPort, err := cmd.Flags().GetInt("vsock-port")
3738
if err != nil {
3839
return err
3940
}
40-
vSockPort := 0
41-
if vSockPortOverride != 0 {
42-
vSockPort = vSockPortOverride
41+
virtioPort, err := cmd.Flags().GetString("virtio-port")
42+
if err != nil {
43+
return err
4344
}
4445
if tick == 0 {
4546
return errors.New("tick must be specified")
@@ -67,11 +68,14 @@ func daemonAction(cmd *cobra.Command, _ []string) error {
6768
r := mux.NewRouter()
6869
server.AddRoutes(r, backend)
6970
srv := &http.Server{Handler: r}
71+
err = os.RemoveAll(socket)
72+
if err != nil {
73+
return err
74+
}
7075

7176
var l net.Listener
72-
virtioPort := "/dev/virtio-ports/" + filenames.VirtioPort
73-
if _, err := os.Stat(virtioPort); err == nil {
74-
qemuL, err := serialport.Listen(virtioPort)
77+
if virtioPort != "" {
78+
qemuL, err := serialport.Listen("/dev/virtio-ports/" + virtioPort)
7579
if err != nil {
7680
return err
7781
}
@@ -84,6 +88,16 @@ func daemonAction(cmd *cobra.Command, _ []string) error {
8488
}
8589
l = vsockL
8690
logrus.Infof("serving the guest agent on vsock port: %d", vSockPort)
91+
} else {
92+
socketL, err := net.Listen("unix", socket)
93+
if err != nil {
94+
return err
95+
}
96+
if err := os.Chmod(socket, 0o777); err != nil {
97+
return err
98+
}
99+
l = socketL
100+
logrus.Infof("serving the guest agent on %q", socket)
87101
}
88102
return srv.Serve(l)
89103
}

cmd/lima-guestagent/install_systemd_linux.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ func newInstallSystemdCommand() *cobra.Command {
2121
RunE: installSystemdAction,
2222
}
2323
installSystemdCommand.Flags().Int("vsock-port", 0, "use vsock server on specified port")
24+
installSystemdCommand.Flags().String("virtio-port", "", "use virtio server instead a UNIX socket")
2425
return installSystemdCommand
2526
}
2627

@@ -29,7 +30,11 @@ func installSystemdAction(cmd *cobra.Command, _ []string) error {
2930
if err != nil {
3031
return err
3132
}
32-
unit, err := generateSystemdUnit(vsockPort)
33+
virtioPort, err := cmd.Flags().GetString("virtio-port")
34+
if err != nil {
35+
return err
36+
}
37+
unit, err := generateSystemdUnit(vsockPort, virtioPort)
3338
if err != nil {
3439
return err
3540
}
@@ -67,7 +72,7 @@ func installSystemdAction(cmd *cobra.Command, _ []string) error {
6772
//go:embed lima-guestagent.TEMPLATE.service
6873
var systemdUnitTemplate string
6974

70-
func generateSystemdUnit(vsockPort int) ([]byte, error) {
75+
func generateSystemdUnit(vsockPort int, virtioPort string) ([]byte, error) {
7176
selfExeAbs, err := os.Executable()
7277
if err != nil {
7378
return nil, err
@@ -77,6 +82,9 @@ func generateSystemdUnit(vsockPort int) ([]byte, error) {
7782
if vsockPort != 0 {
7883
args = append(args, fmt.Sprintf("--vsock-port %d", vsockPort))
7984
}
85+
if virtioPort != "" {
86+
args = append(args, fmt.Sprintf("--virtio-port %s", virtioPort))
87+
}
8088

8189
m := map[string]string{
8290
"Binary": selfExeAbs,

pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh

+8-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ name="lima-guestagent"
3535
description="Forward ports to the lima-hostagent"
3636
3737
command=${LIMA_CIDATA_GUEST_INSTALL_PREFIX}/bin/lima-guestagent
38-
command_args="daemon --vsock-port "${LIMA_CIDATA_VSOCK_PORT}""
38+
command_args="daemon --vsock-port "${LIMA_CIDATA_VSOCK_PORT}" --virtio-port "${LIMA_CIDATA_VIRTIO_PORT}""
3939
command_background=true
4040
pidfile="/run/lima-guestagent.pid"
4141
EOF
@@ -47,5 +47,11 @@ else
4747
# Remove legacy systemd service
4848
rm -f "${LIMA_CIDATA_HOME}/.config/systemd/user/lima-guestagent.service"
4949

50-
sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd --vsock-port "${LIMA_CIDATA_VSOCK_PORT}"
50+
if [ "${LIMA_CIDATA_VSOCK_PORT}" != "0" ]; then
51+
sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd --vsock-port "${LIMA_CIDATA_VSOCK_PORT}"
52+
elif [ "${LIMA_CIDATA_VIRTIO_PORT}" != "" ]; then
53+
sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd --virtio-port "${LIMA_CIDATA_VIRTIO_PORT}"
54+
else
55+
sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd
56+
fi
5157
fi

pkg/cidata/cidata.TEMPLATE.d/lima.env

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ LIMA_CIDATA_SKIP_DEFAULT_DEPENDENCY_RESOLUTION=
4141
{{- end}}
4242
LIMA_CIDATA_VMTYPE={{ .VMType }}
4343
LIMA_CIDATA_VSOCK_PORT={{ .VSockPort }}
44+
LIMA_CIDATA_VIRTIO_PORT={{ .VirtioPort}}
4445
{{- if .Plain}}
4546
LIMA_CIDATA_PLAIN=1
4647
{{- else}}

pkg/cidata/cidata.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func setupEnv(y *limayaml.LimaYAML, args TemplateArgs) (map[string]string, error
110110
return env, nil
111111
}
112112

113-
func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort, tcpDNSLocalPort int, nerdctlArchive string, vsockPort int) error {
113+
func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort, tcpDNSLocalPort int, nerdctlArchive string, vsockPort int, virtioPort string) error {
114114
if err := limayaml.Validate(*y, false); err != nil {
115115
return err
116116
}
@@ -135,6 +135,7 @@ func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort
135135
RosettaBinFmt: *y.Rosetta.BinFmt,
136136
VMType: *y.VMType,
137137
VSockPort: vsockPort,
138+
VirtioPort: virtioPort,
138139
Plain: *y.Plain,
139140
}
140141

pkg/cidata/template.go

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ type TemplateArgs struct {
8181
SkipDefaultDependencyResolution bool
8282
VMType string
8383
VSockPort int
84+
VirtioPort string
8485
Plain bool
8586
}
8687

pkg/driver/driver.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ type Driver interface {
6464

6565
ListSnapshots(_ context.Context) (string, error)
6666

67+
// ForwardGuestAgent returns if the guest agent sock needs forwarding by host agent.
68+
ForwardGuestAgent() bool
69+
70+
// GuestAgentConn returns the guest agent connection, or nil (if forwarded by ssh).
6771
GuestAgentConn(_ context.Context) (net.Conn, error)
6872
}
6973

@@ -73,6 +77,7 @@ type BaseDriver struct {
7377

7478
SSHLocalPort int
7579
VSockPort int
80+
VirtioPort string
7681
}
7782

7883
var _ Driver = (*BaseDriver)(nil)
@@ -137,6 +142,12 @@ func (d *BaseDriver) ListSnapshots(_ context.Context) (string, error) {
137142
return "", fmt.Errorf("unimplemented")
138143
}
139144

145+
func (d *BaseDriver) ForwardGuestAgent() bool {
146+
// if driver is not providing, use host agent
147+
return d.VSockPort == 0 && d.VirtioPort == ""
148+
}
149+
140150
func (d *BaseDriver) GuestAgentConn(_ context.Context) (net.Conn, error) {
141-
return nil, fmt.Errorf("unimplemented")
151+
// use the unix socket forwarded by host agent
152+
return nil, nil
142153
}

pkg/hostagent/hostagent.go

+32-3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ type HostAgent struct {
5353
eventEnc *json.Encoder
5454
eventEncMu sync.Mutex
5555

56-
vSockPort int
56+
vSockPort int
57+
virtioPort string
5758

5859
clientMu sync.RWMutex
5960
client guestagentclient.GuestAgentClient
@@ -117,6 +118,7 @@ func New(instName string, stdout io.Writer, sigintCh chan os.Signal, opts ...Opt
117118
}
118119

119120
vSockPort := 0
121+
virtioPort := ""
120122
if *y.VMType == limayaml.VZ {
121123
vSockPort = 2222
122124
} else if *y.VMType == limayaml.WSL2 {
@@ -125,9 +127,11 @@ func New(instName string, stdout io.Writer, sigintCh chan os.Signal, opts ...Opt
125127
logrus.WithError(err).Error("failed to get free VSock port")
126128
}
127129
vSockPort = port
130+
} else if *y.VMType == limayaml.QEMU {
131+
virtioPort = filenames.VirtioPort
128132
}
129133

130-
if err := cidata.GenerateISO9660(inst.Dir, instName, y, udpDNSLocalPort, tcpDNSLocalPort, o.nerdctlArchive, vSockPort); err != nil {
134+
if err := cidata.GenerateISO9660(inst.Dir, instName, y, udpDNSLocalPort, tcpDNSLocalPort, o.nerdctlArchive, vSockPort, virtioPort); err != nil {
131135
return nil, err
132136
}
133137

@@ -160,6 +164,7 @@ func New(instName string, stdout io.Writer, sigintCh chan os.Signal, opts ...Opt
160164
Yaml: y,
161165
SSHLocalPort: sshLocalPort,
162166
VSockPort: vSockPort,
167+
VirtioPort: virtioPort,
163168
})
164169

165170
a := &HostAgent{
@@ -176,6 +181,7 @@ func New(instName string, stdout io.Writer, sigintCh chan os.Signal, opts ...Opt
176181
sigintCh: sigintCh,
177182
eventEnc: json.NewEncoder(stdout),
178183
vSockPort: vSockPort,
184+
virtioPort: virtioPort,
179185
guestAgentAliveCh: make(chan struct{}),
180186
}
181187
return a, nil
@@ -561,6 +567,9 @@ func (a *HostAgent) watchGuestAgentEvents(ctx context.Context) {
561567
}
562568
}
563569

570+
localUnix := filepath.Join(a.instDir, filenames.GuestAgentSock)
571+
remoteUnix := "/run/lima-guestagent.sock"
572+
564573
a.onClose = append(a.onClose, func() error {
565574
logrus.Debugf("Stop forwarding unix sockets")
566575
var errs []error
@@ -573,9 +582,19 @@ func (a *HostAgent) watchGuestAgentEvents(ctx context.Context) {
573582
}
574583
}
575584
}
585+
if a.driver.ForwardGuestAgent() {
586+
if err := forwardSSH(context.Background(), a.sshConfig, a.sshLocalPort, localUnix, remoteUnix, verbCancel, false); err != nil {
587+
errs = append(errs, err)
588+
}
589+
}
576590
return errors.Join(errs...)
577591
})
578592
for {
593+
if a.client == nil || !isGuestAgentSocketAccessible(ctx, a.client) {
594+
if a.driver.ForwardGuestAgent() {
595+
_ = forwardSSH(ctx, a.sshConfig, a.sshLocalPort, localUnix, remoteUnix, verbForward, false)
596+
}
597+
}
579598
client, err := a.getOrCreateClient(ctx)
580599
if err == nil {
581600
if err := a.processGuestAgentEvents(ctx, client); err != nil {
@@ -610,8 +629,18 @@ func (a *HostAgent) getOrCreateClient(ctx context.Context) (guestagentclient.Gue
610629
return a.client, err
611630
}
612631

613-
func (a *HostAgent) createClient(ctx context.Context) (guestagentclient.GuestAgentClient, error) {
632+
func (a *HostAgent) createConnection(ctx context.Context) (net.Conn, error) {
614633
conn, err := a.driver.GuestAgentConn(ctx)
634+
// default to forwarded sock
635+
if conn == nil && err == nil {
636+
var d net.Dialer
637+
conn, err = d.DialContext(ctx, "unix", filepath.Join(a.instDir, filenames.GuestAgentSock))
638+
}
639+
return conn, err
640+
}
641+
642+
func (a *HostAgent) createClient(ctx context.Context) (guestagentclient.GuestAgentClient, error) {
643+
conn, err := a.createConnection(ctx)
615644
if err != nil {
616645
return nil, err
617646
}

website/content/en/docs/dev/Internals/_index.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,12 @@ VNC:
7373

7474
Guest agent:
7575

76-
Each drivers use their own mode of communication
76+
Each drivers use their own mode of communication
7777
- `qemu`: uses virtio-port `io.lima-vm.guest_agent.0`
7878
- `vz`: uses vsock port 2222
7979
- `wsl2`: uses free random vsock port
80+
The fallback is to use port forward over ssh port
81+
- `ga.sock`: Forwarded to `/run/lima-guestagent.sock` in the guest, via SSH
8082

8183
Host agent:
8284
- `ha.pid`: hostagent PID

0 commit comments

Comments
 (0)