m_tag_find() overhead
Eugene Grosbein
eugen at kuzbass.ru
Tue Nov 25 06:22:20 PST 2008
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
More information about the freebsd-ipfw
mailing list