m_tag_find() overhead

Eugene Grosbein eugen at kuzbass.ru
Tue Nov 25 05:42:42 PST 2008


I wonder if one more call to m_tag_find() for every outgoing packet
would be expensive.

For many years conventional way to implement PBR was: use 'ipfw fwd'.
Currently 'ipfw add fwd ... in' marks a packet with PACKET_TAG_IPFORWARD.
Such forwarding changes packet's outgoing interface generally
but none in the kernel reflect this in packet's metadata
and packets are passed by ip_output() to PFIL hooks with wrong
outgoing interface name ( details and How-To-Repeat may be found here:
http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/129036 )

I've patched src/sys/netinet/ip_output.c to fix this problem
by extra check for PACKET_TAG_IPFORWARD and update of route
if necessary. This adds a call to m_tag_find() for every outgoing
packet if packet filtering is enabled and kernel has
options IPFIREWALL_FORWARD. Please review.

It works for my test lab but I'm not sure if that's correct:
should a call to rtalloc_ign() be accomplished with some
resource freeing call? And what's the meaning of RTF_CLONING second
argument of rtalloc_ign?

--- ip_output.c.orig	2008-11-25 14:21:26.000000000 +0700
+++ ip_output.c	2008-11-25 18:29:32.000000000 +0700
@@ -195,6 +195,20 @@
 		ro->ro_rt = (struct rtentry *)0;
+	/* 
+	 * Check if packet has changed next-hop in ip_input()
+	 * If so, update route so pfil hooks get it right 
+	 */
+	if ((inet_pfil_hook.ph_busy_count != -1) &&
+	    (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL))) {
+		bzero(&iproute, sizeof(iproute));
+		ro = &iproute;
+		bcopy((fwd_tag+1), &ro->ro_dst, sizeof(struct sockaddr_in));
+		m_tag_delete(m, fwd_tag);
+		rtalloc_ign(ro, RTF_CLONING);
+		dst = (struct sockaddr_in *)&ro->ro_dst;
+	}
 	if (ro->ro_rt == NULL && fwd_tag == NULL) {
 	if (ro->ro_rt == NULL) {

Eugene Grosbein

More information about the freebsd-net mailing list