Finish merge of zerocopy bpf.
This commit is contained in:
parent
212b42b0a3
commit
2676a4aff3
@ -721,159 +721,6 @@ pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef BIOCGETBUFMODE
|
||||
/*
|
||||
* Zero-copy BPF buffer routines to check for and acknowledge BPF data in
|
||||
* shared memory buffers.
|
||||
*
|
||||
* pcap_next_zbuf_shm(): Check for a newly available shared memory buffer,
|
||||
* and set up p->buffer and cc to reflect one if available. Notice that if
|
||||
* there was no prior buffer, we select zbuf1 as this will be the first
|
||||
* buffer filled for a fresh BPF session.
|
||||
*/
|
||||
static int
|
||||
pcap_next_zbuf_shm(pcap_t *p, int *cc)
|
||||
{
|
||||
struct bpf_zbuf_header *bzh;
|
||||
|
||||
if (p->zbuffer == p->zbuf2 || p->zbuffer == NULL) {
|
||||
bzh = (struct bpf_zbuf_header *)p->zbuf1;
|
||||
if (bzh->bzh_user_gen !=
|
||||
atomic_load_acq_int(&bzh->bzh_kernel_gen)) {
|
||||
p->bzh = bzh;
|
||||
p->zbuffer = (u_char *)p->zbuf1;
|
||||
p->buffer = p->zbuffer + sizeof(*bzh);
|
||||
*cc = bzh->bzh_kernel_len;
|
||||
return (1);
|
||||
}
|
||||
} else if (p->zbuffer == p->zbuf1) {
|
||||
bzh = (struct bpf_zbuf_header *)p->zbuf2;
|
||||
if (bzh->bzh_user_gen !=
|
||||
atomic_load_acq_int(&bzh->bzh_kernel_gen)) {
|
||||
p->bzh = bzh;
|
||||
p->zbuffer = (u_char *)p->zbuf2;
|
||||
p->buffer = p->zbuffer + sizeof(*bzh);
|
||||
*cc = bzh->bzh_kernel_len;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
*cc = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* pcap_next_zbuf() -- Similar to pcap_next_zbuf_shm(), except wait using
|
||||
* select() for data or a timeout, and possibly force rotation of the buffer
|
||||
* in the event we time out or are in immediate mode. Invoke the shared
|
||||
* memory check before doing system calls in order to avoid doing avoidable
|
||||
* work.
|
||||
*/
|
||||
static int
|
||||
pcap_next_zbuf(pcap_t *p, int *cc)
|
||||
{
|
||||
struct bpf_zbuf bz;
|
||||
struct timeval tv;
|
||||
struct timespec cur;
|
||||
fd_set r_set;
|
||||
int data, r;
|
||||
int tmout, expire;
|
||||
|
||||
#define TSTOMILLI(ts) (((ts)->tv_sec * 1000) + ((ts)->tv_nsec / 1000000))
|
||||
/*
|
||||
* Start out by seeing whether anything is waiting by checking the
|
||||
* next shared memory buffer for data.
|
||||
*/
|
||||
data = pcap_next_zbuf_shm(p, cc);
|
||||
if (data)
|
||||
return (data);
|
||||
/*
|
||||
* If a previous sleep was interrupted due to signal delivery, make
|
||||
* sure that the timeout gets adjusted accordingly. This requires
|
||||
* that we analyze when the timeout should be been expired, and
|
||||
* subtract the current time from that. If after this operation,
|
||||
* our timeout is less then or equal to zero, handle it like a
|
||||
* regular timeout.
|
||||
*/
|
||||
tmout = p->to_ms;
|
||||
if (tmout)
|
||||
(void) clock_gettime(CLOCK_MONOTONIC, &cur);
|
||||
if (p->interrupted && p->to_ms) {
|
||||
expire = TSTOMILLI(&p->firstsel) + p->to_ms;
|
||||
tmout = expire - TSTOMILLI(&cur);
|
||||
#undef TSTOMILLI
|
||||
if (tmout <= 0) {
|
||||
p->interrupted = 0;
|
||||
data = pcap_next_zbuf_shm(p, cc);
|
||||
if (data)
|
||||
return (data);
|
||||
if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) {
|
||||
(void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
|
||||
"BIOCROTZBUF: %s", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
return (pcap_next_zbuf_shm(p, cc));
|
||||
}
|
||||
}
|
||||
/*
|
||||
* No data in the buffer, so must use select() to wait for data or
|
||||
* the next timeout.
|
||||
*/
|
||||
FD_ZERO(&r_set);
|
||||
FD_SET(p->fd, &r_set);
|
||||
if (tmout != 0) {
|
||||
tv.tv_sec = tmout / 1000;
|
||||
tv.tv_usec = (tmout * 1000) % 1000000;
|
||||
}
|
||||
r = select(p->fd + 1, &r_set, NULL, NULL, p->to_ms != 0 ? &tv :
|
||||
NULL);
|
||||
if (r < 0 && errno == EINTR) {
|
||||
if (!p->interrupted && p->to_ms) {
|
||||
p->interrupted = 1;
|
||||
p->firstsel = cur;
|
||||
}
|
||||
return (0);
|
||||
} else if (r < 0) {
|
||||
(void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
|
||||
"select: %s", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
p->interrupted = 0;
|
||||
/*
|
||||
* Check again for data, which may exist now that we've either been
|
||||
* woken up as a result of data or timed out. Try the "there's data"
|
||||
* case first since it doesn't require a system call.
|
||||
*/
|
||||
data = pcap_next_zbuf_shm(p, cc);
|
||||
if (data)
|
||||
return (data);
|
||||
|
||||
/*
|
||||
* Try forcing a buffer rotation to dislodge timed out or immediate
|
||||
* data.
|
||||
*/
|
||||
if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) {
|
||||
(void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
|
||||
"BIOCROTZBUF: %s", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
return (pcap_next_zbuf_shm(p, cc));
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify kernel that we are done with the buffer. We don't reset zbuffer so
|
||||
* that we know which buffer to use next time around.
|
||||
*/
|
||||
static int
|
||||
pcap_ack_zbuf(pcap_t *p)
|
||||
{
|
||||
|
||||
atomic_store_rel_int(&p->bzh->bzh_user_gen, p->bzh->bzh_kernel_gen);
|
||||
p->bzh = NULL;
|
||||
p->buffer = NULL;
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
|
||||
{
|
||||
@ -881,9 +728,6 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
|
||||
int n = 0;
|
||||
register u_char *bp, *ep;
|
||||
u_char *datap;
|
||||
#ifdef BIOCSETBUFMODE
|
||||
int i;
|
||||
#endif
|
||||
#ifdef PCAP_FDDIPAD
|
||||
register int pad;
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user