Linux' bridge filter framework has available mechanisms where the layer 2 filtering done by
ebtables can do an upcall to
iptables (as well as
ip6tables) and have filtering travel from layer 2 (
ebtables' frames) through layer 3 (
iptables) and then back to layer 2. This is much beyond the use the
BROUTING chain which only gives the logical choice of staying at layer 2 or continuing at layer 3 (by doing a frame
broute to local).
This layering violation allows for example to leverage the
conntrack facility and have stateful firewalling available as if at layer 2.
It also caused troubles when people didn't expect this to happen and got issues hard to debug, or hindered performances when it was (most of the time) not needed. So starting with kernel 3.18, the br_netfilter code was split from the bridge code and modularized and is not automatically loaded anymore.
To use this feature now with iptables, one has to
modprobe br_netfilter and keep the sysconf parameter
net.bridge.bridge-nf-call-iptables set to
1 (equivalent to
echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables). This will now allow all the wonderful complexity of OP's link: ebtables/iptables interaction on a Linux-based bridge. Note that this module can also be automatically loaded when iptables uses the
physdev) match and this can subtly alter the whole firewall behaviour if not careful when using both
nftables: this feature is still not available today for
nftables. The current status is considered a bit messy (because of layering violations' additional complexity) and some reorganization is sought before trying to implement this for
nftables, as hinted in some netdevconf reports. It's not clear if the newer emulation layer
xtables-nft (as used by default in future Debian 10) can use this feature (probably not).