From owner-p4-projects@FreeBSD.ORG Wed Aug 3 14:00:57 2011 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id BA8911065675; Wed, 3 Aug 2011 14:00:57 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 7D08F1065673 for ; Wed, 3 Aug 2011 14:00:57 +0000 (UTC) (envelope-from syuu@FreeBSD.org) Received: from skunkworks.freebsd.org (skunkworks.freebsd.org [IPv6:2001:4f8:fff6::2d]) by mx1.freebsd.org (Postfix) with ESMTP id 69BCC8FC14 for ; Wed, 3 Aug 2011 14:00:57 +0000 (UTC) Received: from skunkworks.freebsd.org (localhost [127.0.0.1]) by skunkworks.freebsd.org (8.14.4/8.14.4) with ESMTP id p73E0vQa072467 for ; Wed, 3 Aug 2011 14:00:57 GMT (envelope-from syuu@FreeBSD.org) Received: (from perforce@localhost) by skunkworks.freebsd.org (8.14.4/8.14.4/Submit) id p73E0vDY072462 for perforce@freebsd.org; Wed, 3 Aug 2011 14:00:57 GMT (envelope-from syuu@FreeBSD.org) Date: Wed, 3 Aug 2011 14:00:57 GMT Message-Id: <201108031400.p73E0vDY072462@skunkworks.freebsd.org> X-Authentication-Warning: skunkworks.freebsd.org: perforce set sender to syuu@FreeBSD.org using -f From: Takuya ASADA To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 197135 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 03 Aug 2011 14:00:58 -0000 http://p4web.freebsd.org/@@197135?ac=10 Change 197135 by syuu@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 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 -#include +#include #include -#include +#include #include -#include +#include #include #include -#include + #include -#include #include #include #include -#include -#include +#include +#include #include +#include +#include +#include #include #include -#include -#include -#include +#include #include +#include #include -#include - -#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 ==== //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 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 -#include +#include #include -#include +#include #include -#include +#include + #include -#include #include #include #include -#include -#include +#include +#include #include +#include +#include +#include #include #include -#include -#include -#include +#include #include -#include +#include +#include + +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) <<<