Skip to content

Commit f2c5e34

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 <[email protected]>
1 parent 3d6754e commit f2c5e34

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
@@ -524,6 +524,11 @@ jobs:
524524
create_arg:
525525
- ""
526526
- "--network=vzNAT"
527+
include:
528+
- template: default.yaml
529+
create_arg: "--network=vzNAT"
530+
additional_env: |
531+
_LIMA_DIRECT_IP_PORT_FORWARDER=true
527532
steps:
528533
- name: "Adjust LIMACTL_CREATE_ARGS"
529534
# --cpus=1 is needed for running vz on GHA: https://github.com/lima-vm/lima/pull/1511#issuecomment-1574937888
@@ -544,6 +549,9 @@ jobs:
544549
run: brew install bash coreutils w3m socat
545550
- name: Uninstall qemu
546551
run: brew uninstall --ignore-dependencies --force qemu
552+
- name: Set additional environment variables
553+
if: matrix.additional_env != null
554+
run: echo "${{ matrix.additional_env }}" >>$GITHUB_ENV
547555
- name: Test
548556
run: ./hack/test-templates.sh templates/${{ matrix.template }}
549557
- if: failure()

pkg/hostagent/hostagent.go

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

pkg/hostagent/requirements.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ If any private key under ~/.ssh is protected with a passphrase, you need to have
150150
noMaster: true,
151151
},
152152
)
153+
153154
if runtime.GOOS == "darwin" {
154155
// Limit the Guest IP address detection only to macOS for now.
155156
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)