I just noticed the packet dumps in your original message. They show that
the TCP checksum of all packets past #3 are incorrect.
This is a similar problem with one caused by using the virtio "vhost"
mode with standard tap network devices - if the dhcp server and client
are on the same physical machine, the sender of a packet doesn't fill
in the TCP checksum (assuming that tcp checksum offloading will fix it),
but the tcp checksum offload happens at a level low enough it is never
reached by packets just going to another guest on the same host, so the
checksum is never filled in, and the receiver thus rejects the packet.
(If you want to read a long boring history of this problem, which is
only tangentially related to yours, look here:
https://bugzilla.redhat.com/show_bug.cgi?id=612588 )
It's possible there is a similar bug with certain versions of macvtap
support in the kernel; you'd have to look that up. In the meantime, I
think you should be able to solve your problem by modifying your guests'
interface definitions like this:
<interface type='network'>
<mac address='52:54:00:0e:58:ae'/>
<source network='vlan222'/>
<target dev='macvtap0'/>
<model type='virtio'/>
<driver name='qemu'/> <!-- ADD THIS LINE -->
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00'
slot='0x03' function='0x0'/>
</interface>
This forces libvirt to call qemu with vhost turned off.