Congestion Control Algorithms

  • Wondering why some of the standard CC algorithms that are in FreeBSD aren't included. For example: cc_htcp, cc_cdg and cc_cubic. Appears that the only option is "newreno". Each have their place and purpose. For those not familiar with the topic, here is an article that speaks to benefits of different algorithm types:

    The point here is that being able to select a different CCA based on use case, connectivity and other network semantics may help to improve performance. There's no silver bullet, but there are obvious situations where one (or another) may provide better performance. As reference under load, htcp and cubic have frequently netted better performance results. Granted margins may sometimes be thin, but sometimes those margins can make the difference.


  • Congestion control is done at the source of a TCP connection, not in routers along the way. What may happen in routers and switches is determining the most efficient way to handle the forwarded traffic, through priority etc..

  • Congestion control is not "solely" at the source. Congestion control is performed by each -hop- in the path. A hop may be any type of device: router, firewall, etc.

    The firewall is a path in that process. It cannot be logically excluded - only exception is bridge (transparent). Outside of that, it does play a role as it has implications on packets that pass "through" it. To further the point, ALTQ (prior to queues across CPUs) when coupled with HFSC was the predominant means to enable user experience despite congestion through devices in the path. The premise being that high priority services (DNS, DHCP, VoIP, ACK packets) were given priority over bulk traffic. Thus, outside of a bridging firewall - would suggest that the firewall [itself] does play a role in how those packets are handled. Why would so many running OpenBSD and FreeBSD utilize a different CCA for those firewalls, due to the firewall being part-and-parcel to the packet path?


  • @justme2 said in Congestion Control Algorithms:

    Congestion control is not "solely" at the source. Congestion control is performed by each -hop- in the path. A hop may be any type of device: router, firewall, etc.

    You may want to read up on congestion control. It is done by the TCP end points. There is nothing a switch or router can do to control congestion, other than drop packets or ECN. What can be done is determining the optimal queue management, so that latency is reduced as much as possible. While buffers can reduce the number of dropped packets, if too big, they introduce their own problems. Congestion, etc., is covered quite well in "Computer Networks" by Tanenbaum & Wetherall

    TCP congestion control

  • Correct and a firewall becomes an end point - notably for service(s) that reside on it. Services such as HAProxy, Squid, etc. are on the firewall - it becomes the "end point" for those services. If the firewall were -only- a firewall and no services (generating packets inbound/output) - then there would be agreement. But the moment that you provide services then CCA applies.

  • Netgate Administrator

    That's true but that's not the main purpose of pfSense. It's optimised for routing not serving.

    If you feel they would be useful for your application you can open a feature request in redmine:


  • Suggest that once you include NAT - landscape changes. The deterministic factor is where the socket actually terminated - not logical end point, but rather actual. Other scenario is with N interfaces all of same type/bw and only one is egress. Either drop the packet (plain router) or provide response. End-to-end principle generally does not apply when you manipulate the packet or Proxy.

    VPN termination, apps, etc still infers packet management and CCA potential.

    Given statement of “router” bias - if congestion occurs at/within the PFsense device, what behavior should be expected? Simply packets are dropped or ??? Looking for clarity to set expectation of behaviors at this point.


  • @justme2 said in Congestion Control Algorithms:

    The deterministic factor is where the socket actually terminated - not logical end point, but rather actual.

    The socket is still at the end device. All NAT does is change addresses & port numbers. It has no effect on TCP flow control.

  • Being able to proxy a connection is a built-in function on a rule - thus the firewall is certainly involved [directly] in CCA as the socket terminates on the firewall. This isn't to suggest that "all" traffic does, but for some cases... When one looks across the "built-in" (without installing additional packages) - there are a number of functions/services that cause PFSense to be the end point (or origination point) for TCP connections. If you expand upon that with the available packages... The firewall [itself] still has to manage it's local traffic in contrast to pass-through traffic. This is the source of the question(s) around CCA - especially thinking about it if one starts adding on various services: Snort, Squid, pfBlocker, HAProxy and so on. If one were doing nothing but purely firewall (especially as a bridge firewall) with 3 ports and no rules that cause a socket to terminate on the firewall (such as rules with proxy), eg: management, inside and outside without any services, then it's a mute point.

    Where the conversation was additionally leading towards was based on the following scenario:

    • 4 (or more) ports, with 1 port being egress.
    • If the combined bandwidth of the 3 non-egress ports exceeds the egress port...
      How is that handled in terms of PFSense? The congestion is "within" the bounds of the firewall [itself]. Does the local CCA function play a role when it comes to PFSense? As the kernel is compiled - not sure if PFSense handles certain things 'differently' from standard FreeBSD, hence the question(s) to try to ascertain specific behavior(s). Was hoping that someone may know - even if the answer was simply "it drops the packets". Any answer is fine, provided that the answer is correct for PFSense in context.

    For example, in Cisco terms: it would normally have a defined set queues for the egress port. commonly FiFO or WFQ. It will buffer what it can and will reduce tcp window size for ingress as it tries to push traffic out.

    NAT has more to it than just port/address changes - there's also checksum creation, for example as a result of any address and port changes. Otherwise, services that are sensitive to packet specifics would fail (SIP, X, etc). Although your point is made in that NAT is logically just an elegant swapping and table maintenance artifact for purpose.

    Hopefully that provides better context of the information to be ascertained.


  • I support adding the modules, its basically 4 tiny modules, it makes no sense to ommit them, I expect its a leftover from the nano build days where everything was very minimalist.

    Whilst with NAT the flow control should not be affected by a router, there is instances where the pfSense is the end point such as update downloads, pfblockerng downloads, if its used as a proxy, and tcp dns lookups on the dns resolver. I dont expect any major performance changes but at the same time adding the modules is minimal work.

  • Netgate Administrator

    Indeed building the modules but not loading them by default seems very low risk so I would not expect that to be rejected. Though I still don't expect it to make much difference.
    Add it as a feature request on redmine if you have not already.


  • Rebel Alliance Developer Netgate

    It may be OK and low-risk but as some have seen with the new 12.0-RELEASE there is still some risk.

    The other algorithms are not tested as regularly or as thoroughly.

  • It's unfortunate that, that is the case. Although 12.0-RELEASE was just published this month. Tend wait until at least the first round of patches are released before upgrading to a newer version, as a means to [hopefully] avoid initial pitfalls. Will be curious to know what changed (and why) in cc.h to result in Cubic being broken.

    For those that stray, there is a measure of associated risk. If one's environment falls into the high bandwidth, high latency realm - then there may be good reason to consider alternatives.

  • Rebel Alliance Developer Netgate

    I am of the opinion that if you are running a service with sufficient load to need that kind of tuning, it probably doesn't belong on the firewall at that point.

  • @jimp well cubic is not the default, I would agree if it was.

    Also its pretty unfortunate that issue, as its probably the first one related to cubic for several years, there is multiple issues with 12.0 anyway, and as always x.0 releases should usually be avoided regardless if you worried about risk. Finally cubic isnt the only alternative, I personally dont use it all now, HTCP and CDG are probably preferred. I believe FreeBSD is the only major OS now that has newreno as default.

    Given there is no option for operators of pfsense to compile their own kernel/modules I am still of the opinion it should be considered.

  • Banned

    @chrcoluk said in Congestion Control Algorithms:

    Given there is no option for operators of pfsense to compile their own kernel/modules I am still of the opinion it should be considered.

    Huh, spin-up a matching FreeBSD VM, compile the module you need and copy it over. Where is the problem? If that's to difficult for you then you shouldn't mess with kernel modules at all.

  • Modern firewalls blur the line - good, bad or indifferent. Certainly at some measure of service load, you are going to try to strip away as much as possible from the firewall. That may also be offset by architectural/standardization considerations. The firewall still has various "internal" functions where it, itself becomes another cog in the wheel.

    The issue is not service "load". For example, you might be running HAProxy with very low "service load" while the the available bandwidth on egress is at saturation due to traffic "through" the firewall - increasing window. Standing up a server (or VM) to support a minimal overhead function is a waste, may not be possible for some sites and the firewall [itself] still has to deal with handling CC for origination/termination of integrated components. pfBlockerNG is a great enhancement that falls into that same category - with a flurry of activity every hour. The firewall [itself] and how it handles CC plays a role. What's notable is that the weakness of newreno is high bandwidth, high latency situations. No single CCA is going to be good at all things - it's purely use case driven.

    A tangent, although quite interesting - perhaps germane, perhaps not - was considering what would be needed to ensure that the firewall "itself" was handled as 'any other consumer' when it comes to traffic flows "through" the firewall vs. following routing and heading outbound (gateway w/NAT as example). It still doesn't alleviate the need for CC, however... In order to ensure that the firewall [itself] appears as any other consumer -AFAIK- it would need to move to a FIB-based model with a dedicated "traffic" port (not a bad thing, although could be a point of contention). It does bring some interestingly significant value, too. May also vastly change the dynamic for deployment of services (DNS, DHCP, et al). However, the firewall's own traffic becomes 'subject to' and 'handled as' the traffic would be for any other consumer - removing any potential for variation of handling.

    As to the point of spinning up a VM to get a module - that's simply unneeded, excess effort and far more likely to create an issue. What happens if an upgrade occurs and the old file is used vs. the file being included as part of the upgrade? This far outweighs any risks, as the old module could present a kernel crash on boot/load - nastier to unwind than say switching to a different CCA and rebooting (to ensure that all remnants are removed). Could make remote servicing of a firewall - a nightmare.

  • I understand that, but lets put things in perspective, these are a few modules already part of the OS, the work to activate them is adding them to a build script, and the size of the modules?

    Average 14kB each.

    I have seen far bigger things taking much more effort implemented in pfSense.

    For reference modules are not loaded by default, they optional, so the risk of crashing on boot, simply by compiling them and distributing them is pretty much zero. If the end user has gone to the trouble of adding a module to their loader.conf.local then they can go to the trouble of removing it as well if it becomes a problem.

Log in to reply