Subject: Re: bpf/pcap performance
To: Guy Harris <guy@alum.mit.edu>
From: Darren Reed <darrenr@reed.wattle.id.au>
List: tech-net
Date: 04/10/2004 07:17:58
In some email I received from Guy Harris, sie wrote:
> > * libpcap-2004-something is being used with pcap_setbuff to set the BPF
> >   buffer to 1MB
> 
> At least in the tcpdump.org libpcap, the only platform that has 
> "pcap_setbuff()" is Win32; the problem with "pcap_setbuff()" and BPF is 
> that BIOCSBLEN only works on a BPF device not bound to an interface, 
> and once you've done "pcap_open_live()" the device is bound to an 
> interface so you can't set the buffer size.

Really?  So....hmmm....this isn't what I was expecting.  I should have
paid closer attention to what the code was doing rather than trusting
it was setting it and working.  You might have suspected that this code
was originally written on Windows and has been ported back to Unix and
given that the function is present, no consideration was given to whether
or not the code actually did anything.

> Do you mean you have a version of libpcap that sets the minimum initial 
> buffer size to 1MB rather than 32K?

No (see previous comment).  I think what I'm going to do, now I read
this, is create:

pcap_open_live2(device, snaplen, bufsize, promisc, ms, ebuf)

and have pcap_open_live() call it with bufsize == 0 or something
and...  see patch below.  Qualifies as a dirty hack but maybe it's
good enough? I've only implemented pcap_open_live2() for BPF just
as "proof of concept."

I've also added pcap_getbuff() - seemed to be an obvious ommission
in the interface.  The other option here was to make the bufsize
parameter to pcap_open_live2() pass by reference but that seemed
rather crass and pcap_getbuff() is a missing link, IMHO...

Create
Darren

Index: pcap.h
===================================================================
RCS file: /work/CVS/NextGenLiDev/Implementation/libpcap/pcap.h,v
retrieving revision 1.2
diff -c -r1.2 pcap.h
*** pcap.h	22 May 2003 05:10:03 -0000	1.2
--- pcap.h	9 Apr 2004 21:20:32 -0000
***************
*** 170,175 ****
--- 170,176 ----
  char	*pcap_lookupdev(char *);
  int	pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *);
  pcap_t	*pcap_open_live(const char *, int, int, int, char *);
+ pcap_t	*pcap_open_live2(const char *, int, int, int, int, char *);
  pcap_t	*pcap_open_dead(int, int);
  pcap_t	*pcap_open_offline(const char *, char *);
  void	pcap_close(pcap_t *);
***************
*** 199,204 ****
--- 200,206 ----
  int	pcap_is_swapped(pcap_t *);
  int	pcap_major_version(pcap_t *);
  int	pcap_minor_version(pcap_t *);
+ int	pcap_getbuff(pcap_t *);
  int	pcap_setbuff(pcap_t *, int);
  
  /* XXX */
Index: pcap-bpf.c
===================================================================
RCS file: /work/CVS/NextGenLiDev/Implementation/libpcap/pcap-bpf.c,v
retrieving revision 1.3
diff -c -r1.3 pcap-bpf.c
*** pcap-bpf.c	21 May 2003 02:19:39 -0000	1.3
--- pcap-bpf.c	9 Apr 2004 21:20:32 -0000
***************
*** 438,443 ****
--- 438,451 ----
  pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
      char *ebuf)
  {
+ 	return pcap_open_live2(device, snaplen, NULL, promisc, to_ms, ebuf);
+ }
+ 
+ 
+ pcap_t *
+ pcap_open_live2(const char *device, int snaplen, int bufsize, int promisc,
+     int to_ms, char *ebuf)
+ {
  	int fd;
  	struct ifreq ifr;
  	struct bpf_version bv;
***************
*** 487,494 ****
  	 * XXX - there should be a user-accessible hook to set the
  	 * initial buffer size.
  	 */
! 	if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || v < 32768)
! 		v = 32768;
  	for ( ; v != 0; v >>= 1) {
  		/* Ignore the return value - this is because the call fails
  		 * on BPF systems that don't have kernel malloc.  And if
--- 495,506 ----
  	 * XXX - there should be a user-accessible hook to set the
  	 * initial buffer size.
  	 */
! 	if (bufsize == 0) {
! 		if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || v < 32768)
! 			v = 32768;
! 	} else
! 		v = bufsize;
! 
  	for ( ; v != 0; v >>= 1) {
  		/* Ignore the return value - this is because the call fails
  		 * on BPF systems that don't have kernel malloc.  And if
***************
*** 760,765 ****
--- 772,790 ----
  	return (0);
  }
  
+ 
+ /* Get the dimension of the kernel-level capture buffer */
+ int
+ pcap_getbuff(pcap_t *p)
+ {
+ 	int v;
+ 
+ 	if (ioctl(p->fd, BIOCGBLEN, (caddr_t)&v) == -1)
+ 		return -1;
+ 	return v;
+ }
+ 
+ 
  /* Set the dimension of the kernel-level capture buffer */
  int
  pcap_setbuff(pcap_t *p, int dim)