Good VLAN how to with multiple dumb APs and inter-vlan routing on 24.10

I am trying to setup vlans with multiple dumb aps. Finding a good tutorial seems hard - many seem to be pre-DSA and the others largely just use a single router/ap combo whereas I need 'slightly' more than that:

All the light blue network equipment is running openwrt (24.10 or, in the case of the switch, main). Does anyone know of a good how to for a setup like this?

To top it off, I also need inter-vlan routing to be able to use the media players (chromecast and the like) living in routed-iot and the esphome stuff that is supposed to be in local-iot (presumably it means allow from lan to both iot vlans and mdns in both directions, but not quite sure yet - multi homing home assistant might solve some of it). If it helps, I could connect everything to the managed switch but either way, inter-vlan routing will have to happen on the router (a BPI R4. so plenty of oomph).

Getting an SSID for each vlan sounds like the easy thing to fix at the end so I am focusing on wired for now...

For HA, FWIW, I just set up forwarding from LAN to IoT. That was enough in my case to have HA pick up all the 'smart' stuff living in the IoT VLAN.

I wrote this a while ago, it might help you get on your way:

Make sure to map which network devices should be part of which VLANs and tag them appropriately.

1 Like

I actually threw the diagram into Gemini 2.5 Pro and it came out with fairly sensible step by step guidance - at the very least, I never got locked out of a device an lan still works, which already is a good start :-).

I wouldn't trust AI for this... Would you like us to review the configs? Start with the main router:

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

I would not trust config file but step by step instructions seemed reasonable. For debugging I simplified the architecture to this.

IOW, the router acts as core switch right now, only default lan plus one more vlan:

and I only setup routed-iot on AP2 for now. With the result that

  • lan on vlan 1 works like it should (thankfully)
  • routed-iot on vlan 10 cannot even ping the router with static IP (when connecting to its SSID) and DHCP fails completely. So happy to take you up on your offer :slight_smile:

Router
(no wifi; what it calls wan is really a 4th gige switch port which I bridged into the switch as I am using the SFP port named eth2 as WAN)

root@bpir4:~# ubus call system board
{
        "kernel": "6.6.73",
        "hostname": "bpir4",
        "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@bpir4:~# 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 'fdee:5c1c:2872::/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'
        list ports 'wan'

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

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

config device
        option name 'wan'
        option macaddr 'ca:28:51:5f:09:2b'

config device
        option name 'eth2'
        option macaddr 'ca:28:51:5f:09:2b'

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

config interface 'wan6'
        option device 'br-wan'
        option proto 'dhcpv6'
        option force_link '1'
        option reqaddress 'try'
        option reqprefix 'auto'

[skip wireguard]

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

config bridge-vlan
        option device 'br-lan'
        option vlan '10'
        list ports 'eth1:t'
        list ports 'lan1:t'
        list ports 'lan3:t'
        list ports 'wan:t'

config interface 'routed_iot'
        option proto 'static'
        option device 'br-lan.10'
        option ipaddr '192.168.10.1'
        option netmask '255.255.255.0'
config dnsmasq
        option domainneeded '1'
        option localise_queries '1'
        option rebind_protection '1'
        option rebind_localhost '1'
        option local '/lan/'
        option domain 'lan'
        option expandhosts '1'
        option cachesize '1000'
        option authoritative '1'
        option readethers '1'
        option leasefile '/tmp/dhcp.leases'
        option localservice '1'
        option ednspacket_max '1232'
        list interface 'lan'
        list interface 'vpn'
        list server '/mask.icloud.com/'
        list server '/mask-h2.icloud.com/'
        list server '/use-application-dns.net/'
        list server '127.0.0.1#5053'
        list server '127.0.0.1#5054'
        option doh_backup_noresolv '-1'
        option noresolv '1'
        list doh_backup_server '/mask.icloud.com/'
        list doh_backup_server '/mask-h2.icloud.com/'
        list doh_backup_server '/use-application-dns.net/'
        list doh_backup_server '127.0.0.1#5053'
        list doh_backup_server '127.0.0.1#5054'
        list doh_server '127.0.0.1#5053'
        list doh_server '127.0.0.1#5054'

config dhcp 'lan'
        option interface 'lan'
        option start '100'
        option limit '150'
        option leasetime '12h'
        option dhcpv4 'server'
        option dhcpv6 'server'
        option ra 'server'
        list ra_flags 'managed-config'
        list ra_flags 'other-config'

config dhcp 'wan'
        option interface 'wan'
        option ignore '1'

config odhcpd 'odhcpd'
        option maindhcp '0'
        option leasefile '/tmp/hosts/odhcpd'
        option leasetrigger '/usr/sbin/odhcpd-update'
        option loglevel '4'

[... skip static ips...]

config dhcp 'routed_iot'
        option interface 'routed_iot'
        option start '100'
        option limit '150'
        option leasetime '12h'

config forwarding
        option src 'routed_iot' # Allow routed_iot to reach WAN
        option dest 'wan'
root@bpir4:~# cat /etc/config/firewall

config defaults
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option synflood_protect '1'
        option flow_offloading '1'
        option flow_offloading_hw '1'

config zone
        option name 'lan'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'ACCEPT'
        option masq '1'
        list network 'lan'
        list network 'vpn'

config zone
        option name 'wan'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option masq '1'
        option mtu_fix '1'
        list network 'wan'
        list network 'wan6'

config forwarding
        option src 'lan'
        option dest 'wan'

config rule
        option name 'Allow-DHCP-Renew'
        option src 'wan'
        option proto 'udp'
        option dest_port '68'
        option target 'ACCEPT'
        option family 'ipv4'

config rule
        option name 'Allow-Ping'
        option src 'wan'
        option proto 'icmp'
        option icmp_type 'echo-request'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-IGMP'
        option src 'wan'
        option proto 'igmp'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-DHCPv6'
        option src 'wan'
        option proto 'udp'
        option dest_port '546'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-MLD'
        option src 'wan'
        option proto 'icmp'
        option src_ip 'fe80::/10'
        list icmp_type '130/0'
        list icmp_type '131/0'
        list icmp_type '132/0'
        list icmp_type '143/0'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Input'
        option src 'wan'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        list icmp_type 'router-solicitation'
        list icmp_type 'neighbour-solicitation'
        list icmp_type 'router-advertisement'
        list icmp_type 'neighbour-advertisement'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Forward'
        option src 'wan'
        option dest '*'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-IPSec-ESP'
        option src 'wan'
        option dest 'lan'
        option proto 'esp'
        option target 'ACCEPT'

config rule
        option name 'Allow-ISAKMP'
        option src 'wan'
        option dest 'lan'
        option dest_port '500'
        option proto 'udp'
        option target 'ACCEPT'

config rule
        option name 'Allow-WireGuard'
        option src 'wan'
        option dest_port '51820'
        option proto 'udp'
        option target 'ACCEPT'

config zone
        option name 'routed_iot'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'ACCEPT'
        list network 'routed_iot'

config rule
        option name 'Allow-routed-iot-DNS'
        option src 'routed_iot'
        option dest_port '53'
        option target 'ACCEPT'
        list proto 'tcp'
        list proto 'udp'

config rule
        option name 'Allow-routed-iot-DHCP'
        list proto 'udp'
        option src 'routed_iot'
        option dest_port '67-68'
        option target 'ACCEPT'

ap2
(eth0 is its uplink, DHCPd is off so omitting the file)

{
        "kernel": "6.6.73",
        "hostname": "mt3000",
        "system": "ARMv8 Processor rev 4",
        "model": "GL.iNet GL-MT3000",
        "board_name": "glinet,gl-mt3000",
        "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"
        }
}
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 'fd02:d700:86e7::/48'
        option packet_steering '1'

config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'eth0'
        list ports 'eth1'

config interface 'lan'
        option device 'br-lan.1'
        option proto 'static'
        option ipaddr '192.168.1.6'
        option netmask '255.255.255.0'
        option ip6assign '60'
        list dns '192.168.1.1'
        option gateway '192.168.1.1'

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

config bridge-vlan
        option device 'br-lan'
        option vlan '10'
        list ports 'eth0:t'

config interface 'br_routed_iot'
        option proto 'none'
        option device 'br-lan.10'
        option type 'bridge'
config wifi-device 'radio0'
        option type 'mac80211'
        option path 'platform/soc/18000000.wifi'
        option cell_density '0'
        option country 'CH'

config wifi-device 'radio1'
        option type 'mac80211'
        option path 'platform/soc/18000000.wifi+1'
        option channel 'auto'
        option band '5g'
        option htmode 'HE160'
        option cell_density '0'
        option country 'CH'

config wifi-iface 'wifinet0'
        option device 'radio0'
        option mode 'ap'
        option ssid 'KG'
        option encryption 'psk2'
        option network 'lan'
        option ieee80211r '1'
        option ft_over_ds '0'
        option ft_psk_generate_local '1'

config wifi-iface 'wifinet1'
        option device 'radio1'
        option mode 'ap'
        option ssid 'KG'
        option encryption 'psk2'
        option network 'lan'
        option ieee80211r '1'
        option ft_over_ds '0'
        option ft_psk_generate_local '1'

config wifi-iface 'wifinet2'
        option device 'radio1'
        option mode 'ap'
        option ssid 'KG-routed-iot'
        option encryption 'psk2'
        option network 'br_routed_iot'
config defaults
        option syn_flood '1'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'

config zone
        option name 'lan'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'ACCEPT'
        list network 'lan'
        list network 'br_routed_iot'

config zone
        option name 'wan'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option masq '1'
        option mtu_fix '1'

config forwarding
        option src 'lan'
        option dest 'wan'

config rule
        option name 'Allow-DHCP-Renew'
        option src 'wan'
        option proto 'udp'
        option dest_port '68'
        option target 'ACCEPT'
        option family 'ipv4'

config rule
        option name 'Allow-Ping'
        option src 'wan'
        option proto 'icmp'
        option icmp_type 'echo-request'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-IGMP'
        option src 'wan'
        option proto 'igmp'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-DHCPv6'
        option src 'wan'
        option proto 'udp'
        option dest_port '546'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-MLD'
        option src 'wan'
        option proto 'icmp'
        option src_ip 'fe80::/10'
        list icmp_type '130/0'
        list icmp_type '131/0'
        list icmp_type '132/0'
        list icmp_type '143/0'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Input'
        option src 'wan'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        list icmp_type 'router-solicitation'
        list icmp_type 'neighbour-solicitation'
        list icmp_type 'router-advertisement'
        list icmp_type 'neighbour-advertisement'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Forward'
        option src 'wan'
        option dest '*'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-IPSec-ESP'
        option src 'wan'
        option dest 'lan'
        option proto 'esp'
        option target 'ACCEPT'

config rule
        option name 'Allow-ISAKMP'
        option src 'wan'
        option dest 'lan'
        option dest_port '500'
        option proto 'udp'
        option target 'ACCEPT'

Explicitly binding dnsmasq to routed_iot interface (plus reinstating forward to wan) has fixed most of it (IOW, access from the vlan to the internet works now).

Next up:

  • deal with ICMP to enable ping which would be useful to have - solved
  • add the managed switch - solved
  • add local-iot - solved
  • allow access from lan to *iot - still thinking of what I want to allow
  • get mdns working in both directions - still thinking of how I want to do this

But I came across one more thing that I cannot wrap my head around: On the second dumb ap, as soon as I enable vlans, I lose my connection - thankfully luci then reverts it:

This one is

root@redmilivingroom:~# ubus call system board
{
        "kernel": "6.6.73",
        "hostname": "redmilivingroom",
        "system": "ARMv8 Processor rev 4",
        "model": "Xiaomi Redmi Router AX6S",
        "board_name": "xiaomi,redmi-router-ax6s",
        "rootfs_type": "squashfs",
        "release": {
                "distribution": "OpenWrt",
                "version": "24.10.0",
                "revision": "r28427-6df0e3d02a",
                "target": "mediatek/mt7622",
                "description": "OpenWrt 24.10.0 r28427-6df0e3d02a",
                "builddate": "1738624177"
        }
}

with as simple a network as it gets:

root@redmilivingroom:~# 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 'fdf5:87ca:99cf::/48'

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

config interface 'lan'
        option device 'br-lan'
        option proto 'static'
        option ipaddr '192.168.1.4'
        option netmask '255.255.255.0'
        option ip6assign '60'
        option gateway '192.168.1.1'
        list dns '192.168.1.1'

config device
        option name 'wan'
        option macaddr '5c:02:14:ec:7e:01'

You have tagged and untagged vlans in same port ? I'm not sure it is a very good idea.

I guess I could tag vlan 1 just not sure how to get there in one go - you need to change all devices simultaneously to not lose access, no? Not sure how to get there as only some of them have serial console and even for the ones that have it, it's a pain to hook up physically...

Is there an actual issue with having them mixed?

1 Like

I have read that mixing tagged and untagged in same port is a grey area and I have never tested it myself.

It works like expected (on one of the aps, not sure why the other fails) - now if there issues with security, I am not sure (it obviously creates issues when people plug into switch ports but then again, physical security is always an issue). Will do some more research.

Mystery solved, forgot to change lan to br-lan.1 :blush:

2 Likes

Script would have done it for ya :wink:.

I'll pretend to myself I learned something doing it by hand :slight_smile:

Eventually got it all working, including avahi reflection. In case anyone stumbles across this, avahi needs this in the firewall to get access into the vlans:

config rule
        option name 'Allow-mDNS-In-vlan10'
        option src 'vlan10routediot'
        option proto 'udp'
        option dest_port '5353'
        option dest_ip '224.0.0.251'
        option target 'ACCEPT'
        option family 'ipv4'

config rule
        option name 'Allow-mDNS-In-vlan20'
        option src 'vlan20localiot'
        option proto 'udp'
        option dest_port '5353'
        option dest_ip '224.0.0.251'
        option target 'ACCEPT'
        option family 'ipv4'

and an avahi-daemon.conf like this (crucial point: use the device not the interface names in the interface config :slight_smile: ):

[server]
#host-name=foo
#domain-name=local
use-ipv4=yes
#use-ipv6=yes
check-response-ttl=no
use-iff-running=no
allow-interfaces=br-lan.1,br-lan.10,br-lan.20

[publish]
publish-addresses=yes
publish-hinfo=yes
publish-workstation=no
publish-domain=yes
#publish-dns-servers=192.168.1.1
#publish-resolv-conf-dns-servers=yes

[reflector]
enable-reflector=yes
reflect-ipv=no

[rlimits]
#rlimit-as=
rlimit-core=0
rlimit-data=4194304
rlimit-fsize=0
rlimit-nofile=30
rlimit-stack=4194304
rlimit-nproc=3

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.