Skip to content

Commit feeee6c

Browse files
committed
pkg/hostagent: Add the _LIMA_DIRECT_IP_PORT_FORWARDER environment variable to enable direct IP port forwarding to the VM.
### Direct IP Port Forwarding To enable direct IP port forwarding, set the `_LIMA_DIRECT_IP_PORT_FORWARDER` environment variable to `true`: ```bash export _LIMA_DIRECT_IP_PORT_FORWARDER=true ``` This feature makes Lima to use direct IP port forwarding instead of gRPC port forwarding. When this feature is enabled, Lima tries to connect to the guest's IP address directly for port forwarding. #### Fallback to gRPC Port Forwarding Lima may fall back to gRPC port forwarding in the following cases: - If the guest's IP address is not available, Lima falls back to gRPC port forwarding. - If the guest's IP address is available but the connection to the guest's IP address fails, Lima also falls back to gRPC port forwarding. - If the guest's IP address is not accessible from the host (e.g. localhost on guest), Lima falls back to gRPC port forwarding as well. Signed-off-by: Norio Nomura <norio.nomura@gmail.com>
1 parent d8002b7 commit feeee6c

File tree

5 files changed

+78
-25
lines changed

5 files changed

+78
-25
lines changed

.github/workflows/test.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,11 @@ jobs:
519519
create_arg:
520520
- ""
521521
- "--network=vzNAT"
522+
include:
523+
- template: default.yaml
524+
create_arg: "--network=vzNAT"
525+
additional_env: |
526+
_LIMA_DIRECT_IP_PORT_FORWARDER=true
522527
steps:
523528
- name: "Adjust LIMACTL_CREATE_ARGS"
524529
# --cpus=1 is needed for running vz on GHA: https://github.com/lima-vm/lima/pull/1511#issuecomment-1574937888
@@ -539,6 +544,9 @@ jobs:
539544
run: brew install bash coreutils w3m socat
540545
- name: Uninstall qemu
541546
run: brew uninstall --ignore-dependencies --force qemu
547+
- name: Set additional environment variables
548+
if: matrix.additional_env != null
549+
run: echo "${{ matrix.additional_env }}" >>$GITHUB_ENV
542550
- name: Test
543551
run: ./hack/test-templates.sh templates/${{ matrix.template }}
544552
- if: failure()

pkg/hostagent/hostagent.go

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -898,37 +898,52 @@ func (a *HostAgent) processGuestAgentEvents(ctx context.Context, client *guestag
898898
if useSSHFwd {
899899
a.portForwarder.OnEvent(ctx, ev)
900900
} else {
901-
dialContext := func(ctx context.Context, network, guestAddress string) (net.Conn, error) {
902-
guestIPv4, guestIPv6 := a.GuestIPs()
903-
if guestIPv4 == nil && guestIPv6 == nil {
904-
return portfwd.DialContextToGRPCTunnel(client)(ctx, network, guestAddress)
901+
useDirectIPPortForwarding := false
902+
if envVar := os.Getenv("_LIMA_DIRECT_IP_PORT_FORWARDER"); envVar != "" {
903+
b, err := strconv.ParseBool(envVar)
904+
if err != nil {
905+
logrus.WithError(err).Warnf("invalid _LIMA_DIRECT_IP_PORT_FORWARDER value %q", envVar)
906+
} else {
907+
useDirectIPPortForwarding = b
905908
}
906-
// Check if the host part of guestAddress is either unspecified address or matches the known guest IP.
907-
// If so, replace it with the known guest IP to avoid issues with dual-stack setups and DNS resolution.
908-
// Otherwise, fall back to the gRPC tunnel.
909-
if host, _, err := net.SplitHostPort(guestAddress); err != nil {
910-
return nil, err
911-
} else if ip := net.ParseIP(host); ip.IsUnspecified() || ip.Equal(guestIPv4) || ip.Equal(guestIPv6) {
912-
if ip.To4() != nil {
913-
if guestIPv4 != nil {
914-
conn, err := DialContextToGuestIP(guestIPv4)(ctx, network, guestAddress)
915-
if err == nil {
916-
return conn, nil
909+
}
910+
var dialContext func(ctx context.Context, network string, guestAddress string) (net.Conn, error)
911+
if useDirectIPPortForwarding {
912+
logrus.Warn("Direct IP Port forwarding is enabled. It may fall back to GRPC Port Forwarding in some cases.")
913+
dialContext = func(ctx context.Context, network, guestAddress string) (net.Conn, error) {
914+
guestIPv4, guestIPv6 := a.GuestIPs()
915+
if guestIPv4 == nil && guestIPv6 == nil {
916+
return portfwd.DialContextToGRPCTunnel(client)(ctx, network, guestAddress)
917+
}
918+
// Check if the host part of guestAddress is either unspecified address or matches the known guest IP.
919+
// If so, replace it with the known guest IP to avoid issues with dual-stack setups and DNS resolution.
920+
// Otherwise, fall back to the gRPC tunnel.
921+
if host, _, err := net.SplitHostPort(guestAddress); err != nil {
922+
return nil, err
923+
} else if ip := net.ParseIP(host); ip.IsUnspecified() || ip.Equal(guestIPv4) || ip.Equal(guestIPv6) {
924+
if ip.To4() != nil {
925+
if guestIPv4 != nil {
926+
conn, err := DialContextToGuestIP(guestIPv4)(ctx, network, guestAddress)
927+
if err == nil {
928+
return conn, nil
929+
}
930+
logrus.WithError(err).Warn("failed to connect to the guest IPv4 directly, falling back to gRPC tunnel")
917931
}
918-
logrus.WithError(err).Warn("failed to connect to the guest IPv4 directly, falling back to gRPC tunnel")
919-
}
920-
} else if ip.To16() != nil {
921-
if guestIPv6 != nil {
922-
conn, err := DialContextToGuestIP(guestIPv6)(ctx, network, guestAddress)
923-
if err == nil {
924-
return conn, nil
932+
} else if ip.To16() != nil {
933+
if guestIPv6 != nil {
934+
conn, err := DialContextToGuestIP(guestIPv6)(ctx, network, guestAddress)
935+
if err == nil {
936+
return conn, nil
937+
}
938+
logrus.WithError(err).Warn("failed to connect to the guest IPv6 directly, falling back to gRPC tunnel")
925939
}
926-
logrus.WithError(err).Warn("failed to connect to the guest IPv6 directly, falling back to gRPC tunnel")
927940
}
941+
// If we reach here, it means we couldn't find a suitable guest IP
928942
}
929-
// If we reach here, it means we couldn't find a suitable guest IP
943+
return portfwd.DialContextToGRPCTunnel(client)(ctx, network, guestAddress)
930944
}
931-
return portfwd.DialContextToGRPCTunnel(client)(ctx, network, guestAddress)
945+
} else {
946+
dialContext = portfwd.DialContextToGRPCTunnel(client)
932947
}
933948
a.grpcPortForwarder.OnEvent(ctx, dialContext, ev)
934949
}

pkg/hostagent/requirements.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ If any private key under ~/.ssh is protected with a passphrase, you need to have
161161
noMaster: true,
162162
},
163163
)
164+
164165
if runtime.GOOS == "darwin" {
165166
// Limit the Guest IP address detection only to macOS for now.
166167
req = append(req,

website/content/en/docs/config/environment-variables.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,19 @@ This page documents the environment variables used in Lima.
140140
export LIMA_USERNET_RESOLVE_IP_ADDRESS_TIMEOUT=5
141141
```
142142

143+
### `_LIMA_DIRECT_IP_PORT_FORWARDER`
144+
145+
- **Description**: Specifies to use direct IP port forwarding instead of gRPC.
146+
- **Default**: `false`
147+
- **Usage**:
148+
```sh
149+
export _LIMA_DIRECT_IP_PORT_FORWARDER=true
150+
```
151+
- **Note**: Direct IP port forwarding may fall back to gRPC port forwarding in some cases:
152+
- If the guest's IP address is not available, Lima falls back to gRPC port forwarding.
153+
- If the guest's IP address is available but the connection to the guest's IP address fails, Lima also falls back to gRPC port forwarding.
154+
- If the guest's IP address is not accessible from the host (e.g. localhost on guest), Lima falls back to gRPC port forwarding as well.
155+
143156
### `_LIMA_QEMU_UEFI_IN_BIOS`
144157

145158
- **Description**: Commands QEMU to load x86_64 UEFI images using `-bios` instead of `pflash` drives.

website/content/en/docs/config/port.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,22 @@ lima ip addr show lima0
8888

8989
See [Config » Network » VMNet networks](./network/vmnet.md) for the further information.
9090

91+
### Direct IP Port Forwarding
92+
93+
To enable direct IP port forwarding, set the `_LIMA_DIRECT_IP_PORT_FORWARDER` environment variable to `true`:
94+
95+
```bash
96+
export _LIMA_DIRECT_IP_PORT_FORWARDER=true
97+
```
98+
This feature makes Lima to use direct IP port forwarding instead of gRPC port forwarding.
99+
When this feature is enabled, Lima tries to connect to the guest's IP address directly for port forwarding.
100+
101+
#### Fallback to gRPC Port Forwarding
102+
Lima may fall back to gRPC port forwarding in the following cases:
103+
- If the guest's IP address is not available, Lima falls back to gRPC port forwarding.
104+
- If the guest's IP address is available but the connection to the guest's IP address fails, Lima also falls back to gRPC port forwarding.
105+
- If the guest's IP address is not accessible from the host (e.g. localhost on guest), Lima falls back to gRPC port forwarding as well.
106+
91107
## Benchmarks
92108

93109
<!-- When updating the benchmark result, make sure to update the benchmarking environment too -->

0 commit comments

Comments
 (0)