This adds pfil hooks to iflib.
The idea is to examine and potentially drop unwanted traffic as early in the receive as possible, before mbufs are allocated, and before anything is passed up the stack. This saves considerable CPU. On a Xeon X3430 4-core box from ~10 years ago, we see an increase in packet processing from 7.8Mpps to 11.4Mpps under an extreme UDP flood attack:
<10:38am>slug/gallatin:~>nstat -I ix0
InMpps OMpps InGbs OGbs err TCP Est %CPU syscalls csw irq GBfree 7.84 0.00 4.02 0.00 0 1 98.23 38 10601 5260 3.59 7.86 0.00 4.03 0.00 0 1 98.62 34 10354 5140 3.59 7.89 0.00 4.04 0.00 0 1 98.03 34 10431 5145 3.59
^C
<10:38am>slug/gallatin:~>sudo pfilctl link -i ipfw:default-link ix0
<10:38am>slug/gallatin:~>nstat -I ix0
InMpps OMpps InGbs OGbs err TCP Est %CPU syscalls csw irq GBfree
11.40 0.00 5.84 0.00 0 1 94.88 47 21910 10913 3.59
11.39 0.00 5.83 0.00 0 1 93.50 34 20915 10412 3.59
The major changes here are to remove the unneeded abstraction where callers of rxd_frag_to_sd() get back a pointer to the mbuf ring, and are responsible for NULL'ing that mbuf themselves. Now this happens directly in rxd_frag_to_sd(), and it returns an mbuf. This allows us to use the decision (and potentially mbuf) returned by the pfil hooks. The driver can now recycle mbufs to avoid re-allocation when packets are dropped.
There is some unfortunate cleverness in assemble_segments() around handling the remainder of jumbo frames. I could not see a cleaner way to deal with this.
I've tested this with em (via qemu), and ix & ixl on real hardware. It has been a major performance win everywhere from a DOS perspective.