Skip to content

Add --network-id option#258

Draft
tofugarden wants to merge 4 commits into
nirs:mainfrom
tofugarden:feat/network-id
Draft

Add --network-id option#258
tofugarden wants to merge 4 commits into
nirs:mainfrom
tofugarden:feat/network-id

Conversation

@tofugarden

@tofugarden tofugarden commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

--network-id= can be set to isolate the interface to the network with the specified UUID. DHCP service is not provided on this network.

Fixes #120

@tofugarden tofugarden marked this pull request as draft June 21, 2026 19:45

@nirs nirs left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tofugarden Thanks! Let's try to simplify and minimize change in existing code.

Can you add more details on what does not work with ipv6? We can add a test mark as xfail to we know that does not work.

Comment thread docs/integration.md Outdated
Comment thread docs/integration.md Outdated
Comment thread docs/integration.md Outdated
Comment thread docs/integration.md Outdated
Comment thread docs/integration.md Outdated
Comment thread programs/run.c
Comment thread testing/helper_test.py Outdated
Comment thread testing/helper_test.py Outdated
Comment thread testing/helper_test.py Outdated
Comment thread testing/helper_test.py
Comment thread testing/helper_test.py Outdated
Comment thread testing/helper_test.py Outdated
Comment thread testing/helper_test.py Outdated
Comment thread testing/helper.py Outdated
@nirs

nirs commented Jun 21, 2026

Copy link
Copy Markdown
Owner

To simplify the change, I would start with adding --network-id in all layers without the options to set the host ip/ipv6/subnet. When this works locally and in the CI we can add the ipv4 options. Finally add the ipv6 options.

@tofugarden

Copy link
Copy Markdown
Contributor Author

To simplify the change, I would start with adding --network-id in all layers without the options to set the host ip/ipv6/subnet. When this works locally and in the CI we can add the ipv4 options. Finally add the ipv6 options.

Thank you so much, this is great! I should have time to have the first of these smaller patches in by Sunday.

@tofugarden

Copy link
Copy Markdown
Contributor Author

Comparing test results between macOS <26 & 26, and there seems to be inconsistent behavior that isn't documented as far as I can find.

Local testing on macOS 15.6.1 shows:

  • setting vmnet_network_identifier_key without vmnet_host_ip_address_key results in no address being assigned to the host interface
  • vmnet reports 0.0.0.0/0 as the interface subnet
  • Tests fail trying to get an ARP response from 0.0.0.0
  • setting vmnet_host_ip_address_key and vmnet_host_subnet_mask works as expected, and tests that set those keys pass

On macOS 26, a /24 subnet is selected by vmnet and the host gets the first address.

There is nothing explicitly incorrect about having a bridge with no host address I think? It's just a shame that users on <26 will need to manually deconflict subnets if --network-id is set. Docs will note this.

I think I'll write a test that starts two helpers without --host-ip-address (won't be on the next commit anyway) on the same --network-id, and has them ping each other to pass.

@nirs

nirs commented Jun 27, 2026

Copy link
Copy Markdown
Owner

@tofugarden Don't worry about macOS < 26. macOS 27 will be released this year, and macOS 15 will become unsupported next year with macOS 28.

We can add a warning about using --network-id requires without --host-ip-address on macOS < 26. I would not enforce this since letting the system assign the network is the best way - it ensures you do't conflict with other application creating networks.

Let's focus now on adding --network-id without anything else. This can be nice little feature for next release.

@nirs nirs left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tofugarden Thanks! Looks good in quick look, I'll do a more detailed review later.

Please squash all commits and force push, and update the PR message to reflect the current change - adding --network-id option.

Comment thread run Outdated
Comment thread docs/integration.md
@tofugarden

Copy link
Copy Markdown
Contributor Author

@nirs couple small fixes, getting on it now!

@nirs nirs left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the CI failures:
https://github.com/nirs/vmnet-helper/actions/runs/28299280398

If you enable the actions on you fork you can run the tests by creating a pull request to your fork. In this repo I need to approve the workflow manually.

Comment thread programs/helper.c
Comment thread testing/helper_test.py
Comment thread programs/helper.c Outdated
Setting --network-id with --operation-mode=host only allows
communication with other host mode interfaces with the same network ID.
DHCP services are not provided on this network.
@tofugarden tofugarden changed the title WIP: Add --network-id and related host address options Add --network-id option Jun 27, 2026
@tofugarden tofugarden marked this pull request as ready for review June 27, 2026 20:01

@nirs nirs left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to see green tests!

Comment thread docs/integration.md

- **--network-id**: Takes a UUID to identify the network. The guest can only
communicate with other host-mode interfaces with the same network ID. No DHCP
service is provided.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add a note about testing with the run script - it will not with --network-id since our vms are configured to use DHCP, and there is no DHCP server on this network.

If you know how to configure DHCP on the network it can be useful to add a section about this here or in docs/development since this is not related to integration with other tools.

Another option is to improve the the testing/ package to configure static ip for the vm when using --network-id. One option is to add --static-ip option to run script, and change cloud-init to configure a static ip instead o DHCP.

I'm also not sure how this will work with mDNS - the vms ip is discovered using mDNS.

For now we can add a note that this does not work with the run script and improve later if we lean how to make it work.

Comment thread programs/helper.c
Comment thread programs/options.c Outdated
if (!uuid_is_null(opts->network_id) && opts->operation_mode != VMNET_HOST_MODE) {
ERROR("--network-id requires --operation-mode set to 'host'");
exit(EXIT_FAILURE);
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not really related to the network options (--start-address, --end-address, --subnet-mask). Adding it here hides the check. We better add the check in the shared/bridged mode blocks - even if we have to repeat it, it makes the code more clear.

Comment thread programs/run.c
Comment thread programs/run.c Outdated
if (options.subnet_mask != NULL) {
ERROR("[runner] conflicting arguments: --network cannot be used with --subnet-mask");
exit(EXIT_FAILURE);
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like leftover from the previous version - not needed and not related to this change.

Comment thread programs/options.c
Comment thread programs/run.c Outdated
ERROR("[runner] conflicting arguments: --network cannot be used with --subnet-mask");
exit(EXIT_FAILURE);
}
if (options.subnet_mask != NULL) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

options.network_id != NULL?

Comment thread run
"--subnet-mask", help="The IPv4 subnet mask (string) to use on the interface."
)
p.add_argument(
"--network-id",

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to validate that the argument is a UUID:

    type=validate_uuid,
def validate_uuid(s):
    parse and raise if s is not a uuid...
    return parsed uuid...

Comment thread run
if args.network_id:
p.error("--network cannot be used with --network-id")

if args.operation_mode == "bridged":

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing validation that args.network_id is None

Comment thread run
if not args.shared_interface:
p.error("--shared-interface required for --operation-mode=bridged")
if args.enable_isolation:
p.error("--enable-isolation not compatible with --operation-mode=bridged")

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs another block for shared interface rejecting non-None --network-id.

@nirs

nirs commented Jun 27, 2026

Copy link
Copy Markdown
Owner

Tested locally with:

% pytest testing/helper_test.py --log-cli-level=debug -k network_id
====================================================================== test session starts =======================================================================
platform darwin -- Python 3.14.6, pytest-9.0.2, pluggy-1.6.0
rootdir: /Users/nir/src/vmnet-helper
configfile: pyproject.toml
collected 27 items / 25 deselected / 2 selected                                                                                                                  

testing/helper_test.py::TestStart::test_host_mode_network_id 
------------------------------------------------------------------------- live log call --------------------------------------------------------------------------
root: Starting vmnet-helper for 'test' with interface id '83fa1a6e-13ec-408f-ae44-2c26bc317160'
root: interface: {'vmnet_write_max_packets': 256, 'vmnet_read_max_packets': 256, 'vmnet_subnet_mask': '255.255.255.0', 'vmnet_mtu': 1500, 'vmnet_end_address': '192.168.129.254', 'vmnet_start_address': '192.168.129.1', 'vmnet_interface_id': '83FA1A6E-13EC-408F-AE44-2C26BC317160', 'vmnet_max_packet_size': 1514, 'vmnet_mac_address': '1a:ad:75:f7:ca:a2'}
PASSED                                                                                                                                                     [ 50%]
testing/helper_test.py::TestConnectivity::test_ping_host_network_id 
------------------------------------------------------------------------- live log call --------------------------------------------------------------------------
root: Starting vmnet-helper for 'test' with interface id '83fa1a6e-13ec-408f-ae44-2c26bc317160'
root: interface: {'vmnet_write_max_packets': 256, 'vmnet_read_max_packets': 256, 'vmnet_subnet_mask': '255.255.255.0', 'vmnet_mtu': 1500, 'vmnet_end_address': '192.168.129.254', 'vmnet_start_address': '192.168.129.1', 'vmnet_interface_id': '83FA1A6E-13EC-408F-AE44-2C26BC317160', 'vmnet_max_packet_size': 1514, 'vmnet_mac_address': '1a:ad:75:f7:ca:a2'}
test: Sent ARP request to 192.168.129.1
test: Got ARP reply in 0.003647 seconds
test: Sent ICMP echo request to 192.168.129.1
test: Got ICMP reply in 0.000493 seconds
PASSED                                                                                                                                                     [100%]

I ran this after the full tests, so the host network (192.168.128.0/24) was still used by vmnet-broker. We got a new network (192.168.129.0/24) and ping works.

@nirs

nirs commented Jun 27, 2026

Copy link
Copy Markdown
Owner

The missing part to complete this work: learn how to use this with the run script to create 3 vms using host mode and 2 network ids:

  • vm1 network-id=C2C82CCF-F735-4060-9BCF-A68694158764
  • vm2 network-id=C2C82CCF-F735-4060-9BCF-A68694158764
  • vm3 network-id=0CA57A54-4A1C-4125-A4A7-56B87F53C240

vm1 and vm2 will be on same bridge (bridge100) and network (192.168.128.0/24) and can communicate.
vm3 will will be on another bridge (bridge101) and network (192.168.129.0/24) and it should be able to communicate with vm1 and vm2.

You may need to tweak the cloud-init configuration to assign static ip to the vms, or find how to add dhcpd to the network.

Or maybe you have another way to test this mode?

Testing this without --host-ip-address and --host-subnet-mask will be tricky, since you must provide static ip to the vm, but you cannot do without knowing which network you get from vmnet.

@tofugarden

Copy link
Copy Markdown
Contributor Author

@nirs do you want a CI workflow for this, or just a working run? I'm finding it hard to reuse most of integration.yaml at first glance, but happy to duplicate some of it into a separate job in the same workflow.

@tofugarden

Copy link
Copy Markdown
Contributor Author

Testing --network-id should now work in run:

% shared_id=$(uuidgen)
% for vm in test0 test1; do ./run $vm --operation-mode=host --network-id=$shared_id & done
[ ... ] INFO VM is ready at 192.168.128.209
[ ... ] INFO VM is ready at 192.168.128.184

% ./run test2 --operation-mode=host --network-id=$(uuidgen) &
[ ... ] INFO VM is ready at 192.168.129.111

% ssh ubuntu@192.168.209 ping -c 5 -t 10 192.168.128.184                                             
PING 192.168.128.184 (192.168.128.184) 56(84) bytes of data.                                              
64 bytes from 192.168.128.184: icmp_seq=1 ttl=64 time=0.319 ms                                            
64 bytes from 192.168.128.184: icmp_seq=2 ttl=64 time=0.469 ms                                            
64 bytes from 192.168.128.184: icmp_seq=3 ttl=64 time=0.610 ms                                            
64 bytes from 192.168.128.184: icmp_seq=4 ttl=64 time=1.02 ms                                             
64 bytes from 192.168.128.184: icmp_seq=5 ttl=64 time=0.659 ms

% ssh ubuntu@192.168.128.209 ping -c 5 -t 10 192.168.129.111
ping: connect: Network is unreachable

Beware of flakiness due to address conflicts, my IPAM strategy without --host-ip-address is akin to rolling a dice. Also note that VMs declared this way are essentially ephemeral, since changes to their interface's subnet and resulting IP address are not propagated across reboot.

I tried writing a workflow, but I think I kept running out of memory, many runs hung indefinitely or timed out despite the artifacts looking correct. I was able to get things to work once on macos-26-intel, but never again. Haven't tried the large runners yet, they may work.

Comment thread run
Comment on lines +339 to +343
if subnet_mask == "0.0.0.0" and host_address == "0.0.0.0":
# This happens on macOS < 15, let's assign a random subnet
# This will make tests flaky
subnet_mask = "255.255.255.0"
host_address = "192.168.55.1"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still need to test this, no need for CI just yet.

@tofugarden tofugarden marked this pull request as draft June 30, 2026 20:32
@nirs

nirs commented Jun 30, 2026

Copy link
Copy Markdown
Owner

@nirs do you want a CI workflow for this, or just a working run? I'm finding it hard to reuse most of integration.yaml at first glance, but happy to duplicate some of it into a separate job in the same workflow.

No need to update or add a workflow.

The first step is testing this manually, maybe modding the run script to support static ip. This is good enough to prove that this feature works. This is enough to review this change.

The next step is to document how to test this feature in docs/development.md. This should allow developers to test this feature manually. This is enough o merge this change.

The next step is to modify the run script to support static ip. The vm should annoys the mDNS name and the ip address, allowing access to the vm using mDNS. If mDNS does not work, the user can use the static ip. It can work like this:

./run ubuntu --static-ip=192.168.200.2 --network-id FD1D6DEF-CD09-436A-AA29-FDD23960B1AB

This will not work before we implement --host-ip-address and --host-subnet-mask, and optional, since this is an esoteric feature.

The last step is adding CI for this, but this will be very hard. We cannot create vms in host mode since we depend on installing packages. So this means creating vm in shared mode, stopping it and starting it in host mode. This is very slow and we are limited to 5 concurrent runners. I don't want to make the slow CI run 2-3 times slower for testing esoteric feature.

If we will have faster runners that can create a vm in 15 seconds and start it in 5 seconds, it can become feasible to test this in the CI.

@nirs

nirs commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Testing --network-id should now work in run:

% shared_id=$(uuidgen)
% for vm in test0 test1; do ./run $vm --operation-mode=host --network-id=$shared_id & done
[ ... ] INFO VM is ready at 192.168.128.209
[ ... ] INFO VM is ready at 192.168.128.184

% ./run test2 --operation-mode=host --network-id=$(uuidgen) &
[ ... ] INFO VM is ready at 192.168.129.111

% ssh ubuntu@192.168.209 ping -c 5 -t 10 192.168.128.184                                             
PING 192.168.128.184 (192.168.128.184) 56(84) bytes of data.                                              
64 bytes from 192.168.128.184: icmp_seq=1 ttl=64 time=0.319 ms                                            
64 bytes from 192.168.128.184: icmp_seq=2 ttl=64 time=0.469 ms                                            
64 bytes from 192.168.128.184: icmp_seq=3 ttl=64 time=0.610 ms                                            
64 bytes from 192.168.128.184: icmp_seq=4 ttl=64 time=1.02 ms                                             
64 bytes from 192.168.128.184: icmp_seq=5 ttl=64 time=0.659 ms

% ssh ubuntu@192.168.128.209 ping -c 5 -t 10 192.168.129.111
ping: connect: Network is unreachable

Nice!

But assigning random tips is not needed - this will be much simpler:

./run vm1 --operation-mode=host --network-id=$net1 --ip-address 192.168.128.2
./run vm2 --operation-mode=host --network-id=$net1 --ip-address 192.168.128.3
./run vm2 --operation-mode=host --network-id=$net2 --ip-address 192.168.129.2

It cannot be reliable before we support --host-ip-address and --host-subnet-mask, depending on getting networks 192.168.128.0/24 and 192.168.129.0/24.

Beware of flakiness due to address conflicts, my IPAM strategy without --host-ip-address is akin to rolling a dice. Also note that VMs declared this way are essentially ephemeral, since changes to their interface's subnet and resulting IP address are not propagated across reboot.

If we set the static ip using cloud-init the ip address will remain when stating the vm.

I tried writing a workflow, but I think I kept running out of memory, many runs hung indefinitely or timed out despite the artifacts looking correct.

Don't waste time on this, this will be very hard, very slow, and not reliable enough on the old GitHub intel runners.

I was able to get things to work once on macos-26-intel, but never again. Haven't tried the large runners yet, they may work.

macos-26-intel sounds interesting - if they are available we should switch to these runners.

@nirs nirs left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's amend the first commit with the validation fixes.

Comment thread testing/cidata.py
data.update(DISTROS[vm.distro])
# If using static addresses, don't do mDNS setup
if not vm.ip_address:
data.update(DISTROS[vm.distro])

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mDNS is important - this is huge quality of life feature. If we add static ip support we need to try hard to make it work with mDNS.

Creating vm requires installing packages so it cannot work in host mode. We can create a vm in shared mode, stop it , and start it again in host mode.

Comment thread testing/vm.py
"""
if self.ip_address:
interface = ipaddress.IPv4Interface(self.ip_address)
return str(interface.ip)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to always have mDNS - if we need to access the vm by ip_address we can use:

vm.ip_address or vm.fqdn()

When user creates a vm with ip address, they can use the ip address to the connect to the vm. They don't need the logs showing the ip address.

Comment thread testing/vm.py
errno.EHOSTUNREACH,
errno.ECONNREFUSED,
]:
time.sleep(5)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sleeping will add unwanted delay during start and is not needed since when we access the vm via the mDNS address we block in the kernel up to 5 seconds per call.

If accessing with the ip address fail quickly and this becomes a busy loop, we can do this:

start = time.monotonic()
try:
    connect ...
except OSError as e:
    log ...
    if time.monotonic() - start < 0.5:
        time.sleep(1)

This is good change regardless to protected from unexpected early return that we did not experience yet.

Minikube uses the same way:
https://github.com/kubernetes/minikube/blob/2af2c30ef6dfd5b349c77bc1018dff74c8d89309/pkg/drivers/common/ssh.go#L70

Comment thread run
"to the VM are defined using a random number generator seeded from the "
"name of the VM. See assign_ip_address for details. Changes to the static "
"IP address between runs are not propagated, and you should manually delete "
"the disk.img and cidata.iso files for the VM to be reachable."

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is too complicated and magical. Using static ip should be simple - the user specs the ip and responsible for avoiding clashes with other vms or devices on the network.

So the comment should mention that this requires the --ip-address option.

Comment thread run
if args.network_id and args.connection == "runner":
# Without an option to set the host address, --network-id cannot be used with
# --connection=runner
p.error("--network-id is not compatible with --connection=runner")

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How we can run the vm using fd/socket but we cannot run using the runner?

Comment thread run
args, helper.interface[testing.VMNET_MAC_ADDRESS], fd=vm_sock.fileno()
args,
helper.interface[testing.VMNET_MAC_ADDRESS],
ip_address=assign_ip_address(helper, args),

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's simplify - let the user set the ip:

ip_address=args.ip_address

Comment thread run
parsed = uuid.UUID(arg)
if parsed == uuid.NIL:
raise ValueError("Nil UUID will be ignored")
return parsed

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@tofugarden

Copy link
Copy Markdown
Contributor Author

It cannot be reliable before we support --host-ip-address and --host-subnet-mask, depending on getting networks 192.168.128.0/24 and 192.168.129.0/24.

Ok I misunderstood, I thought we wanted a working run with --network-id before we add --host-ip-address. Setting --network-id without --host-ip-address is valid and desirable for the helper, so I wanted that to be available in run. If that's not needed, I'll get started on host IP address assignment and implement that instead.

If we set the static ip using cloud-init the ip address will remain when stating the vm.

This was causing flakiness because vmnet sometimes selects a new subnet upon restart, and then the guest tries to use an address from a different subnet. But if we don't want automatic subnet selection in run, this won't be a problem.

Creating vm requires installing packages so it cannot work in host mode. We can create a vm in shared mode, stop it , and start it again in host mode.

I think systemd-resolved ships with images for fedora & ubuntu, and has mDNS support. I'll try it out. Alpine doesn't, but that's a great workaround!

@nirs

nirs commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Creating vm requires installing packages so it cannot work in host mode. We can create a vm in shared mode, stop it , and start it again in host mode.

I think systemd-resolved ships with images for fedora & ubuntu, and has mDNS support. I'll try it out. Alpine doesn't, but that's a great workaround!

One issue - when restarting a vm cloud-init will not reconfigure the vm unless we generate new cloud-init disk (with new metadata instance-id). So to reconfigure the ip address in host mode we must:

  • delete current cidata.iso, or force creating new one - this can be useful option regardless of --network-id. I think deleting the cidata.iso is good enough, but we can also add a flag like --reconfigure. We can use --host-ip-address to force reconfiguration instead of adding a new flag.
  • set static ip and disable DHCP in network-config (what you did in the last commit)
  • we may need to disable packages and runcmd sections since in host mode we don't have access to the package manager repository. In the last commit you disabled all cloud int configuration which works with the current code. This should be triggered by --operation-id=host - not the --network-id option.

Example flow:

# Create a new vm in shared mode, Control+C to stop
./run vm1 --distro ubuntu

# vm starts in host mode with the requested ip
NET1_UUID=D637004F-D2FC-4C44-940A-12FB093D92F1
NET1_IP1=192.168.200.2
NET1_MASK=255.255.255.0
./run vm1 --operation-mode host --network-id $NET1_UUID --host-ip-address $NET1_IP1 --host-subnet-mask $NET1_MASK

We can document this flow in docs/developement.md

I suggest you start with the docs changes before spending time on the implementation. We should agree on the direction we go first.

@tofugarden

Copy link
Copy Markdown
Contributor Author

I suggest you start with the docs changes before spending time on the implementation. We should agree on the direction we go first.

Ok! What should the scope of this PR be? Do you plan to merge with --host-ip-address in run but not in the helper, and add it in a future PR? Or is proper --host-ip-address support required work to merge? I was under the impression we just wanted --network-id for now.

@nirs

nirs commented Jul 1, 2026

Copy link
Copy Markdown
Owner

I suggest you start with the docs changes before spending time on the implementation. We should agree on the direction we go first.

Ok! What should the scope of this PR be? Do you plan to merge with --host-ip-address in run but not in the helper, and add it in a future PR? Or is proper --host-ip-address support required work to merge? I was under the impression we just wanted --network-id for now.

I think we will have to release --network-id with --host-ip-address and --host-subnet-mask. There is no way to work with static ip if you don't control the network.

You can simply add the next commit with the docs. When we agree on how it should work we can implement it. We can squash the docs commit and implementation later if needed.

Comment thread docs/development.md
Comment on lines +119 to +132
### Without `--network-id`

On most networks, the DHCP range can be constrained using `--start-address`,
`--end-address` and `--subnet-mask`. Addresses outside this range are still
routable as long as they belong to the same subnet. A static IP can be set with
`--guest-ip-address`:

```console
./run vm3 \
--start-address 192.168.12.1 \
--end-address 192.168.12.128 \
--subnet-mask 255.255.255.0 \
--guest-ip-address 192.168.12.129
```

@tofugarden tofugarden Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would get this for free by implementing static addressing for --network-id. Happy to remove since it's out of scope for this PR.

Comment thread docs/development.md
Comment on lines +154 to +159
The following options are available for more control:
- `--host-subnet-mask` is the `vmnet-helper` option to set the subnet mask
when a network ID is set. Defaults to 255.255.255.0.
- `--host-ip-address` is the `vmnet-helper` option to set the host's IP
address when a network ID is set. When used with `./run`, defaults to the
first address in the `--guest-ip-address` subnet.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed for the bare minimum, but these will be simple pass-through options to vmnet-helper once they are implemented there, so free

@tofugarden

Copy link
Copy Markdown
Contributor Author

Also it might make sense for me to do two different PRs related to ./run first:

  1. mDNS with --operation-mode=host
  2. static --guest-ip-address outside the DHCP range

Neither of these are strictly dependent on each other, or --network-id, but we need them to test it.

@nirs

nirs commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Also it might make sense for me to do two different PRs related to ./run first:

  1. mDNS with --operation-mode=host

It should work now - can you share your plan on this change? You can open another issue to describe the change.

  1. static --guest-ip-address outside the DHCP range

Interesting, can be useful feature to use shared network with dhcp but use static ip. Open another issue for this? Show example usage and explain the use case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consider adding --network-identifier option

2 participants