"Damian Higgins" wrote:
Hi Stuart,

First off, thank you for the feedback you provided. Unfortunately, you
misunderstood the issue I'm encountering because you haven't read my
entire post. So, I'll try to make a brief post of the previous
message, to make it easier to read, and hope you will have the
patience to read it this time :).

Perhaps you are misunderstanding how pf works. Instead of trying to solve *your* problem, I will try to describe how pf+altq works, and it will be up to you to figure out how to accomplish what you want to do.


First, some concepts of queueing/policing I learned from my previous
experience in other environments(correct me if I'm wrong) :

First forget about other environments, especially Linux. I have deleted the rest of your post, since it does not really matter what you or other environments think about how traffic shaping should be done. If you are using OpenBSD, try to understand how it is done with pf+altq.


Here are the basic rules for pf. You may already know some of them, but please bear with me. You may learn something new:

# Filtering is stateful in pf, and it is strongly recommended to keep it that way (ie. use 'no state' only if you really know what you are doing). The S/SA flags being default also have strong reasons.

# Think of 'state' as a 'connection'. This is especially true for TCP. Use systat(1) or pftop (from ports) to see the states. A state *sees* packets in *both* directions that belong to a particular traffic.

# If a packet matches a state, no rules are evaluated *hint*

# If a packet does not match an existing state but matches a rule, a state is created. Further packets of this 'connection' will just match the state, and bypass ruleset evaluation.

# Loading pf rules with 'pfctl -f pf.conf' does not clear existing states (unless you also use the proper flush command line switch) *hint*

# A connection that traverses an OpenBSD router usually enters pf twice (at inbound and outbound interface) and provided there are appropriate pass rules, it will create states on both interfaces. That is, every packet of a connection both inbound and outbound will have two states associated with it.

# A connection that originates from or terminates on an OpenBSD box will have a single state associated with it.

# NAT/RDR rules are evaluated before filter rules, and address translation happens *before* rules are evaluated, so rules are always checked against translated packets (NAT on incoming, RDR on outgoing).


And the basic rules for altq:

# altq *only* filters *outbound* packets on an interface. This is usually not related to the direction of the connection itself.

## Example: if you want to restrict internal hosts HTTP downloads from outside servers, these *incoming* HTTP payloads have to be filtered at the interface facing the hosts. This also means there is no way to apply altq to limit downloads that are initiated from the OpenBSD gateway itself.

## Example: if you want to increase the priority of the e-mails that your mail server sends, use the interface facing your ISP.

# Each packet, as it passes through the network stack can be assigned a 'queue-id'. This queue id determines which queue the packet is placed as it *leaves* the box. If a packet has no queue-id, then it is assigned to the default queue.

# The queue ids are mapped to queue names, that is, queues that carry the same name have the same id.


And this is how PF assigns packets to queues:

# Each rule has two queue ids, one for normal one for high-priority packets as specified by the rule definition (see pf.conf for details). If you specified a single queue in your rule definition, that means both ids are equal.

# By default the packet has no queue-id assigned.

# If a packet matches a rule, and that rule specifies a queue, the packet queue-id is replaced by the queue id specified by the rule. If the rule has no queue specified, the packet queue-id is not changed (does not revert back to default).

# If a packet matches a state, the rule that created the state is consulted (as above).

# Since a packet can match up to two rules/states as it traverses a router, the last assigned queue wins (as the queues only take effect as the packet exits the router).

# Note that, since a state matches packets in both directions, packets in both directions will be assigned queue ids by a given state. That makes it possible to create a state with a rule on one interface, and have the reply packets assigned to the same queue specified by that rule on a different interface.


Finally, here are some additional things to think about or investigate:

# You can do a lot of creative and flexible stuff with 'tag' and 'tagged' keywords in your ruleset. Assigning queues by 'pass quick tagged XYZZY queue MAGIC' type of rules is much easier to keep track of.

# What happens if you change the ruleset while traffic is flowing? Hint: existing states will point to a default 'empty' rule.

# What happens when states are synchronized by pfsync(4) between two carp(4)'ed firewalls? Hint: The mapping used to get lost, so if the firewall failed over queues would not work for 'synced' states although they would work nor new states. How this is handled now in -current is left as an exercise.


Now, armed with the above, you should be able to explain the behaviour you see, and design a filter that does what you want.

Have fun ...


Can



PS: pflog, tcpdump and pftop/systat are your friends.

PPS: You can always look at the source code to see how things work.

PPPS: When asking questions, give as much context information as possible.

PPPPS: Some of the above rules may have changed slightly after the recent overhaul of pf state handling. There may also be bugs and/or regressions, so a good bug report really helps a lot. A report that says "it works with 4.3 but not with 4.4 or -current" goes a long way to point out a regression.

Reply via email to