Re: Macnetworkprog Digest, Vol 7, Issue 12
site_archiver@lists.apple.com Delivered-To: macnetworkprog@lists.apple.com I believe that I have figured this out. Although this does not appear to be documented anywhere, I have discovered that the mbuf that the ipf_output hook function receives can actually be a list of packets instead of a single packet. As a result, the hook function needs to iterate across all the packets in the list by calling mbuf_nextpkt(). Otherwise, the hook function will fail to process some packets. This explains why the mbuf_freem_list() function corrects the memory leak. - Jay On Fri, Mar 26, 2010 at 8:45 AM, Jay K. Robertson <jkr@asankya.com> wrote:
Hi Brendan,
I appreciate the suggestion, but I have tried that as well. From my understanding of the documentation, the return codes mean the following: - 0 means accept the packet, and ip_output() will continue processing. - EJUSTRETURN means that the output hook function will take responsibility for the packet and must free it when it is done; ip_output() will stop processing. - Any other value means that ip_output() will free the packet and stop processing.
Regardless of whether I return 1 and let ip_output() do the mbuf_freem(), or return EJUSTRETURN and do the mbuf_freem() myself, I still see a memory leak that is proportional to the number of TCP packets that are being processed.
Strangely, I stumbled onto a workaround yesterday. If I return EJUSTRETURN and use mbuf_freem_list() instead of mbuf_freem(), the memory leak does not occur. It is my understanding that mbuf_freem_list() is not only supposed to free the current mbuf, it is also supposed to walk the list of mbufs that the current mbuf is a part of and free all of those as well. It would seem that this behavior could break ip_output_list() completely, or at best, free packets that have yet to be processed by ip_output_list(). However, I haven't observed any adverse effects.
I would really like to know what the proper solution is, and if this is the proper solution, why this is working.
Thanks, - Jay
On Thu, Mar 25, 2010 at 7:33 PM, Brendan Creane <bcreane@gmail.com> wrote:
I have limited experience with IP filters, but for both socket filters and interface filters, your filter routine needs to return EJUSTRETURN when it consumes a packet, versus your current return value of 1. This seems to contradict the documentation for IP filters, but you may try that as an experiment. regards, Brendan
Message: 1 Date: Wed, 24 Mar 2010 16:27:31 -0400 From: "Jay K. Robertson" <jkr@asankya.com> Subject: Memory Leak Issue When Calling ipf_inject_output() To: macnetworkprog@lists.apple.com Message-ID: <a7c6de981003241327r6841f0a9v50a594454a3f6323@mail.gmail.com> Content-Type: text/plain; charset=ISO-8859-1
Hello,
I am building an NKE on OS X 10.5.8 that captures packets using an IP filter on the outbound path. My ipf_output function is below. This is a simple function that receives IP packets, creates a new mbuf, copies the contents of the old mbuf into the new mbuf, and sends it out via ipf_inject_output().
This function works fine except for one major problem. While the packets appear to be sent correctly, if I send TCP packets outbound through this function, it appears to leak large amounts of memory. For some reason, this only happens on TCP packets--I don't see similar behavior when sending UDP packets. Unfortunately, I don't have visibility into the kernel, so I can't really deduce why this is happening.
To generate traffic, I am using iperf. On the Mac running the NKE, I am using the following command line: iperf -c (server IP) -t 60 -i 10
And, on the remote system, I am using the following command line: iperf -s
When I run this, the system is unable to allocate new mbufs, mbuf tags, etc. after about 1 minute, and the system usually becomes unusable. I am out of ideas on how to resolve this issue. Can someone look at my code below and see what I could be doing wrong? I'm not sure if I am completing all of the steps correctly for capturing the packet, generating the checksums, injecting the packet, etc., as the documentation is practically non-existent.
Thanks, - Jay
static errno_t filter_out(void *cookie, mbuf_t *data, ipf_pktopts *opts) { struct ip *iph = (struct ip *)mbuf_data(*data); u_int8_t protocol = iph->ip_p; int len = noths(iph->ip_len); unsigned char buf[1500]; mbuf_t newdata = NULL; errno_t err, ret = 0; // Accept packets by default int direction = 1;
// Filters packets using mbuf_tag_find() if (0 == this->filter_match_tag(*data, direction)) { MSG_INFO("Ignoring previously processed packet\n"); goto out; }
// Selectively filter packets that we aren't interested in if (!filter_ipv4_filter(*data, protocol)) { goto out; }
mbuf_outbound_finalize(*data, PF_INET, 0); // Finalize checksums ret = 1; // Free original packet regardless of what happens
if (0 != (err = mbuf_copydata(*data, 0, len, buf))) { MSG_ERR("Unable to copy mbuf to buf, err=%d\n", err); goto out; }
// At this point, it is intended that data will be sent to another // thread for deferred processing. That thread will construct and // inject a new mbuf through ipf_inject_output(). For now, we // simulate the construction of the new mbuf.
// Allocate the new packet if (0 != mbuf_allocpacket(MBUF_DONTWAIT, 1500, NULL, &newdata)) { MSG_ERR("Unable to allocate mbuf\n"); goto out; // Copy data into new mbuf } else if (0 != mbuf_copyback(newdata, 0, len, buf, MBUF_DONTWAIT)) { MSG_ERR("Unable to copy buf to mbuf\n"); mbuf_freem(newdata); goto out; // Use mbuf_tag_allocate() to set tag so that we don't process this twice } else if (0 != this->filter_set_tag(newdata, direction)) { MSG_ERR("Unable to set tag\n"); mbuf_freem(newdata); goto out; } else { mbuf_clear_csum_requested(newdata); if (0 != (err = ipf_inject_output(newdata, NULL, NULL))) { MSG_ERR("ipf_inject_output() failed, err=%d\n", err); } else { MSG_INFO("ipf_inject_output() succeeded\n"); } // newdata is freed by ipf_inject_output() upon success or failure }
out: return ret; }
------------------------------
_______________________________________________ Macnetworkprog mailing list Macnetworkprog@lists.apple.com http://lists.apple.com/mailman/listinfo/macnetworkprog
End of Macnetworkprog Digest, Vol 7, Issue 12 *********************************************
_______________________________________________ Do not post admin requests to the list. They will be ignored. Macnetworkprog mailing list (Macnetworkprog@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/macnetworkprog/jkr%40asankya.com
_______________________________________________ Do not post admin requests to the list. They will be ignored. Macnetworkprog mailing list (Macnetworkprog@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/macnetworkprog/site_archiver%40lists.... This email sent to site_archiver@lists.apple.com
participants (1)
-
Jay K. Robertson