PERFORCE change 197135 for review
Takuya ASADA
syuu at FreeBSD.org
Wed Aug 3 14:00:58 UTC 2011
http://p4web.freebsd.org/@@197135?ac=10
Change 197135 by syuu at kikurage on 2011/08/03 14:00:09
test_mqbpf, test_sqbpf replaced with 'bpfnull' based code, from zcopybpf repository.
Affected files ...
.. //depot/projects/soc2011/mq_bpf/src/tools/regression/bpf/mq_bpf/test_mqbpf/test_mqbpf.c#2 edit
.. //depot/projects/soc2011/mq_bpf/src/tools/regression/bpf/mq_bpf/test_sqbpf/Makefile#2 edit
.. //depot/projects/soc2011/mq_bpf/src/tools/regression/bpf/mq_bpf/test_sqbpf/test_sqbpf.c#2 edit
Differences ...
==== //depot/projects/soc2011/mq_bpf/src/tools/regression/bpf/mq_bpf/test_mqbpf/test_mqbpf.c#2 (text+ko) ====
@@ -1,183 +1,459 @@
-/* $OpenBSD: bpf.c,v 1.13 2004/05/05 14:28:58 deraadt Exp $ */
-
-/* BPF socket interface code, originally contributed by Archie Cobbs. */
-
-/*
- * Copyright (c) 1995, 1996, 1998, 1999
- * The Internet Software Consortium. All rights reserved.
+/*-
+ * Copyright (c) 2007 Seccuris Inc.
+ * Copyright (c) 2007 Christian S.J. Peron
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- *
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
*/
-
#include <sys/types.h>
-#include <sys/cdefs.h>
+#include <sys/time.h>
#include <sys/ioctl.h>
-#include <sys/uio.h>
+#include <sys/select.h>
#include <sys/socket.h>
-#include <sys/time.h>
+#include <sys/mman.h>
#include <sys/param.h>
#include <sys/cpuset.h>
-#include <sys/sysctl.h>
+
#include <net/bpf.h>
-#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
-#include <netinet/udp.h>
-#include <netinet/if_ether.h>
+#include <net/if.h>
+#include <net/ethernet.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
+#include <signal.h>
#include <err.h>
+#include <assert.h>
#include <pthread.h>
-#include <signal.h>
-
-#define CAP_FORMAT "cap.dat.%d"
-#define BPF_FORMAT "/dev/bpf%d"
-
-#define QUEUE_TYPE_RX 0
-#define QUEUE_TYPE_TX 1
-#define QUEUE_TYPE_OTHER 2
struct bpf_thread_instance {
- pthread_t thread;
- int rxqueue;
- int txqueue;
- int other;
- int cpu;
- cpuset_t cpuset;
- int fd;
- uint32_t wrote;
+ pthread_t thread;
+ int rxqueue;
+ int txqueue;
+ int other;
+ int cpu;
+ cpuset_t cpuset;
+ int bpffd;
+ u_int64_t sum; /* cycles spent processing packet data */
+ u_int64_t rsum; /* cycles spent in syscalls after wakeup */
+ u_int64_t ssum; /* cycles spent not sleep in event loop */
+ u_int64_t psum; /* cycles spent before buffer can be reclaimed */
+ u_char *bufa, *bufb;
+ unsigned long count;
+ unsigned long wrote;
};
static char *ifname = NULL;
static struct bpf_thread_instance *instances;
static int rxqlen, txqlen;
-static struct timeval start;
+
+int bpf_open(void);
+void usage(void);
+
+static struct ifreq ifr;
+static int Iflag;
+static char *iflag;
+static int bflag = 32768;
+static int vflag;
+static int zflag;
+static int Tflag;
+static int pflag;
+static int Pflag;
+
+#ifndef BPF_BUFMODE_ZBUF
+/*
+ * bpfnull uses certain constructs that depend on zero-copy definitions being
+ * present in bpf.h even when running in normal buffer mode. If the system
+ * doesn't have these constructs, define them locally.
+ */
+struct bpf_zbuf {
+ void *bz_bufa;
+ void *bz_bufb;
+ size_t bz_buflen;
+};
+#warning "BPF_BUFMODE_ZBUF not present, building without zero-copy support"
+#endif
+
+static int
+handle_int(int sig __unused)
+{
+ int i;
+ struct bpf_stat bs;
+ double wrote = 0, throughput;
+ u_int64_t sum = 0; /* cycles spent processing packet data */
+ u_int64_t rsum = 0; /* cycles spent in syscalls after wakeup */
+ u_int64_t ssum = 0; /* cycles spent not sleep in event loop */
+ u_int64_t psum = 0; /* cycles spent before buffer can be reclaimed */
+ unsigned long count = 0;
+#if 0
+ u_int recv = 0;
+ u_int drop = 0;
+#endif
+
+ for (i = 0; i < (rxqlen + txqlen + 1); i++) {
+ pthread_cancel(instances[i].thread);
+ pthread_join(instances[i].thread, NULL);
+ wrote += (double)instances[i].wrote / (double)(1024 * 1024);
+ sum += instances[i].sum;
+ rsum += instances[i].rsum;
+ ssum += instances[i].ssum;
+ psum += instances[i].psum;
+ count += instances[i].count;
+#if 0
+ if (ioctl(instances[i].bpffd, BIOCGSTATS, &bs) < 0)
+ err(-1, "BIOCGSTATS");
+ recv += bs.bs_recv;
+ drop += bs.bs_drop;
+#endif
+ }
+
+ putchar('\n');
+ printf("%lu cycles spent processing packets\n", sum);
+ printf("%lu cycles spent in a syscall after wakeup\n", rsum);
+ printf("%lu cycles spent not sleeping\n", ssum);
+ printf("%lu cycles spent before buffer reclaims\n", psum);
+ printf("%lu packets processed\n", count);
+ throughput = (wrote * 8) / 60;
+ printf("wrote:%f MB throughput:%f Mbps\n",
+ wrote, throughput);
+
+#if 0
+ printf("%u packets received (BPF)\n", recv);
+ printf("%u packets dropped (BPF)\n", drop);
+#endif
+
+ exit(0);
+}
-int bpf_thread(struct bpf_thread_instance *instance)
+u_int64_t
+rdtsc(void)
{
- char filename[50];
- int bpf, b;
- int flag = 1, sz;
- char *rbuf;
- int rbuf_offset = 0;
- int rbuf_len = 0;
- int length = 0;
- struct bpf_hdr *hdr;
- struct ifreq ifr;
+ u_int32_t high, low;
+
+ __asm __volatile("rdtsc" : "=a" (low), "=d" (high));
+ return (low | ((u_int64_t) high << 32));
+}
- ifr.ifr_addr.sa_family = AF_LOCAL;
- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+/*
+#define CACHE_LINE_SIZE 32
+*/
- CPU_ZERO(&instance->cpuset);
- CPU_SET(instance->cpu, &instance->cpuset);
- cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1,
- sizeof(cpuset_t), &instance->cpuset);
+static void
+bpf_process_packets(struct bpf_thread_instance *instance, struct bpf_zbuf *bz, char *bufname)
+{
+ int clen, hlen, i;
+ u_char *b,*bp, *ep, *p, by;
+#define bhp ((struct bpf_hdr *)bp)
- snprintf(filename, sizeof(filename), CAP_FORMAT, instance->cpu);
- instance->fd = open(filename, O_RDWR | O_CREAT);
- if (instance->fd < 0) {
- perror("open");
- return instance->fd;
+ b = bp = bz->bz_bufa;
+ ep = bp + bz->bz_buflen;
+ while (bp < ep) {
+ instance->count++;
+ if (pflag) {
+ /*
+ * XXXCSJP this prefetch method needs to be
+ * re-visted
+ */
+ __builtin_prefetch(bp + bhp->bh_datalen, 0, 3);
+ }
+ clen = bhp->bh_caplen;
+ hlen = bhp->bh_hdrlen;
+ if (Tflag) {
+ for (i = 0; i < bhp->bh_datalen; i++)
+ by = p[i];
+ bp += BPF_WORDALIGN(clen + hlen);
+ continue;
+ }
+ instance->wrote += bhp->bh_caplen;
+ bp += BPF_WORDALIGN(clen + hlen);
}
- /* Open a BPF device */
- for (b = 0; 1; b++) {
- snprintf(filename, sizeof(filename), BPF_FORMAT, b);
- bpf = open(filename, O_RDWR, 0);
- if (bpf < 0) {
- if (errno == EBUSY)
- continue;
- else {
- perror("open");
- return bpf;
+}
+
+static void
+bpf_wait_for_fullbuf(struct bpf_thread_instance *instance)
+{
+ fd_set s_set, r_set;
+ struct bpf_zbuf bz;
+ char *pbuf;
+ int n;
+ struct bpf_zbuf_header *bzha, *bzhb;
+ struct timeval tv;
+ void *prev2, *prev;
+ u_int64_t b, a, c, d, e, f;
+
+ prev2 = prev = NULL;
+ pbuf = malloc(bflag + 1);
+ if (pbuf == NULL)
+ err(1, "malloc");
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ FD_SET(instance->bpffd, &s_set);
+ for (;;) {
+ r_set = s_set;
+ n = select(instance->bpffd + 1, &r_set, NULL, NULL, &tv);
+ e = rdtsc();
+ if (n < 0) {
+ fprintf(stderr,"owned by select\n");
+ err(1, "select failed");
+ }
+ if (vflag)
+ (void) fprintf(stderr, "select wakeup\n");
+ if (n != 0 && !FD_ISSET(instance->bpffd, &r_set) && vflag)
+ printf("No timeout and fd is not ready!\n");
+#ifdef BPF_BUFMODE_ZBUF
+ if (zflag == 0) {
+#endif
+ c = rdtsc();
+ n = read(instance->bpffd, pbuf, bflag);
+ d = rdtsc();
+ if (n < 0)
+// err(1, "read failed");
+ fprintf(stderr, "read failed");
+ instance->psum += d - e;
+ instance->rsum += d - c;
+ bz.bz_bufa = pbuf;
+ bz.bz_buflen = n;
+ b = rdtsc();
+ bpf_process_packets(instance, &bz, "W");
+ a = rdtsc();
+ instance->sum += a - b;
+#ifdef BPF_BUFMODE_ZBUF
+ } else {
+ bzha = (struct bpf_zbuf_header *)instance->bufa;
+ bzhb = (struct bpf_zbuf_header *)instance->bufb;
+ if (n == 0) {
+ c = rdtsc();
+ if (ioctl(instance->bpffd, BIOCROTZBUF, &bz) < 0)
+ err(1, "ioctl");
+ d = rdtsc();
+ instance->rsum += d - c;
+ if (bz.bz_bufa == NULL) {
+ if (vflag)
+ printf("timeout no data\n");
+ continue;
+ }
+ }
+ assert(bzha->bzh_kernel_gen > bzha->bzh_user_gen ||
+ bzhb->bzh_kernel_gen > bzhb->bzh_user_gen);
+ if (bzha->bzh_kernel_gen > bzha->bzh_user_gen) {
+ bz.bz_bufa = instance->bufa;
+ bz.bz_bufa += sizeof(struct bpf_zbuf_header);
+ bz.bz_buflen = bzha->bzh_kernel_len;
+ b = rdtsc();
+ bpf_process_packets(instance, &bz, "A");
+ a = rdtsc();
+ instance->sum += a - b;
+ instance->psum += a - e;
+ bzha->bzh_user_gen++;
+ } else if (bzhb->bzh_kernel_gen > bzhb->bzh_user_gen) {
+ bz.bz_bufa = instance->bufb;
+ bz.bz_bufa += sizeof(struct bpf_zbuf_header);
+ bz.bz_buflen = bzhb->bzh_kernel_len;
+ b = rdtsc();
+ bpf_process_packets(instance, &bz, "B");
+ a = rdtsc();
+ instance->sum += a - b;
+ instance->psum += a - e;
+ bzhb->bzh_user_gen++;
}
- } else
+ }
+#endif
+ f = rdtsc();
+ instance->ssum += f - e;
+ }
+}
+
+int
+bpf_open(void)
+{
+ char buf[32];
+ int i, ret;
+
+ for (i = 0; i < 8; i++) {
+ snprintf(buf, sizeof(buf), "/dev/bpf%d", i);
+ ret = open(buf, O_RDWR);
+ if (ret != -1)
break;
+ else if (errno != EBUSY)
+ (void) fprintf(stderr, "open %s: %s\n",
+ buf, strerror(errno));
}
+ return (ret);
+}
+
+void
+usage()
+{
+
+ (void) fprintf(stderr, "usage: bpfnull [-ipPTwvz] [-b bufsize] "
+ "[-c limit] [-f file] -i interface\n");
+ exit(0);
+}
+
+#ifdef BPF_BUFMODE_ZBUF
+static int
+bpf_zbuf_init(struct bpf_thread_instance *instance, struct bpf_zbuf *bz)
+{
+ int bmode;
+ u_int zbufmax;
- /* Set the BPF device to point at this interface. */
- if (ioctl(bpf, BIOCSETIF, &ifr) < 0) {
- perror("SETIF");
- return -1;
+ if ((bflag % getpagesize()) != 0)
+ errx(1, "-b must be multiple of system page size");
+ bz->bz_buflen = bflag;
+ instance->bufa = mmap(NULL, bz->bz_buflen, PROT_READ | PROT_WRITE,
+ MAP_ANON, -1, 0);
+ if (instance->bufa == MAP_FAILED)
+ err(1, "mmap(bufa)");
+ instance->bufb = mmap(NULL, bz->bz_buflen, PROT_READ | PROT_WRITE,
+ MAP_ANON, -1, 0);
+ if (instance->bufb == MAP_FAILED)
+ err(1, "mmap(bufb)");
+ bz->bz_bufa = instance->bufa;
+ bz->bz_bufb = instance->bufb;
+ bmode = BPF_BUFMODE_ZBUF;
+ if (ioctl(instance->bpffd, BIOCSETBUFMODE, &bmode) < 0)
+ err(1, "ioctl(BIOCGSETBUFMODE)");
+ if (ioctl(instance->bpffd, BIOCGETZMAX, (caddr_t)&zbufmax) < 0) {
+ err(1, "ioctl(BIOCGETZMAX)");
+ }
+ if (bz->bz_buflen > zbufmax) {
+ printf("zbufmax is smaller than buflen:%d\n", zbufmax);
}
+ if (ioctl(instance->bpffd, BIOCSETZBUF, bz) < 0)
+ err(1, "ioctl(BIOCSETZBUF)");
+ if (vflag)
+ (void) fprintf(stderr,
+ "DEBUG: bufa=%p bufb=%p\n", instance->bufa, instance->bufb);
+ return (0);
+}
+#endif
+
+static int
+bpf_rbuf_init(struct bpf_thread_instance *instance)
+{
+ int v, bmode;
- /*
- * Set immediate mode so that reads return as soon as a packet
- * comes in, rather than waiting for the input buffer to fill
- * with packets.
- */
- if (ioctl(bpf, BIOCIMMEDIATE, &flag) < 0) {
- perror("IMMEDIATE");
- return -1;
+#ifdef BPF_BUFMODE_ZBUF
+ bmode = BPF_BUFMODE_BUFFER;
+
+ if (ioctl(instance->bpffd, BIOCGETBUFMODE, &bmode) < 0)
+ err(1, "ioctl(BIOCGETBUFMODE)");
+#endif
+ for (v = bflag; v != 0; v >>= 1) {
+ (void) ioctl(instance->bpffd, BIOCSBLEN, &v);
+ if (ioctl(instance->bpffd, BIOCSETIF, &ifr) == 0)
+ break;
}
+ if (ioctl(instance->bpffd, BIOCFLUSH, NULL) < 0)
+ err(1, "ioctl(BIOCFLUSH)");
+ return (0);
+}
- /* Get the required BPF buffer length from the kernel. */
- if (ioctl(bpf, BIOCGBLEN, &sz) < 0) {
- perror("BLEN");
- return -1;
+int bpf_thread(struct bpf_thread_instance *instance)
+{
+ struct bpf_zbuf bz;
+ struct ifreq ifr;
+ int opt;
+
+ CPU_ZERO(&instance->cpuset);
+ CPU_SET(instance->cpu, &instance->cpuset);
+ cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1,
+ sizeof(cpuset_t), &instance->cpuset);
+
+ bzero(&ifr, sizeof(ifr));
+ strlcpy(ifr.ifr_name, iflag, sizeof(ifr.ifr_name));
+ instance->bpffd = bpf_open();
+ if (instance->bpffd == -1) {
+ (void) fprintf(stderr, "bpfnull: no bpf device available\n");
+ exit(1);
+ }
+ if (vflag)
+ (void) fprintf(stderr,
+ "DEBUG: obtained bpf fd=%d\n", instance->bpffd);
+#ifdef BPF_BUFMODE_ZBUF
+ if (zflag) {
+ if (vflag)
+ (void) fprintf(stderr,
+ "DEBUG: bufmode=zerocopy\n");
+ bzero(&bz, sizeof(bz));
+ bpf_zbuf_init(instance, &bz);
+ if (ioctl(instance->bpffd, BIOCSETIF, &ifr) < 0)
+ err(1, "ioctl(BIOCSETIF)");
+ } else {
+#endif
+ if (vflag)
+ (void) fprintf(stderr,
+ "DEBUG: bufmode=buffer\n");
+ bpf_rbuf_init(instance);
+#ifdef BPF_BUFMODE_ZBUF
+ }
+#endif
+ if (Iflag) {
+ if (vflag)
+ (void) fprintf(stderr,
+ "DEBUG: setting BIOCIMMEDIATE\n");
+ opt = 1;
+ if (ioctl(instance->bpffd, BIOCIMMEDIATE, &opt) < 0)
+ err(1, "BIOCIMMEDIATE");
}
- rbuf = malloc(sz);
- if (!rbuf) {
- perror("malloc");
- return -1;
+ if (Pflag) {
+ if (vflag)
+ (void) fprintf(stderr,
+ "DEBUG: putting card into promiscuous "
+ "mode\n");
+ if (ioctl(instance->bpffd, BIOCPROMISC, NULL) < 0)
+ err(1, "BIOCPROMISC");
}
+ if (vflag)
+ (void) fprintf(stderr,
+ "DEBUG: attaching to %s\n", iflag);
- if (ioctl(bpf, BIOCENAQMASK, NULL) < 0) {
+ if (ioctl(instance->bpffd, BIOCENAQMASK, NULL) < 0) {
perror("enable qmask");
return -1;
}
if (instance->rxqueue > -1) {
- if (ioctl(bpf, BIOCSTRXQMASK, &instance->rxqueue) < 0) {
+ if (ioctl(instance->bpffd, BIOCSTRXQMASK, &instance->rxqueue) < 0) {
perror("rx qmask");
return -1;
}
}
if (instance->txqueue > -1) {
- if (ioctl(bpf, BIOCSTTXQMASK, &instance->txqueue) < 0) {
+ if (ioctl(instance->bpffd, BIOCSTTXQMASK, &instance->txqueue) < 0) {
perror("tx qmask");
return -1;
}
}
if (instance->other > -1) {
- if (ioctl(bpf, BIOCSTOTHERMASK, &instance->other) < 0) {
+ if (ioctl(instance->bpffd, BIOCSTOTHERMASK, &instance->other) < 0) {
perror("other qmask");
return -1;
}
@@ -185,96 +461,18 @@
instance->wrote = 0;
- while(1) {
- /* If the buffer is empty, fill it. */
- if (rbuf_offset >= rbuf_len) {
- length = read(bpf, rbuf,
- sz);
- if (length < 0) {
- perror("read");
- return length;
- }
- rbuf_offset = 0;
- rbuf_len = length;
- }
- /*
- * If there isn't room for a whole bpf header, something
- * went wrong, but we'll ignore it and hope it goes
- * away... XXX
- */
- if (rbuf_len - rbuf_offset <
- sizeof(struct bpf_hdr)) {
- rbuf_offset = rbuf_len;
- printf("rbuf_len - rbuf_offset < sizeof(struct bpf_hdr)\n");
- continue;
- }
-
- hdr = (struct bpf_hdr *)&rbuf[rbuf_offset];
-
- /*
- * If the bpf header plus data doesn't fit in what's
- * left of the buffer, stick head in sand yet again...
- */
- if (rbuf_offset + hdr->bh_hdrlen + hdr->bh_caplen >
- rbuf_len) {
- rbuf_offset = rbuf_len;
- printf("rbuf_offset + hdr->bh_hdrlen + hdr->bh_caplen > rbuf_len\n");
- continue;
- }
-
- /* Skip over the BPF header... */
- rbuf_offset += hdr->bh_hdrlen;
-
- /*
- * If the captured data wasn't the whole packet, or if
- * the packet won't fit in the input buffer, all we can
- * do is drop it.
- */
- if (hdr->bh_caplen != hdr->bh_datalen) {
- rbuf_offset =
- BPF_WORDALIGN(rbuf_offset +
- hdr->bh_caplen);
- printf("hdr->bh_caplen != hdr->bh_datalen\n");
- continue;
- }
-
- /* Copy out the data in the packet... */
- write(instance->fd, rbuf + rbuf_offset, hdr->bh_caplen);
- instance->wrote += hdr->bh_caplen;
- rbuf_offset =
- BPF_WORDALIGN(rbuf_offset +
- hdr->bh_caplen);
- }
+ bpf_wait_for_fullbuf(instance);
return 0;
}
-static void timer_handler(int arg)
+int
+main(int argc, char *argv[])
{
- struct timeval curr;
- time_t sec;
- int i, ret;
- uint32_t wrote = 0;
-
- for (i = 0; i < (rxqlen + txqlen + 1); i++) {
- pthread_cancel(instances[i].thread);
- pthread_join(instances[i].thread, (void **)&ret);
- wrote += instances[i].wrote;
- }
- gettimeofday(&curr, NULL);
- sec = curr.tv_sec - start.tv_sec;
- wrote /= (1024 * 1024);
- printf("sec:%ld wrote:%d MB thoughput:%f MB/s\n",
- sec, wrote, (double)wrote / (double)sec);
- exit(0);
-}
-
-int main(int argc, char **argv)
-{
- struct ifreq ifr;
- int i, s, ret, maxcpus;
+ char ch;
+ int i, s, maxcpus;
struct sigaction action = {
- .sa_handler = timer_handler,
+ .sa_handler = (void (*)(int))handle_int,
.sa_flags = 0
};
struct itimerval timer = {
@@ -288,14 +486,53 @@
}
};
- if (argc < 2) {
- printf("usage: %s [ifname]\n", argv[0]);
+ sigemptyset(&action.sa_mask);
+ if (sigaction(SIGALRM, &action, NULL) < 0) {
+ perror("sigaction");
+ return -1;
+ }
+ if (setitimer(ITIMER_REAL, &timer, NULL) < 0) {
+ perror("setitimer");
return -1;
}
-
- ifname = argv[1];
+ signal(SIGINT, (void *)handle_int);
+ while ((ch = getopt(argc, argv, "b:c:f:hIi:pPTwvz")) != -1) {
+ switch (ch) {
+ case 'b':
+ bflag = atoi(optarg);
+ break;
+ case 'i':
+ iflag = optarg;
+ break;
+ case 'I':
+ Iflag = 1;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'P':
+ Pflag = 1;
+ break;
+ case 'T':
+ Tflag = 1;
+ break;
+ case 'v':
+ vflag++;
+ break;
+#ifdef BPF_BUFMODE_ZBUF
+ case 'z':
+ zflag++;
+ break;
+#endif
+ default:
+ usage();
+ }
+ }
+ if (iflag == NULL)
+ usage();
+
ifr.ifr_addr.sa_family = AF_LOCAL;
- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ strncpy(ifr.ifr_name, iflag, sizeof(ifr.ifr_name));
s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
if (s < 0) {
perror("socket");
@@ -314,18 +551,6 @@
instances = (struct bpf_thread_instance *)
calloc(maxcpus, sizeof(struct bpf_thread_instance));
- sigemptyset(&action.sa_mask);
- if (sigaction(SIGALRM, &action, NULL) < 0) {
- perror("sigaction");
- return -1;
- }
- if (setitimer(ITIMER_REAL, &timer, NULL) < 0) {
- perror("setitimer");
- return -1;
- }
-
- gettimeofday(&start, NULL);
-
for (i = 0; i < maxcpus; i++) {
instances[i].cpu = i;
instances[i].rxqueue = -1;
@@ -358,7 +583,7 @@
(void *(*)(void *))bpf_thread, &instances[i]);
for (i = 0; i < maxcpus; i++)
- pthread_join(instances[i].thread, (void **)&ret);
+ pthread_join(instances[i].thread, NULL);
- return 0;
+ return (0);
}
==== //depot/projects/soc2011/mq_bpf/src/tools/regression/bpf/mq_bpf/test_sqbpf/Makefile#2 (text+ko) ====
@@ -1,5 +1,7 @@
PROG= test_sqbpf
SRCS+= test_sqbpf.c
+DPADD= ${LIBPCAP}
+LDADD= -lpcap
NO_MAN=
.include <bsd.prog.mk>
==== //depot/projects/soc2011/mq_bpf/src/tools/regression/bpf/mq_bpf/test_sqbpf/test_sqbpf.c#2 (text+ko) ====
@@ -1,101 +1,377 @@
-/* $OpenBSD: bpf.c,v 1.13 2004/05/05 14:28:58 deraadt Exp $ */
-
-/* BPF socket interface code, originally contributed by Archie Cobbs. */
-
-/*
- * Copyright (c) 1995, 1996, 1998, 1999
- * The Internet Software Consortium. All rights reserved.
+/*-
+ * Copyright (c) 2007 Seccuris Inc.
+ * Copyright (c) 2007 Christian S.J. Peron
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- *
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
*/
-
#include <sys/types.h>
-#include <sys/cdefs.h>
+#include <sys/time.h>
#include <sys/ioctl.h>
-#include <sys/uio.h>
+#include <sys/select.h>
#include <sys/socket.h>
-#include <sys/time.h>
+#include <sys/mman.h>
+
#include <net/bpf.h>
-#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
-#include <netinet/udp.h>
-#include <netinet/if_ether.h>
+#include <net/if.h>
+#include <net/ethernet.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
+#include <signal.h>
#include <err.h>
-#include <signal.h>
+#include <pcap.h>
+#include <assert.h>
+
+int bpf_open(void);
+void usage(void);
+u_int64_t sum; /* cycles spent processing packet data */
+u_int64_t rsum; /* cycles spent in syscalls after wakeup */
+u_int64_t ssum; /* cycles spent not sleep in event loop */
+u_int64_t psum; /* cycles spent before buffer can be reclaimed */
+
+static struct ifreq ifr;
+static pcap_dumper_t *dp;
+static pcap_t *p;
+static int bpffd = -1;
+static char *fflag = "-";
+static unsigned long cflag;
+static int Iflag;
+static char *iflag;
+static int bflag = 32768;
+static int wflag;
+static int vflag;
+static int zflag;
+static int Tflag;
+static int pflag;
+static int Pflag;
+
+static u_char *bufa, *bufb;
+static unsigned long packet_count;
+static unsigned long packet_wrote;
+
+#ifndef BPF_BUFMODE_ZBUF
+/*
+ * bpfnull uses certain constructs that depend on zero-copy definitions being
+ * present in bpf.h even when running in normal buffer mode. If the system
+ * doesn't have these constructs, define them locally.
+ */
+struct bpf_zbuf {
+ void *bz_bufa;
+ void *bz_bufb;
+ size_t bz_buflen;
+};
+#warning "BPF_BUFMODE_ZBUF not present, building without zero-copy support"
+#endif
+
+static int
+handle_int(int sig __unused)
+{
+ struct bpf_stat bs;
+ double wrote, throughput;
+
+ putchar('\n');
+ printf("%lu cycles spent processing packets\n", sum);
+ printf("%lu cycles spent in a syscall after wakeup\n", rsum);
+ printf("%lu cycles spent not sleeping\n", ssum);
+ printf("%lu cycles spent before buffer reclaims\n", psum);
+ printf("%lu packets processed\n", packet_count);
+ wrote = (double)packet_wrote / (double)(1024 * 1024);
+ throughput = (wrote * 8) / 60;
+ printf("wrote:%f MB throughput:%f Mbps\n",
+ wrote, throughput);
+ if (ioctl(bpffd, BIOCGSTATS, &bs) < 0)
+ err(-1, "BIOCGSTATS");
+
+ printf("%u packets received (BPF)\n", bs.bs_recv);
+ printf("%u packets dropped (BPF)\n", bs.bs_drop);
+
+ exit(0);
+}
+
+u_int64_t
+rdtsc(void)
+{
+ u_int32_t high, low;
+
+ __asm __volatile("rdtsc" : "=a" (low), "=d" (high));
+ return (low | ((u_int64_t) high << 32));
+}
+
+static void
+bpf_init_dumpfile(void)
+{
+
+ if (wflag == 0)
+ return;
+ p = pcap_open_dead(DLT_EN10MB, 0xffffU);
+ dp = pcap_dump_open(p, fflag);
+ if (dp == NULL) {
+ pcap_perror(p, fflag);
+ exit(1);
+ }
+}
+
+#define CACHE_LINE_SIZE 32
+
+static void
+bpf_process_packets(struct bpf_zbuf *bz, char *bufname)
+{
+ struct pcap_pkthdr phd;
+ int clen, hlen, i;
+ u_char *b,*bp, *ep, *p, by;
+#define bhp ((struct bpf_hdr *)bp)
+
+ b = bp = bz->bz_bufa;
+ ep = bp + bz->bz_buflen;
+ while (bp < ep) {
+ packet_count++;
+ if (cflag > 0 && packet_count > cflag)
+ exit(0);
+ if (pflag) {
+ /*
+ * XXXCSJP this prefetch method needs to be
+ * re-visted
+ */
+ __builtin_prefetch(bp + bhp->bh_datalen, 0, 3);
+ }
+ clen = bhp->bh_caplen;
+ hlen = bhp->bh_hdrlen;
+ p = (u_char *)bp + hlen;
+ phd.ts.tv_sec = bhp->bh_tstamp.tv_sec;
+ phd.ts.tv_usec = bhp->bh_tstamp.tv_usec;
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list