Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 25 Nov 2008 20:42:39 +0700
From:      Eugene Grosbein <eugen@kuzbass.ru>
To:        net@freebsd.org
Cc:        ipfw@freebsd.org
Subject:   m_tag_find() overhead
Message-ID:  <20081125134239.GA17138@svzserv.kemerovo.su>

next in thread | raw e-mail | index | archive | help
Hi!

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;
 	}
 #ifdef IPFIREWALL_FORWARD
+	/* 
+	 * 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) {
 #else
 	if (ro->ro_rt == NULL) {


Eugene Grosbein



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20081125134239.GA17138>