I spent a gazillion hours tonight Googling and working through a bunch of different threads on the topic of QOS. (I’m new to Mikrotik and was going to wade in slowly, but I encountered some choppy voice on a test call today and thought I’d try to clean that up.)
I started with the script posted upthread by pcunite, but after reading some of the documentation, I made some changes and thought I’d post them here to share (in case it helps anyone, or in case someone would like to fix any massive errors I’ve created).
One of the issues with pcunite’s script is that you have to back off from the rated line speed by 10% or so in order to give Queue A (the one with the VoIP markings) a chance to breathe, since there doesn’t appear to be any logic that actually prioritizes Queue A over Queue C–it just basically relies on the fact that Queue C can’t quite use the entire connection to prevent Queue A’s packets from queuing at the ISP edge (in my case, the cable modem).
I think I’ve encountered a way to get a bit closer to the actual maximum throughput and let HTTP and other bulk downloads use the full connection without compromising VoIP (and other priority) packets. This is done by making all of the traffic classes child queues of a single parent queue and then ordering these child queues in priority–my understanding in the Mikrotik wiki documentation is that this should work.
I did some testing and it seems to work when I forced the link to saturation with HTTP traffic (there was no audible VoIP packet loss, and HTTP traffic showed a small amount of packets in the queue while the VoIP queue showed traffic and no queuing, indicating they were passed through without delay).
In my case, I’m on a 50m down, 3m up cable connection, and my ISP does ever so slightly overprovision the connection (~51mbps down and ~3.2mbps up, and they do a pretty good job of giving me my rated speed 24/7), so I wrote the script to push me right to the edge of 50M/3M, and it seems to work OK and gives me just barely shy of those figures to my workstation all while keeping the VoIP connection clean and ICMP pings to nearby servers in the single digits. That said, this is really just a test and a draft and a quick hack of the script (plus an attempt to remove a few of the seemingly redundant lines), so for those just stumbling upon this thread from Google, don’t put this into production without it being vetted by the more experienced community members here.
I also threw in a few extra things–some lines (with limit-at=) to guarantee bandwidth for at least a couple of concurrent calls–this may be unnecessary since it’s first in the priority list, but I figured it couldn’t hurt. I also capped the bandwidth of VoIP and other priority traffic to a shade less than my actual connection, just in case for some reason something happens and a UDP flood attempts to monopolize my upstream bandwidth–there will be a little left over for HTTP and other traffic.
One thing–both the original script by pcunite and this one seem to fail to properly mark the HTTP_BIG traffic. I don’t know if there have been any changes in RouterOS since pcunite last updated his script that may affect that, but I spent a good two hours working on trying to get that to work to no avail. Ultimately, I decided that as long as VoIP traffic is properly classified and prioritized and ACK packets are given priority on the uplink (which helps with the browser feeling responsive even on a saturated uplink), the need to separately classify bulk uploads is mitigated. Perhaps someone can troubleshoot that further.
Oh, one other thing–I did change the VoIP mangle rules to go by DSCP markings rather than ports, since my VoIP infrastructure does mark packets, but if yours doesn’t, you’ll want to uncomment the port-based matching lines and delete the ones that reference DSCP.
Anyway, it seems to be working here, but there’s a very good chance I just got lucky in my testing and it really isn’t working at all or something, so hopefully someone will come along to stop me from spreading misinformation if that’s the case…but I hope this helps in some way.
Date: September 29, 2015
Version: 1.3b1, based on work by pcunite
Tested with RouterOS 6.32.1
Rename ether1-gateway and bridge-local to match your environment
###############################################################################
Mangle
Using prerouting/postrouting since we don’t have dst or src checks.
/ip firewall mangle
###############################################################################
DNS requests. Mark in two places because DNS is sent out by the router (itself) too.
add chain=prerouting action=mark-connection protocol=udp port=53 connection-state=new new-connection-mark=“DNS” comment=“DNS”
add chain=postrouting action=mark-connection protocol=udp port=53 connection-state=new new-connection-mark=“DNS”
add chain=postrouting action=mark-packet passthrough=no connection-mark=“DNS” new-packet-mark=“DNS”
Mark all VoIP TCP traffic based on DSCP marking 46 and 26.
add chain=prerouting action=mark-connection protocol=tcp dscp=46 new-connection-mark=“VOIP” comment=“VOIP”
add chain=prerouting action=mark-connection protocol=udp dscp=46 new-connection-mark=“VOIP”
add chain=prerouting action=mark-connection protocol=tcp dscp=26 new-connection-mark=“VOIP”
add chain=prerouting action=mark-connection protocol=udp dscp=26 new-connection-mark=“VOIP”
add chain=prerouting action=mark-packet passthrough=no connection-mark=“VOIP” new-packet-mark=“VOIP”
Mark all VoIP traffic. We’ve set all our equiptment to use SIP 5060,5061 and RTP 10000-20000.
add chain=prerouting action=mark-connection protocol=udp port=5060,5061,10000-20000 new-connection-mark=“VOIP” comment=“VOIP”
add chain=prerouting action=mark-packet passthrough=no connection-mark=“VOIP” new-packet-mark=“VOIP”
Mark all UDP traffic. Mark different UDP streams if you want more granularity.
add chain=prerouting action=mark-connection protocol=udp connection-state=new new-connection-mark=“UDP” comment=“UDP”
add chain=prerouting action=mark-packet passthrough=no connection-mark=“UDP” new-packet-mark=“UDP”
Ping replies. Mark in two places because ICMP is sent out by the router (itself) too.
add chain=prerouting action=mark-connection protocol=icmp connection-state=new new-connection-mark=“ICMP” comment=“ICMP”
add chain=postrouting action=mark-connection protocol=icmp connection-state=new new-connection-mark=“ICMP”
add chain=postrouting action=mark-packet passthrough=no connection-mark=“ICMP” new-packet-mark=“ICMP”
ACK traffic. Based on viewtopic.php?f=2&t=67965
add chain=postrouting action=mark-packet passthrough=no protocol=tcp tcp-flags=ack packet-size=0-123 new-packet-mark=“ACK” comment=“ACK”
add chain=prerouting action=mark-packet passthrough=no protocol=tcp tcp-flags=ack packet-size=0-123 new-packet-mark=“ACK”
Mark all new HTTP(s) connections with “HTTP” if they have not previously been marked as “HTTP_BIG”.
If the current mark of “HTTP” tranfers more than 5MB and at a rate of 200k+ then mark it as “HTTP_BIG” for the duration of the TCP session.
add chain=prerouting action=mark-connection protocol=tcp new-connection-mark=“HTTP” connection-state=new port=80,443 comment=“HTTP”
add chain=prerouting action=mark-connection protocol=tcp connection-mark=“HTTP” new-connection-mark=“HTTP_BIG” connection-bytes=500000-0 connection-rate=200k-1000M
add chain=prerouting action=mark-packet passthrough=no connection-mark=“HTTP_BIG” new-packet-mark=“HTTP_BIG”
add chain=prerouting action=mark-packet passthrough=no connection-mark=“HTTP” new-packet-mark=“HTTP”
Mark everything else that has no mark applied.
add chain=prerouting action=mark-connection connection-mark=no-mark new-connection-mark=“OTHER” comment=“OTHER”
add chain=prerouting action=mark-packet passthrough=no connection-mark=“OTHER” new-packet-mark=“OTHER”
###############################################################################
HTB Queue Tree a unidirectional queue
Based on 50M down / 3M up connection (measured at 50400k/50.4M down, 3008k/3.0M up).
Replace with your own values as needed and adjust downward if connection is unreliable.
Notes:
priority means ‘drop packets’ WHEN needed.
When limit-at=0 priority starts when max-limit is reached.
When limit-at=123 priority starts when limit-at is reached.
The priority option applies to children not parents. Parent is for setting
overall limits. Therefore use limit-at and max-limit on the children if
you want more granularity.
max-limit must always be set or priority will not happen.
Tips for TCP (not VoIP) SOHO network:
limit-at = Total bandwidth / max hosts
max-limit = Total bandwidth / min hosts
/queue tree
###############################################################################
The secret to ensuring VoIP quality (or any UDP traffic) is to put it into
a queue that will never be full and thus never prioritize (drop) packets.
add name=“MASTER_UP” parent=ether1-gateway queue=default max-limit=3000k
add name=“MASTER_DOWN” parent=bridge-local queue=default max-limit=50000k
add name=“VOIP_U” parent=“MASTER_UP” packet-mark=“VOIP” queue=default limit-at=200k max-limit=2850k priority=1
add name=“VOIP_D” parent=“MASTER_DOWN” packet-mark=“VOIP” queue=default limit-at=200k max-limit=45000k priority=1
add name=“ACK_U” parent=“MASTER_UP” packet-mark=“ACK” queue=default limit-at=200k max-limit=2850k priority=2
add name=“ACK_D” parent=“MASTER_DOWN” packet-mark=“ACK” queue=default limit-at=2000k max-limit=45000k priority=2
add name=“DNS_U” parent=“MASTER_UP” packet-mark=“DNS” queue=default limit-at=200k max-limit=2850k priority=3
add name=“DNS_D” parent=“MASTER_DOWN” packet-mark=“DNS” queue=default limit-at=2000k max-limit=45000k priority=3
add name=“UDP_U” parent=“MASTER_UP” packet-mark=“UDP” queue=default limit-at=200k max-limit=2850k priority=4
add name=“UDP_D” parent=“MASTER_DOWN” packet-mark=“UDP” queue=default limit-at=2000k max-limit=45000k priority=4
add name=“ICMP_U” parent=“MASTER_UP” packet-mark=“ICMP” queue=default limit-at=200k max-limit=2850k priority=5
add name=“ICMP_D” parent=“MASTER_DOWN” packet-mark=“ICMP” queue=default limit-at=2000k max-limit=45000k priority=5
add name=“HTTP_U” parent=“MASTER_UP” packet-mark=“HTTP” queue=default limit-at=200k max-limit=3000k priority=6
add name=“HTTP_D” parent=“MASTER_DOWN” packet-mark=“HTTP” queue=default limit-at=2000k max-limit=50000k priority=6
add name=“HTTP_BIG_U” parent=“MASTER_UP” packet-mark=“HTTP_BIG” queue=default limit-at=200k max-limit=3000k priority=7
add name=“HTTP_BIG_D” parent=“MASTER_DOWN” packet-mark=“HTTP_BIG” queue=default limit-at=2000k max-limit=50000k priority=7
add name=“OTHER_U” parent=“MASTER_UP” packet-mark=“OTHER” queue=default limit-at=200k max-limit=3000k priority=8
add name=“OTHER_D” parent=“MASTER_DOWN” packet-mark=“OTHER” queue=default limit-at=2000k max-limit=50000k priority=8