OK, got done testing, using RADIUS attributes for address-lists to use PCQ instead of simple queues seems to work. Unfortunately I can't test it in a larger environment for a while to see whether or not this really performs better under larger user loads. Maybe someone else can verify or check this in the meantime.
Here the setup:
Simple default Hotspot on an interface.
[admin@MikroTik] > /ip hotspot profile print where name=hotspot
Flags: * - default
1 name="hotspot" dns-name="hotspot.example.com" html-directory=hotspot rate-limit="" login-by=https ssl-certificate=wildcard use-radius=yes radius-accounting=yes
[admin@MikroTik] > /ip hotspot print detail
Flags: X - disabled, I - invalid, S - HTTPS
0 S name="hotspot" interface=hotspot1 profile=hotspot idle-timeout=none keepalive-timeout=none ip-of-dns-name=10.1.0.1 proxy-status="running"
Two user profiles without much information on them, I guess they don't really have to exist for this but we often have cases where the shared-users property is set to something other than unlimited.
[admin@MikroTik] > /ip hotspot user profile print where name~"^pro"
Flags: * - default
1 name="profile1" idle-timeout=none keepalive-timeout=2m status-autorefresh=1m shared-users=unlimited transparent-proxy=no
2 name="profile2" idle-timeout=none keepalive-timeout=2m status-autorefresh=1m shared-users=unlimited transparent-proxy=no
Here the RADIUS debug from the router side:
13:15:52 radius,debug,packet sending Access-Request with id 31 to 1.1.1.2:1812
13:15:52 radius,debug,packet Signature = 0x08edbdab79838cb24353d0cd0b03e0c6
13:15:52 radius,debug,packet NAS-Port-Type = 19
13:15:52 radius,debug,packet Calling-Station-Id = "00:1E:52:87:F4:4A"
13:15:52 radius,debug,packet Called-Station-Id = "hotspot"
13:15:52 radius,debug,packet NAS-Port-Id = "hotspot1"
13:15:52 radius,debug,packet User-Name = "banana"
13:15:52 radius,debug,packet NAS-Port = 2149580801
13:15:52 radius,debug,packet Acct-Session-Id = "80200001"
13:15:52 radius,debug,packet Framed-IP-Address = 10.2.0.254
13:15:52 radius,debug,packet MT-Host-IP = 10.2.0.254
13:15:52 radius,debug,packet User-Password = 0x7065656c
13:15:52 radius,debug,packet Service-Type = 1
13:15:52 radius,debug,packet WISPr-Logoff-URL = "http://10.1.0.1/logout"
13:15:52 radius,debug,packet NAS-Identifier = "MikroTik"
13:15:52 radius,debug,packet NAS-IP-Address = 1.1.1.3
13:15:52 radius,debug,packet received Access-Accept with id 31 from 1.1.1.2:1812
13:15:52 radius,debug,packet Signature = 0x74253fd3958d99e3025a917a6f0ec25e
13:15:52 radius,debug,packet Idle-Timeout = 600
13:15:52 radius,debug,packet Service-Type = 512
13:15:52 radius,debug,packet Connect-Info = "Unknown"
13:15:52 radius,debug,packet Calling-Station-Id = "profile1"
13:15:52 radius,debug,packet MT-Group = "profile1"
13:15:52 radius,debug,packet MT-Address-List = "profile1"
13:15:52 radius,debug received reply for 3f:27
13:15:52 hotspot,debug banana (10.2.0.254): Access-Accept from RADIUS
13:15:52 hotspot,debug banana (10.2.0.254): user profile <profile1> from RADIUS
13:15:52 hotspot,debug banana (10.2.0.254): using profile <profile1>
13:15:52 hotspot,debug banana (10.2.0.254): address list <profile1> from RADIUS
13:15:52 hotspot,debug banana (10.2.0.254): idle timeout <600> from RADIUS
13:15:52 hotspot,debug banana (10.2.0.254): adding ip->user binding
13:15:52 hotspot,debug banana (10.2.0.254): adding address-list rule <profile1>
13:15:52 hotspot,account,info,debug banana (10.2.0.254): logged in
And a view of the address-list that the IP was added to:
[admin@MikroTik] > /ip firewall address-list print detail where list~"^pro"
Flags: X - disabled, D - dynamic
0 D list=profile1 address=10.2.0.254
Only two mangle rules are needed for each profile, one for downstream, one for upstream:
[admin@MikroTik] > /ip firewall mangle print
Flags: X - disabled, I - invalid, D - dynamic
0 chain=prerouting action=mark-packet new-packet-mark=profile1-up passthrough=yes src-address-list=profile1 hotspot=from-client
1 chain=postrouting action=mark-packet new-packet-mark=profile1-down passthrough=yes dst-address-list=profile1 hotspot=to-client
2 chain=prerouting action=mark-packet new-packet-mark=profile2-up passthrough=yes src-address-list=profile2 hotspot=from-client
3 chain=postrouting action=mark-packet new-packet-mark=profile2-down passthrough=yes dst-address-list=profile2 hotspot=to-client
Two queue types are needed for each profile, though I guess queue types could be shared if the rate limit per stream is the same. On a system with many users pcq-total-limit would have to be raised significantly:
[admin@MikroTik] > /queue type print where name~"^pro"
0 name="profile1-up" kind=pcq pcq-rate=512000 pcq-limit=50 pcq-classifier=src-address pcq-total-limit=2000
1 name="profile1-down" kind=pcq pcq-rate=1024000 pcq-limit=50 pcq-classifier=dst-address pcq-total-limit=2000
2 name="profile2-up" kind=pcq pcq-rate=256000 pcq-limit=50 pcq-classifier=src-address pcq-total-limit=2000
3 name="profile2-down" kind=pcq pcq-rate=512000 pcq-limit=50 pcq-classifier=dst-address pcq-total-limit=2000
And the queues themselves:
[admin@MikroTik] > /queue tree print
Flags: X - disabled, I - invalid
0 name="profile1-up" parent=global-in packet-mark=profile1-up limit-at=0 queue=profile1-up priority=8 max-limit=0 burst-limit=0 burst-threshold=0 burst-time=0s
1 name="profile1-down" parent=global-out packet-mark=profile1-down limit-at=0 queue=profile1-down priority=8 max-limit=0 burst-limit=0 burst-threshold=0 burst-time=0s
2 name="profile2-up" parent=global-in packet-mark=profile2-up limit-at=0 queue=profile2-up priority=8 max-limit=0 burst-limit=0 burst-threshold=0 burst-time=0s
3 name="profile2-down" parent=global-out packet-mark=profile2-down limit-at=0 queue=profile2-down priority=8 max-limit=0 burst-limit=0 burst-threshold=0 burst-time=0s
The PCQ rate limits are applied correctly and the simple queues that still exist for the Hotspot traffic before the user is authenticated do not register traffic after authentication.