Lan ports behaving like a hub instead of switch

OpenWrt 24.10 on a Banana PI R4 (w/MediaTek MT7988 Filogic 880)

When I run a packet capture on a host machine to LAN port lan1, I can see all unicast traffic from another host machine connected to LAN port lan2 (which was destined for outbound internet egressing out a WAN port). Both hosts are on the same subnet, but it’s as if though the router lan switch ports are behaving like old-school hub ports and are broadcasting their traffic on all ports.

My question is - What do I have to reconfigure for the hosts/ports to have connectivity between each other (be in the same subnet/broadcast domain), but not broadcast all their unicast IP traffic to one another? (so they behave like switch ports)

I was able to find the "port isolation" configuration knob in the LuCI web UI under:
Network | Interfaces | Devices | lan1 | Bridge port specific options | Port isolation

and that ended up isolating that port from the other hosts, but then the hosts on lan1 and lan2 were no longer able to communicate with each other. (which is not what I wanted)

Some additional data points - the lan ports (lan1, lan2 and lan3) are members of a “bridge interface” called br-lan in the default configuration, but I’m not sure that implies they should be broadcasting to on all ports.

This appears to be somewhat relevant documentation, but I don’t think it answers my question: DSA Mini-Tutorial

I dont think I want VLANs here (I want the hosts to be in the same subnet)

Let’s review your config.

Please connect to your OpenWrt device using ssh and copy the output of the following commands and post it here using the "Preformatted text </> " button:
grafik
Remember to redact passwords, MAC addresses and any public IP addresses you may have:

ubus call system board
cat /etc/config/network
cat /etc/config/wireless
cat /etc/config/dhcp
cat /etc/config/firewall

Thanks for the reply. Here are some of the relevant configs. (I don't think the firewall config could be relevant here, but if I'm wrong it'll take me a bit to redact some of the information before I can post it)

root@OpenWrt:~# ubus call system board
{
        "kernel": "6.6.73",
        "hostname": "OpenWrt",
        "system": "ARMv8 Processor rev 0",
        "model": "Bananapi BPI-R4",
        "board_name": "bananapi,bpi-r4",
        "rootfs_type": "squashfs",
        "release": {
                "distribution": "OpenWrt",
                "version": "24.10.0",
                "revision": "r28427-6df0e3d02a",
                "target": "mediatek/filogic",
                "description": "OpenWrt 24.10.0 r28427-6df0e3d02a",
                "builddate": "1738624177"
        }
}
root@OpenWrt:~# cat /etc/config/network

config interface 'loopback'
        option device 'lo'
        option proto 'static'
        option ipaddr '127.0.0.1'
        option netmask '255.0.0.0'

config globals 'globals'
        option ula_prefix 'fd36:af6c:1b2c::/48'
        option packet_steering '1'

config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'eth1'
        list ports 'lan1'
        list ports 'lan2'
        option promisc '0'

config interface 'lan'
        option device 'br-lan'
        option proto 'static'
        option ipaddr '10.0.0.1'
        option netmask '255.255.255.0'
        option ip6assign '60'

config device
        option name 'br-wan'
        option type 'bridge'
        list ports 'wan'
        list ports 'eth2'

config device
        option name 'wan'

config device
        option name 'eth2'

config interface 'wan'
        option device 'br-wan'
        option proto 'dhcp'
        option peerdns '0'

config interface 'wan6'
        option device 'br-wan'
        option proto 'dhcpv6'

config interface 'guest'
        option proto 'static'
        option ipaddr '192.168.0.1'
        option netmask '255.255.255.0'
        option device 'br-guest'

config interface 'iot'
        option proto 'static'
        option ipaddr '172.16.0.1'
        option netmask '255.255.255.0'
        option device 'br-iot'

config device
        option type 'bridge'
        option name 'br-iot'
        option bridge_empty '1'
        list ports 'lan3'

config device
        option type 'bridge'
        option name 'br-guest'
        option bridge_empty '1'

I think your issue is related to your iot network using a separate bridge with a lan port. You need to use a single bridge and then bridge-VLANs in order to achieve your goals. You can also delete the promiscuous line form the bridge.

Start by deleting this:

Then, add port lan3 back into the main bridge and remove the promisc line:

config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'eth1'
        list ports 'lan1'
        list ports 'lan2'
        list ports 'lan3'

Then create bridge-VLANs:

config bridge-vlan
        option device 'br-lan'
        option vlan '1'
        list ports 'eth1:u*'
        list ports 'lan1:u*'
        list ports 'lan2:u*'

config bridge-vlan
        option device 'br-lan'
        option vlan '2'
        list ports 'lan3:u*'

Finally, edit the lan to use device br-lan.1 and the iot network to use br-lan.2:

config interface 'lan'
        option device 'br-lan.1'
        option proto 'static'
        option ipaddr '10.0.0.1'
        option netmask '255.255.255.0'
        option ip6assign '60'

...

config interface 'iot'
        option proto 'static'
        option ipaddr '172.16.0.1'
        option netmask '255.255.255.0'
        option device 'br-lan.2'

Reboot and test again.

I am a bit uncertain about one other thing -- eth1 may not belong in br-lan, but I would need to see the default state of the device to know for sure.

In order to simplify things for troubleshooting I just completely deleted the br-iot bridge device and moved the lan3 port back to br-lan So I'm back to the default configuration when I first installed OpenWrt (I think this would also suffice for your line of troubleshooting)

As an aside - the option promisc '0' was still listed in my previous config because I was fiddling with that knob while troubleshooting. Setting it back to its default of 0 apparently preserves it in the config file. But it's deleted now.

Rebooted the router, but unfortunately the undesirable behavior still exists. Here is the current config:

root@OpenWrt:~# cat /etc/config/network

config interface 'loopback'
        option device 'lo'
        option proto 'static'
        option ipaddr '127.0.0.1'
        option netmask '255.0.0.0'

config globals 'globals'
        option ula_prefix 'fd36:af6c:1b2c::/48'
        option packet_steering '1'

config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'eth1'
        list ports 'lan1'
        list ports 'lan2'
        list ports 'lan3'

config interface 'lan'
        option device 'br-lan'
        option proto 'static'
        option ipaddr '10.0.0.1'
        option netmask '255.255.255.0'
        option ip6assign '60'

config device
        option name 'br-wan'
        option type 'bridge'
        list ports 'wan'
        list ports 'eth2'

config device
        option name 'wan'

config device
        option name 'eth2'

config interface 'wan'
        option device 'br-wan'
        option proto 'dhcp'
        option peerdns '0'

config interface 'wan6'
        option device 'br-wan'
        option proto 'dhcpv6'

config interface 'guest'
        option proto 'static'
        option ipaddr '192.168.0.1'
        option netmask '255.255.255.0'
        option device 'br-guest'

config device
        option type 'bridge'
        option name 'br-guest'
        option bridge_empty '1'

In the default configuration eth1 is part of br-lan if I remember correctly. It's a slot for an SFP module which is currently unpopulated. Here is an illustrative diagram from https://docs.banana-pi.org/en/BPI-R4/GettingStarted_BPI-R4#_network_configuration (potentially outdated since the port labeled lan0 is now known as wan)

FWIW My testing methodology is running wireshark or sudo tcpdump icmp on the host plugged into lan1, while the host plugged into lan2 pings some address on the internet (e.g. 1.1.1.1)

The lan1 host can see the outbound icmp echo requests (and all other traffic for that matter)

I think the best option would be to reset to defaults and test in that condition. Make a backup first (this way you can easily restore your current config). Reset, test, and report what happens.