This is what DHCP is for.
You can freely choose their MAC addresses, right? Setup a DHCP server on the system in the same (possibly, virtual) ethernet segment as VMs, and bind your IPs to certain MACs.
You will also need to distribute some routes (use DHCP options 121 and 249). The machine with DHCP server itself doesn't need to have public IP or IP in the same network as all clients; the communication with DHCP server takes place when there are still no addresses configured on the client anyway.
If you use ISC DHCP, you need to do something like the following. I am assuming your host machine is your router and NAT box for VMs and it also will host your DHCP server. If you want to do other way, slight adjustments will be required:
- define options 121 and 249 somewhere around top of the
dhcpd.conf
:
option rfc3442-classless-static-routes code 121 = array of integer 8;
option ms-classless-static-routes code 249 = array of integer 8;
probably, new versions don't need this, but mine does.
- create a
shared-network
block, put your dynamic private subnet and your public addresses as "subnets" with masks 32:
option routers 192.168.210.1;
option domain-name-servers 8.8.8.8, 8.8.4.4;
shared-network libvirt-vm-net {
subnet 192.168.210.0 netmask 255.255.255.0 {
range 192.168.210.2 192.168.210.254;
}
subnet 192.0.2.1 netmask 255.255.255.255 {
option rfc3442-classless-static-routes 32, 192,168,210,1, 0,0,0,0, 0, 192,168,210,1;
option ms-classless-static-routes 32, 192,168,210,1, 0,0,0,0, 0, 192,168,210,1;
}
...
}
I am assuming your "private" network for machines behind NAT will be 192.168.210.0/24 and the host will be .1 in that network (assigned to a bridge). Static classless routes (options 121 and 249) setting will add following routes:
ip route add 192.168.210.1 dev eth0
ip route add default via 192.168.210.1
which are needed for everything to work despite the fact there is no subnet containing 192.0.2.1/32 and 192.168.210.1; better try such setup in lab environment if you are unsure how this routing works
- create host definitions with your desired MAC addresses bound to your static IP addresses:
host public-server-1 { hardware ethernet 00:11:22:33:44:55; fixed-address 192.0.2.1; }
...
- add static neighbour ("ARP") entries for those MACs into
/etc/ethers
(on the host):
00:11:22:33:44:55 192.0.2.1
...
- add static routes towards those addreses through the corresponding bridge interface; I don't know how to do this using standard networking configuration of your OS distro, but generic Linux way is like this:
ip route add 192.0.2.1 dev br0
...
Then make sure you assign those MACs to your important VMs within libvirt configs. Other VMs (whose MACs aren't bound) will get their addresses from the configured range as usual.
Actually I implemented and tested this setup in even "more complex" setup (DHCP, host and router all were distinct systems), also I dont' use libvirt and my host is PVE. Even PXE booting perfectly works for both "normal" subnetwork machines (like 192.168.210.0 in the example) and for "public IP" machines (like 192.0.2.1).
To allow all VMs to access Internet you have to use NAT for private IPs and to not to use it for public; it is not a problem, use the rule like iptables -t nat -A POSTROUTING -o <physical-interface-with-public-ip> -s <private-ip-range> -j MASQUERADE
. This way, your private range will be translated to the public-facing address of the host itself, but public addresses will not get translated, but will be routed as they are. Again, it is no problem having public and private addresses on the same network segment and walking through the same virtual NIC.