I'm playing with pf/altq code for a project of mine, and some of it may be of interest to people here. The diffs are for -current only.
http://homepage.mac.com/quension/pf/qexp0.diff
The first diff gives pf DiffServ and ECN awareness (IP level; TCP level ECN is already present). The undocumented "tos" filter option is removed and replaced with "dscp", which matches the DiffServ codepoint of the IPv4 TOS field and IPv6 TC field. TOS_LOWDELAY matching (ssh interactive) is fixed for ECN-enabled sessions, and priority queueing is enabled for IPv6.
dscp = "dscp" ( string | number [ "/" number ] )
For valid strings, read the diff, which maps strings to predefined codepoint value/mask pairs. You can also specify the codepoint value manually, with an optional mask. Default mask is 0x3f (all 6 bits). The predefined value/mask pairs make up a weird mix of 2 obsolete standards and 2 current standards.
http://homepage.mac.com/quension/pf/qexp1.diff
The second diff builds on the first by adding DiffServ-based queueing that works within state. You define a dsqueue that maps various DiffServ values to specific queues, then use that dsqueue in a rule. This change relegates the priority queues to handling TCP ACKs only; dsqueue mappings replace the old internal TOS_LOWDELAY match.
The pfctl changes in this diff are somewhat cobbled together: the syntax isn't great, pfctl doesn't watch for duplicate dsqueue definitions (kernel merges) or dscp mappings (kernel uses first), doesn't echo dsqueue definitions in verbose mode, displays no debug information, etc. The intent was to get only basic functionality, as my own project doesn't require pfctl.
For an example, I'll just dump the configuration I did basic testing with:
[ Side note: HFSC would be better suited to this level of traffic ] [ management, but I'm having a surprising amount of difficulty in ] [ wrapping my head around HFSC theory, and so far pfctl doesn't ] [ like what I'm feeding it. I haven't yet decided if pfctl is ] [ yelling at me for good reason ;) ]
# Queue theory: # standard default for non-testing traffic # explicit root for testing traffic, capped at 50mbit/s # TCP ACKs at high priority, 10% bandwidth cap # tos-lowdelay (ssh interactive) packets at next-highest priority, # 20% bandwidth assignment, free to use excess bandwidth # tos-throughput (ssh file) packets at low priority, 50% bandwidth # assignment, option to use excess bandwidth, and a larger queue # to avoid drops
altq on $int_if cbq queue { f_def, t_def }
queue f_def cbq( default )
queue t_def bandwidth 50Mb { t_l4sq, t_lowdelay, t_throughput }
queue t_l4sq priority 7 bandwidth 10%
queue t_lowdelay priority 6 bandwidth 20% cbq(borrow)
queue t_throughput qlimit 100 bandwidth 50% priority 2 cbq(borrow)# DiffServ Queue map theory: # tos-lowdelay to a separate queue, bundle TCP ACKs with it, since # they aren't critical to maintaining incoming datastream # (assumption is burst-patterned traffic, not sustained) # tos-throughput to a separate queue, but put TCP ACKs in a priority # queue to maintain incoming streams
dsqueue test { \
dscp tos-lowdelay queue t_lowdelay, \
dscp tos-throughput queue(t_throughput, t_l4sq) \
}# Rule queue theory: # default to explicit test root queue, with TCP ACKs in the priority # queue (assuming mostly sustained streams, rather than bursts) # use dsqueue mappings when appropriate
pass out on $int_if from 192.168.0.1 to 192.168.0.50 keep state \
queue(t_def, t_l4sq) dsqueue test