Check that the kernel is set to enable IP forwarding:
sysctl -a | grep forwarding
You can enable with:
sudo sysctl net.ipv4.conf.all.forwarding=1
sudo sysctl net.ipv6.conf.all.forwarding=1
There may also be an issue with ARP proxying. Check with:
sysctl -a | grep proxy_arp
And set with the command:
sudo sysctl net.ipv4.conf.eth0.proxy_arp=1
You can put the keys and values in a file under /etc/sysctl.d
to have the values reset on reboot.
Testing from another device on the router's subnet may help determine the problem.
- Pinging the virtual machine may provide useful diagnostics.
- Checking if you can ARP for the virtual machine will indicate if you can find the MAC address for the server. Use "arp -a" after pinging it to see if the MAC address is successfully found.
- Traceroute may indicate where the problem starts.
Testing with tcpdump
on the eth0
interface may also indicate where the connection is failing.
- Repeated
arp
requests without a valid response indicates a reachability issue.
- Missing
echo
or echo reply
traffic may indicate which side has an issue.
- Traceroute responses to the router or addresses behind it may provide additional information.
It turns out that due to the heavy modular concept of systemd
and systemd-networkd
the scripting question needs to be tackled from a different angle: instead of looking for scripting with the bridge .netdev
definition, the systemd
way is to have a (very small) one-shot .service
unit that is wanted by the bridge .netdev
.
As a side note: it seems that in more recent Linux kernels, the kernel
bridges actually don't use the dynamically changing lowest MAC48
scheme for the bridge MAC48 anymore. Instead, they create a static
MAC48 for the bridge itself. So, in the very strict sense this
solution is not really needed anymore, unless one prefers to use a
"real" hardware MAC48; which is what is done here in the following
service unit.
The necessary new service unit (in lieu of the old post-up
from /etc/network/interfaces
) lives in /etc/systemd/system/bridge-stable-mac.service
and assigns the MAC48 from (built-in, fixed) wlan0
to the bridge itself:
[Service]
Type=oneshot
ExecStart=/bin/bash -c "/bin/echo 'br0 available, setting MAC ' `/bin/cat /sys/class/net/wlan0/address`"
ExecStart=/bin/bash -c "/sbin/ip link set br0 address `/bin/cat /sys/class/net/wlan0/address`"
[Install]
WantedBy=sys-subsystem-net-devices-br0.device
The central point here is the WantedBy=
clause: whenever br0
starts, then this service should be run (exactly once, Type=oneshot
). Systemd is really neat here, as it doesn't need to edit the existing device definition in order to add our dependency, but instead calculates this dependency using our inverse WantedBy=
link. This is really where I think that systemd
does shine.
The service unit above assumes that your bridge is named br0
. You should use a corresponding .netdev
file to define this bridge br0
. For instance, in /etc/systemd/network/10-br0.netdev
:
[NetDev]
Name=br0
Kind=bridge
When it comes to hotplugging bridge ports, systemd
actually does this already out-of-the-box, which is very neat; in /etc/systemd/network/10-br0-ports.network
:
[Match]
Name=eth0 wlan0
[Network]
Bridge=br0
That's it!
Best Answer
According to the manpage of
systemd.netdev
you can add a MAC address in the[NetDev]
section.Just insert the MAC address of
eth0
there.