Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 06 Jan 2008 20:00:59 +0000
From:      Peter Wood <peter@alastria.net>
To:        freebsd-net@freebsd.org
Subject:   Implementation of Sampling for BPF
Message-ID:  <4781337B.40104@alastria.net>

next in thread | raw e-mail | index | archive | help
Hey All,

I piped up a couple of weeks before Christmas regarding a need to control or at
least reliably predict which packets a system would drop if too many packets
where being received by the kernel destined for a BPF program. My particular
example here is a copy of Snort monitoring a mirror of two 1000mbs lines, with
data rates averaging about 900mbs now.

As you can imagin with a reasonable Snort ruleset the kernel is being forced to
drop packets before Snort can process all data sent to it, it is the
uncertainly of a fair sample (or lack of) that I'm worried about.

So today I finally sat down and looked at implementing this on a copy of the
source tree for RELENG_7 from cvs (as this would be the OS we would run,
although I'll happily rework it for CURRENT once complete). I've had an
interesting experience
as this has been my first time modifying the networking side of the BSD kernel.

I initially sat down to implement a "capture 1 in x" model, and have managed
(with what seems like a duct tape special) to implement this basic functionality
by altering the common macro's for receiving and sending data BPF_?TAP? and
ETHER_BPF_MTAP.

One issue I have come across is that due to the order of execution of
ifp->if_data.ifi_ipacket/ifp->if_data.ifi_opacket and the various BPF macros for
packets that cause a response, providing the reply is quick enough that too will
be captured for BPF. For example:

Incoming (ICMP Request)
-----------------------
ifp->if_data.ifi_ipacket++;
ETHER_BFP_MTAP();

Outgoing (ICMP Responce)
------------------------
BFP_MTAP();
ifp->if_data.ifi_opacket++;

So instead I am now looking at reimplementing the concept with the sampling
method I had originally wanted which is "ever x packets capture y packets up
until z packets in a second".

It is now this part I'm looking for feedback from, probably from the more
experiences BSD network hackers. I haven't done a complete survey of the
interface drivers, nor have I looked at the none NIC interfaces, however I'm
unsure that I should trust that the order of execution for incoming and outgoing
packets to be the same.

Instead I'm considering looking at implementing the sampling in bpf_?tap? in
bpf.c just after the BPF interface lock is acquired.

 From my usage point of view I would like the sampling rules to affect all bpf
listeners the same (i.e. they receive the same packets). In my case this is
more for debugging purposes so that I can see what packets Snort is receiving
without shutting it down and putting it into debug.

I believe I would need to maintain the following new information in the bpf_if
structure, probably in it's own structure to keep it neat:

struct bpf_sample {
	u_int skip;		  /* Number of packets to skip before a run */
	u_int run;		  /* Number of packets to run and capture */
	int maxpps;		  /* Maximum number of packets per second */

	u_int current;		  /* Number of packets seen in skip+run */

	/* Making use of ppsratecheck() from kern_time.c */
	int curpps;		  /* Current number of packets per second */
	struct timeval  lasttime; /* Last "time" (actually ticks in tv->sec) */
};

My first question is would bpf_if be the correct place for this information? I
looked at ifnet, however as this data only affects bpf it makes a tad more sense
for it to go into bpf_if.

 From the code I have read, bpfif is initialized from bpfattach2, which is in 
turn called by ether_ifattach via bpfattach, and should be available as soon as 
the interface is added to the kernels interface list.

Secondly because this is interface wide, and I'm unaware of any other control 
application for BPF I'd look at extending ifconfig with some new directives to 
control this.

Perhaps something like:
ifconfig le0 SAMPLESKIP 1000 SAMPLERUN 100 SAMPLEMAX 100000
ifconfig le0 SAMPLE   } Already have these two using a new flag of IFF_SAMPLE,
ifconfig le0 -SAMPLE  } although I can understand objection to new flags.

 From what I've seen this would require the implementation of several new 
ioctl's which would be received by ifhwioctl in if.c. However if it was stored 
in bpfif, that would require obtaining the lock from if.c which currently has no 
files from BPF included. What's the best way to address this? Leave the data in 
ifnet? But if it's in ifnet do I need to lock the ifnet for each packet in BPF?

I think to be honest that's all the specific questions I have, otherwise does it 
look like I'm headed in the right direction? I appreciated someone more 
experienced could probably just knock this up in a couple of minutes, but I'm 
willing/wanting to learn.

Thanks,

P.
-- 
Peter Wood <peter@alastria.net>




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