Traffic shaping - prioritising TCP ACK - Solved

We (very) successfully shape traffic on Linux systems using HTB and are unable to achieve the same control when using MikroTik routers. The most important rule (to us), which we are currently unable to implement, is the ability to prioritise TCP ACK (acknowledgement) packets to ensure the remote system is more quickly able to adjust the transmission rate.

Method we’re using on Linux to prioritise TCP ACK packets:

tc filter add dev $1 parent 1: protocol ip prio 12 u32 \
  match ip protocol 6 0xff \
  match u8 0x05 0x0f at 0 \
  match u16 0x0000 0xffc0 at 2 \
  match u8 0x10 0xff at 33 \
  flowid 1:10;

What we thought would work the same way:

  /ip firewall mangle
    protocol="tcp" tcp-flags=ack chain=postrouting

Our full MikroTik traffic prioritisation implementation:

/queue type
  add name=syrex-pfifo kind=pfifo pfifo-limit=5
  add name=syrex-sfq kind=sfq sfq-perturb=10
/queue tree
  add name="vpn-out" packet-mark="" parent=global-out priority=1 queue="default" limit-at="512k" max-limit="512k" burst-limit=0 burst-threshold=0 burst-time=0s
  add name="vpn-out-fast" packet-mark="vpn-out-fast" parent="vpn-out" priority=2 queue="syrex-pfifo" limit-at="64k" max-limit="512k" burst-limit=0 burst-threshold=0 burst-time=0s
  add name="vpn-out-prio" packet-mark="vpn-out-prio" parent="vpn-out" priority=3 queue="syrex-sfq" limit-at="320k" max-limit="512k" burst-limit=0 burst-threshold=0 burst-time=0s
  add name="vpn-out-normal" packet-mark="vpn-out-normal" parent="vpn-out" priority=5 queue="syrex-sfq" limit-at="64k" max-limit="460k" burst-limit=0 burst-threshold=0 burst-time=0s
  add name="vpn-out-slow" packet-mark="vpn-out-slow" parent="vpn-out" priority=8 queue="syrex-sfq" limit-at="64k" max-limit="128k" burst-limit=0 burst-threshold=0 burst-time=0s
/ip firewall mangle
  add out-interface="vpn" new-packet-mark="vpn-out-fast" protocol="tcp" dscp="4" chain=postrouting action=mark-packet passthrough=no
  add out-interface="vpn" new-packet-mark="vpn-out-fast" protocol="icmp" chain=postrouting action=mark-packet passthrough=no
  add out-interface="vpn" new-packet-mark="vpn-out-fast" protocol="tcp" tcp-flags=ack chain=postrouting action=mark-packet passthrough=no
  add out-interface="vpn" new-packet-mark="vpn-out-prio" dst-address="192.168.1.23" chain=postrouting action=mark-packet passthrough=no
  add out-interface="vpn" new-packet-mark="vpn-out-prio" dst-address="192.168.1.24" chain=postrouting action=mark-packet passthrough=no
  add out-interface="vpn" new-packet-mark="vpn-out-slow" protocol="tcp" dst-port=25 chain=postrouting action=mark-packet passthrough=no
  add out-interface="vpn" new-packet-mark="vpn-out-slow" protocol="tcp" dst-port=465 chain=postrouting action=mark-packet passthrough=no
  add out-interface="vpn" new-packet-mark="vpn-out-normal" chain=postrouting action=mark-packet passthrough=no

Can’t you mark the packet then prioritize based upon the packet mark?

/ip firewall mangle protocol="tcp" tcp-flags=ack chain=postrouting action=mark-packet new-packet-mark="TCP-ack-packet"

Mark the tcp packets with size 0-123 in pre or postrouting and give it high priority in the queue.

This works perfectly! Many thanks for the quick tip.

Would anyone have any reference material to substantiate that the 0-123 packet size? I would like to make it as specific as possible but the following is currently working:

/queue type
  add name=syrex-pfifo kind=pfifo pfifo-limit=5
  add name=syrex-sfq   kind=sfq   sfq-perturb=10
/queue tree
  add name="vpn-out"        packet-mark=""               parent=global-out priority=1 queue="default"     limit-at="512k" max-limit="512k"
  add name="vpn-out-fast"   packet-mark="vpn-out-fast"   parent="vpn-out"  priority=2 queue="syrex-pfifo" limit-at="64k"  max-limit="512k"
  add name="vpn-out-prio"   packet-mark="vpn-out-prio"   parent="vpn-out"  priority=3 queue="syrex-sfq"   limit-at="320k" max-limit="512k"
  add name="vpn-out-normal" packet-mark="vpn-out-normal" parent="vpn-out"  priority=5 queue="syrex-sfq"   limit-at="64k"  max-limit="460k"
  add name="vpn-out-slow"   packet-mark="vpn-out-slow"   parent="vpn-out"  priority=8 queue="syrex-sfq"   limit-at="64k"  max-limit="128k"
/ip firewall mangle
  add out-interface="vpn" new-packet-mark="vpn-out-fast"   chain=postrouting action=mark-packet passthrough=no protocol="tcp" dscp="4"
  add out-interface="vpn" new-packet-mark="vpn-out-fast"   chain=postrouting action=mark-packet passthrough=no protocol="icmp"
  add out-interface="vpn" new-packet-mark="vpn-out-fast"   chain=postrouting action=mark-packet passthrough=no protocol="tcp" tcp-flags="ack" packet-size="0-123"
  add out-interface="vpn" new-packet-mark="vpn-out-prio"   chain=postrouting action=mark-packet passthrough=no src-address="192.168.1.23"
  add out-interface="vpn" new-packet-mark="vpn-out-prio"   chain=postrouting action=mark-packet passthrough=no src-address="192.168.1.24"
  add out-interface="vpn" new-packet-mark="vpn-out-slow"   chain=postrouting action=mark-packet passthrough=no protocol="tcp" dst-port="25"
  add out-interface="vpn" new-packet-mark="vpn-out-slow"   chain=postrouting action=mark-packet passthrough=no protocol="tcp" dst-port="465"
  add out-interface="vpn" new-packet-mark="vpn-out-normal" chain=postrouting action=mark-packet passthrough=no

Is there a reason that you want to additionally match the packet size?

This will match park the tcp ack packets regardless of their size:

add out-interface="vpn" new-packet-mark="vpn-out-fast"   chain=postrouting action=mark-packet passthrough=no protocol="tcp" tcp-flags="ack"

Not setting the size was resulting in the rule matching all traffic. Reading the following article leads me to understand that each packet associated with an established connection would have the ACK flag set:
http://packetlife.net/blog/2010/jun/7/understanding-tcp-sequence-acknowledgment-numbers/

Limiting the size to 0-123, together with the tcp ack flag appears to be working…

The criteria are matched via the logical AND. This means the more criteria that you specify the more restrictive the match will be. I am bewildered as to on how you can be more restrictive and match more. I tried this rule on one of my routers without the size and it it regularly matches traffic.

Are you seeing any traffic being matched when excluding the size limitation?

Attached is a set of rules that simply count matches because the action is passthrough. They were enabled at the exact same time… as you can see the I have a lot more ACK packets then I have ACK packets under 124 bits.
TCP_ACT_Test.jpg

Yeah Josh you are right , it will match a lot more traffic .

bbs , I ran into the EXACT same problem you had as we migrate a lot of netfilter+tc boxes to mtk . At the time I was trying to get it working properly via tcp flags but just could not get it working properly (call it time constraints or rush troubleshooting at 4am) . I’m certain someone smarter than I has a one liner tcp flags to match it perfect :blush: :blush: :blush:


BBS , the secret is in here in the packet details . Do the following on a linux lab / test box and have a look at the size

tcpdump -v -i ethX ‘tcp[13] & 16 != 0’ and src srciporhostnamewhereconnectionisoriginating and less 124 (remember)


Beste Wense
djd