Mangle rule order for minimizing CPU load?

I am using Mangle and Queue trees for shaping my customers.
As traffic is increasing I have got a feeling that throughput is somehow restricted at some point.
I can see that the %CPU is rising, and the vast of it is consumed by the firewall.
Therefore I am thinking of optimizing my mangle rules and I need some advice from you experts.

I have just moved conn marking to separate chains, and the structure of mangle is now as follows:
(For simplicity only 2 bandwidth classes are included, a lot more exist, presumably calling even more for optimizing)

/ip firewall mangle
# Skip marking of GRE and SNMP, then jump to classify chain for new conns
add action=return chain=prerouting comment="Do not classify GRE (EOIP)" \
    log-prefix=GRE protocol=gre
add action=return chain=prerouting comment="Do not classify SNMP" dst-port=161 \
    log-prefix=SNMP protocol=udp
add action=jump chain=prerouting comment="Classify non-marked conns" \
    connection-mark=no-mark connection-state=new jump-target=classify_up

# Mark upload packets based on connmarks
add action=mark-packet chain=prerouting comment=\
    "Mark Packet upload Private 3000:" connection-mark=conn_Private_3000_up \
    new-packet-mark=packet_Private_3000_up passthrough=no
add action=mark-packet chain=prerouting comment=\
    "Mark Packet upload Private 5000:" connection-mark=conn_Private_5000_up \
    new-packet-mark=packet_Private_5000_up passthrough=no

# Skip marking of GRE and SNMP, then jump to classify chain for new conns
add action=return chain=postrouting comment="Do not classify GRE (EOIP)" \
    log-prefix=GRE protocol=gre
add action=return chain=postrouting comment="Do not classify SNMP" log-prefix=\
    SNMP protocol=udp src-port=161
add action=jump chain=postrouting comment="Classify non-marked conns" \
    connection-mark=no-mark connection-state=new jump-target=classify_down


# Mark upload packets based on connmarks
add action=mark-packet chain=postrouting comment=\
    "Mark Packet download Private 6000:" connection-mark=conn_Private_6000_down \
    new-packet-mark=packet_Private_6000_down passthrough=no
add action=mark-packet chain=postrouting comment=\
    "Mark Packet download Private 10000:" connection-mark=\
    conn_Private_10000_down new-packet-mark=packet_Private_10000_down \
    passthrough=no

# Chain for classifying download traffic
add action=mark-connection chain=classify_down comment=\
    "Mark Conn upload Private 10000/5000:" connection-state="" \
    new-connection-mark=conn_Private_5000_up passthrough=yes src-address-list=\
    Adr_Private_10000/5000
add action=mark-connection chain=classify_down comment=\
    "Mark Conn upload Private 6000/3000:" connection-state="" \
    new-connection-mark=conn_Private_3000_up passthrough=yes src-address-list=\
    Adr_Private_6000/3000
add action=return chain=classify_down

# Chain for classifying upload traffic
add action=mark-connection chain=classify_up comment=\
    "Mark Conn download Private 6000/3000:" connection-state="" \
    dst-address-list=Adr_Private_6000/3000 new-connection-mark=\
    conn_Private_6000_down passthrough=yes
add action=mark-connection chain=classify_up comment=\
    "Mark Conn download Private 10000/5000:" connection-state="" \
    dst-address-list=Adr_Private_10000/5000 new-connection-mark=\
    conn_Private_10000_down passthrough=yes
add action=return chain=classify_up

I have the following questions:

  1. Is testing for connection-mark=no-mark neccessary in addition to connection-state=new? I assume a new connection won’t have any marks?

  2. As the “classifying” chains are only hit by new connections, I guess they won’t add much load. But can I use passthrough=no in the classifying chains? Will execution then return to the rule succeeding the jump rule, thus moving straight on to packet marking for new connections as well?

  3. I am thinking of re-ordering the packet mark rules. Let’s say 80% of my customers are on the 6000/3000 plan, then the vast of the packets will match only the rules for 6000/3000, right?
    Will it then be a good idea to move these rules above the 10000/5000 rules, avoiding a false test for most of the traffic against the 10000/5000 address list before moving to the right rule?

Any other suggestions?
( I know there are other ways to avoid running GRE/SNMP and other “administrative” traffic through the classifier but that’s not my concern here)

  1. Probably not, but I doubt that it makes much difference.

  2. No, passthrough=no finishes processing, it won’t return to parent chain.

  3. Reordering seems like a good idea, but you may also want to add something else. It’s useless to have action=return on end of subchain, it happens automatically. But it can be useful like this:

/ip firewall filter
add chain=mychain src-address-list=list1 action=mark-connection new-connection-mark=mark1 passthrough=yes
add chain=mychain connection-mark=!no-mark action=return 
add chain=mychain src-address-list=list2 action=mark-connection new-connection-mark=mark2 passthrough=yes
add chain=mychain connection-mark=!no-mark action=return 
add chain=mychain src-address-list=list3 action=mark-connection new-connection-mark=mark3 passthrough=yes
...

It will return processing to parent chain once the connection is marked. It’s extra rules, but checking for existence of connection mark should take next to nothing, definitely less than searching through another address list.