aboutsummaryrefslogtreecommitdiff
path: root/tools/tools/netmap/pkt-gen.c
diff options
context:
space:
mode:
authorLuigi Rizzo <luigi@FreeBSD.org>2012-05-03 15:37:05 +0000
committerLuigi Rizzo <luigi@FreeBSD.org>2012-05-03 15:37:05 +0000
commit99fb123f8d95c80945aba9f7599519f5ea3bb054 (patch)
tree035b1b772dae9fb0317c484bc12bd7b83c8fe15f /tools/tools/netmap/pkt-gen.c
parentdf76012c5b5971cb196d4ea779904117712a8396 (diff)
downloadsrc-99fb123f8d95c80945aba9f7599519f5ea3bb054.tar.gz
src-99fb123f8d95c80945aba9f7599519f5ea3bb054.zip
Notes
Diffstat (limited to 'tools/tools/netmap/pkt-gen.c')
-rw-r--r--tools/tools/netmap/pkt-gen.c133
1 files changed, 108 insertions, 25 deletions
diff --git a/tools/tools/netmap/pkt-gen.c b/tools/tools/netmap/pkt-gen.c
index 43eeda86e159..e651a971be2f 100644
--- a/tools/tools/netmap/pkt-gen.c
+++ b/tools/tools/netmap/pkt-gen.c
@@ -25,7 +25,7 @@
/*
* $FreeBSD$
- * $Id: pkt-gen.c 10637 2012-02-24 16:36:25Z luigi $
+ * $Id: pkt-gen.c 10967 2012-05-03 11:29:23Z luigi $
*
* Example program to show how to build a multithreaded packet
* source/sink using the netmap device.
@@ -90,6 +90,36 @@ int verbose = 0;
#define SKIP_PAYLOAD 1 /* do not check payload. */
+inline void prefetch (const void *x)
+{
+ __asm volatile("prefetcht0 %0" :: "m" (*(const unsigned long *)x));
+}
+
+// XXX only for multiples of 32 bytes, non overlapped.
+static inline void
+pkt_copy(void *_src, void *_dst, int l)
+{
+ uint64_t *src = _src;
+ uint64_t *dst = _dst;
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+ if (unlikely(l >= 1024)) {
+ bcopy(src, dst, l);
+ return;
+ }
+ for (; l > 0; l-=64) {
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ }
+}
+
+
#if EXPERIMENTAL
/* Wrapper around `rdtsc' to take reliable timestamps flushing the pipeline */
#define netmap_rdtsc(t) \
@@ -140,6 +170,11 @@ struct glob_arg {
int npackets; /* total packets to send */
int nthreads;
int cpus;
+ int options; /* testing */
+#define OPT_PREFETCH 1
+#define OPT_ACCESS 2
+#define OPT_COPY 4
+#define OPT_MEMCPY 8
int use_pcap;
pcap_t *p;
};
@@ -394,19 +429,35 @@ check_payload(char *p, int psize)
*/
static int
send_packets(struct netmap_ring *ring, struct pkt *pkt,
- int size, u_int count, int fill_all)
+ int size, u_int count, int options)
{
u_int sent, cur = ring->cur;
if (ring->avail < count)
count = ring->avail;
+#if 0
+ if (options & (OPT_COPY | OPT_PREFETCH) ) {
+ for (sent = 0; sent < count; sent++) {
+ struct netmap_slot *slot = &ring->slot[cur];
+ char *p = NETMAP_BUF(ring, slot->buf_idx);
+
+ prefetch(p);
+ cur = NETMAP_RING_NEXT(ring, cur);
+ }
+ cur = ring->cur;
+ }
+#endif
for (sent = 0; sent < count; sent++) {
struct netmap_slot *slot = &ring->slot[cur];
char *p = NETMAP_BUF(ring, slot->buf_idx);
- if (fill_all)
+ if (options & OPT_COPY)
+ pkt_copy(pkt, p, size);
+ else if (options & OPT_MEMCPY)
memcpy(p, pkt, size);
+ else if (options & OPT_PREFETCH)
+ prefetch(p);
slot->len = size;
if (sent == count - 1)
@@ -428,8 +479,8 @@ sender_body(void *data)
struct netmap_if *nifp = targ->nifp;
struct netmap_ring *txring;
int i, n = targ->g->npackets / targ->g->nthreads, sent = 0;
- int fill_all = 1;
-
+ int options = targ->g->options | OPT_COPY;
+D("start");
if (setaffinity(targ->thread, targ->affinity))
goto quit;
/* setup poll(2) mechanism. */
@@ -444,9 +495,13 @@ sender_body(void *data)
void *pkt = &targ->pkt;
pcap_t *p = targ->g->p;
- for (; sent < n; sent++) {
- if (pcap_inject(p, pkt, size) == -1)
- break;
+ for (i = 0; sent < n; i++) {
+ if (pcap_inject(p, pkt, size) != -1)
+ sent++;
+ if (i > 10000) {
+ targ->count = sent;
+ i = 0;
+ }
}
} else {
while (sent < n) {
@@ -461,8 +516,8 @@ sender_body(void *data)
/*
* scan our queues and send on those with room
*/
- if (sent > 100000)
- fill_all = 0;
+ if (sent > 100000 && !(targ->g->options & OPT_COPY) )
+ options &= ~OPT_COPY;
for (i = targ->qfirst; i < targ->qlast; i++) {
int m, limit = MIN(n - sent, targ->g->burst);
@@ -470,12 +525,12 @@ sender_body(void *data)
if (txring->avail == 0)
continue;
m = send_packets(txring, &targ->pkt, targ->g->pkt_size,
- limit, fill_all);
+ limit, options);
sent += m;
targ->count = sent;
}
}
- /* Tell the interface that we have new packets. */
+ /* flush any remaining packets */
ioctl(fds[0].fd, NIOCTXSYNC, NULL);
/* final part: wait all the TX queues to be empty. */
@@ -672,6 +727,7 @@ int
main(int arc, char **argv)
{
int i, fd;
+ char pcap_errbuf[PCAP_ERRBUF_SIZE];
struct glob_arg g;
@@ -696,12 +752,15 @@ main(int arc, char **argv)
g.cpus = 1;
while ( (ch = getopt(arc, argv,
- "i:t:r:l:d:s:D:S:b:c:p:T:w:v")) != -1) {
+ "i:t:r:l:d:s:D:S:b:c:o:p:PT:w:v")) != -1) {
switch(ch) {
default:
D("bad option %c %s", ch, optarg);
usage();
break;
+ case 'o':
+ g.options = atoi(optarg);
+ break;
case 'i': /* interface */
ifname = optarg;
break;
@@ -775,6 +834,26 @@ main(int arc, char **argv)
usage();
}
+ if (td_body == sender_body && g.src_mac == NULL) {
+ static char mybuf[20] = "ff:ff:ff:ff:ff:ff";
+ /* retrieve source mac address. */
+ if (source_hwaddr(ifname, mybuf) == -1) {
+ D("Unable to retrieve source mac");
+ // continue, fail later
+ }
+ g.src_mac = mybuf;
+ }
+
+ if (g.use_pcap) {
+ D("using pcap on %s", ifname);
+ g.p = pcap_open_live(ifname, 0, 1, 100, pcap_errbuf);
+ if (g.p == NULL) {
+ D("cannot open pcap on %s", ifname);
+ usage();
+ }
+ mmap_addr = NULL;
+ fd = -1;
+ } else {
bzero(&nmr, sizeof(nmr));
nmr.nr_version = NETMAP_API;
/*
@@ -811,16 +890,6 @@ main(int arc, char **argv)
// continue, fail later
}
- if (td_body == sender_body && g.src_mac == NULL) {
- static char mybuf[20] = "ff:ff:ff:ff:ff:ff";
- /* retrieve source mac address. */
- if (source_hwaddr(ifname, mybuf) == -1) {
- D("Unable to retrieve source mac");
- // continue, fail later
- }
- g.src_mac = mybuf;
- }
-
/*
* Map the netmap shared memory: instead of issuing mmap()
* inside the body of the threads, we prefer to keep this
@@ -869,8 +938,15 @@ main(int arc, char **argv)
D("aborting");
usage();
}
+ }
-
+ if (g.options) {
+ D("special options:%s%s%s%s\n",
+ g.options & OPT_PREFETCH ? " prefetch" : "",
+ g.options & OPT_ACCESS ? " access" : "",
+ g.options & OPT_MEMCPY ? " memcpy" : "",
+ g.options & OPT_COPY ? " copy" : "");
+ }
/* Wait for PHY reset. */
D("Wait %d secs for phy reset", wait_link);
sleep(wait_link);
@@ -881,7 +957,12 @@ main(int arc, char **argv)
signal(SIGINT, sigint_h);
if (g.use_pcap) {
- // XXX g.p = pcap_open_live(..);
+ g.p = pcap_open_live(ifname, 0, 1, 100, NULL);
+ if (g.p == NULL) {
+ D("cannot open pcap on %s", ifname);
+ usage();
+ } else
+ D("using pcap %p on %s", g.p, ifname);
}
targs = calloc(g.nthreads, sizeof(*targs));
@@ -1018,9 +1099,11 @@ main(int arc, char **argv)
rx_output(count, delta_t);
}
+ if (g.use_pcap == 0) {
ioctl(fd, NIOCUNREGIF, &nmr);
munmap(mmap_addr, nmr.nr_memsize);
close(fd);
+ }
return (0);
}