br0 is only a layer 2 networking abstraction - a virtual switch, essentially. If you have a DHCP server running on your hypervisor, have a an IP address assigned to the br0 interface that the DHCP server is pointed at (on the hypervisor itself), and have the DHCP server define a subnet matching the network of your layer 3 address with an appropriate range, then this will work without any other devices.
However, in most cases when using a bridged interface, there is already a DHCP server on the broadcast domain that you're attaching to. br0 acts as a switch, so that traffic is passed to your guests. From your description of your problems, I can offer you an example configuration that will solve most of your problems.
Remember that you must honor the OSI model when stacking interfaces. What this means is that when creating a layer 2 abstraction such as a bridge, you cannot have any layer 3 addressing underneath it. It simply won't work. Since a bridge acts as a switch, you will be giving the bridge itself an IP address and attaching other interfaces in a link layer capacity only. This includes virtual interfaces for VMs and physical interfaces for bridging the external network to said VMs and to the hypervisor.
In this configuration, eth0 is attached to br0, and br0 gets your addressing. VMs attach to br0, and DHCP services (whether they're on your hypervisor or external to it on the same layer 2 domain) will give addresses to your VMs.
# cat /etc/network/interfaces
auto eth0
iface eth0 inet manual
auto br0
iface br0 inet dhcp
bridge_ports eth0
This assumes you're using DHCP to get your address for br0. If not, you will need to apply static addressing to the br0 interface.
When this is done, you will need to restart networking (# systemctl stop networking && systemctl start networking
). This will break your link, so you will need to have an OOB method to get into your machine if your configuration fails. If it's correct, you should be able to reconnect via SSH after the services have been started. It's very important to be able to access the machine via OOB for this kind of task, as it's very easy to get locked out.
Alternatively, and recommended
This is really a job for libvirt to handle. Using libvirt, you can easily use the built in NAT networking for VMs that don't need to be accessed from outside yet need access to the internet. It's also easier to define VMs, create consistent configurations, and to generally manage resources.
You can use a combination of virsh
, virt-install
, and qemu-img
to manage this via the cli. There are many other graphical frontends that you could use alternatively to manage libvirt, such as oVirt or Virtual Machine Manager (virt-manager
)