[IPFW] [DIVERT] IP header checksums - why calculate twice?

Dom F misc+freebsd at talk2dom.com
Wed Aug 28 10:45:50 UTC 2013


[Copy of my post to FreeBSD Firewalls forum sent here by suggestion from 
moderator]

I've been toying with using IPDIVERT to adjust values in an IPv4 header. 
When adjusting an incoming IP header, the man page for divert(4) says:

Quote:
Packets written as incoming and having incorrect checksums will be dropped.

My main issue was with trying to leverage the optimised kernel functions 
for checksumming an IP header, for example in_cksum_hdr(). Processes 
that connect to DIVERT sockets are based in user-land so in_cksum_hdr() 
isn't readily available during compile.

Eventually the thought hit me that if some part of the kernel has to 
validate checksums (to decide whether to drop a packet) AND if my 
user-land process has to calculate a checksum to avoid its packet being 
dropped THEN surely there are two wasted checksum calculations going on?

If a root-owned process, root needed for RAW socket, can be trusted to 
inject packets back into the IP stack then surely we can skip the 
checksum test and save a few CPU cycles plus a bit of latency.

Very simple patch for /usr/src/sys/netinet/ip_divert.c (based on rev 
224575):

Code:
--- ip_divert.c.orig    2013-08-26 20:52:18.000000000 +0100
+++ ip_divert.c 2013-08-26 20:52:44.000000000 +0100
@@ -496,6 +496,12 @@
                 /* Send packet to input processing via netisr */
                 switch (ip->ip_v) {
                 case IPVERSION:
+                       /* mark mbuf as having valid checksum
+                          to save userland divert process from
+                          calculating checksum, and kernel having
+                          to check it */
+                       m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED |
+ CSUM_IP_VALID;
                         netisr_queue_src(NETISR_IP, (uintptr_t)so, m);
                         break;
  #ifdef INET6


More information about the freebsd-net mailing list