Openstack Neutron provides by default some protections for your VMs’ communications, those protections verify that VMs can not impersonate other VMs. You can easily see how it does that by checking the flow rules in an OVS deployment using:
ovs-ofctl dump-flows br-int
If you look for a certain qvo port (or the port number, depending on the deployment), this will show the following lines
table=24, n_packets=1234, n_bytes=1234, priority=2,arp,in_port="qvo",arp_spa=10.10.10.10 actions=resubmit(,25) table=24, n_packets=1234, n_bytes=1234, priority=0 actions=drop
Table 24 by default will drop all the packets originated from a VM unless they are resubmitted to table 25. The criteria for submitting to table 25 is simple: That the source IP for this traffic is the one that has been assigned to that VM, if not it will drop the packet at the end of table 24
In addition , there’s a protection from changing the MAC address of the interface, it’s implemented via the following rule
table=25, n_packets=1234, n_bytes=1234, priority=2,in_port="qvo",dl_src=aa:aa:aa:aa:aa:aa actions=resubmit(,60)
which basically compares the source MAC address of the packet with the expected MAC address of the VM.
In some use cases, you may want to drop this protection, it can be done using
neutron port-update $PORT_ID --port-security-enabled=false
This will ensure there’s no openflow rules in br-int that will drop your packets if they don’t adhere to the MAC/IP requirements
Good Luck !