bool netmap_tx_queues_empty(void *p) { sendpacket_t *sp = p; struct netmap_ring *txring; assert(sp); txring = NETMAP_TXRING(sp->nm_if, sp->cur_tx_ring); while (NETMAP_TX_RING_EMPTY(txring)) { /* current ring is empty- go to next */ ++sp->cur_tx_ring; if (sp->cur_tx_ring > sp->last_tx_ring) /* last ring */ return true; txring = NETMAP_TXRING(sp->nm_if, sp->cur_tx_ring); } /* * send TX interrupt signal */ ioctl(sp->handle.fd, NIOCTXSYNC, NULL); return false; }
int sendpacket_send_netmap(void *p, const u_char *data, size_t len) { sendpacket_t *sp = p; struct netmap_ring *txring; struct netmap_slot *slot; char *pkt; uint32_t cur, avail; if (sp->abort) return 0; txring = NETMAP_TXRING(sp->nm_if, sp->cur_tx_ring); while ((avail = nm_ring_space(txring)) == 0) { /* out of space on current TX queue - go to next */ ++sp->cur_tx_ring; if (sp->cur_tx_ring > sp->last_tx_ring) { /* * out of space on all queues * * we have looped through all configured TX queues * so we have to reset to the first queue and * wait for available space */ sp->cur_tx_ring = sp->first_tx_ring; /* send TX interrupt signal * * On Linux this makes one slot free on the * ring, which increases speed by about 10Mbps. * * But it will never free up all the slots. For * that we must poll and call again. */ ioctl(sp->handle.fd, NIOCTXSYNC, NULL); /* loop again */ return -2; } txring = NETMAP_TXRING(sp->nm_if, sp->cur_tx_ring); } /* * send */ cur = txring->cur; slot = &txring->slot[cur]; slot->flags = 0; pkt = NETMAP_BUF(txring, slot->buf_idx); memcpy(pkt, data, min(len, txring->nr_buf_size)); slot->len = len; if (avail <= 1) slot->flags = NS_REPORT; dbgx(3, "netmap cur=%d slot index=%d flags=0x%x empty=%d avail=%u bufsize=%d\n", cur, slot->buf_idx, slot->flags, NETMAP_TX_RING_EMPTY(txring), nm_ring_space(txring), txring->nr_buf_size); /* let kernel know that packet is available */ cur = NETMAP_RING_NEXT(txring, cur); #ifdef HAVE_NETMAP_RING_HEAD_TAIL txring->head = cur; #else txring->avail--; #endif txring->cur = cur; return len; }
int sendpacket_send_netmap(void *p, const u_char *data, size_t len) { int retcode = 0; sendpacket_t *sp = p; struct netmap_ring *txring; struct netmap_slot *slot; char *pkt; uint32_t cur, avail; if (sp->abort) return retcode; txring = NETMAP_TXRING(sp->nm_if, sp->cur_tx_ring); while ((avail = nm_ring_space(txring)) == 0) { /* out of space on current TX queue - go to next */ ++sp->cur_tx_ring; if (sp->cur_tx_ring > sp->last_tx_ring) { /* * out of space on all queues * * we have looped through all configured TX queues * so we have to reset to the first queue and * wait for available space */ struct pollfd pfd; sp->cur_tx_ring = sp->first_tx_ring; /* send TX interrupt signal * * On Linux this makes one slot free on the * ring, which increases speed by about 10Mbps. * * But it will never free up all the slots. For * that we must poll and call again. */ ioctl(sp->handle.fd, NIOCTXSYNC, NULL); pfd.fd = sp->handle.fd; pfd.events = POLLOUT; pfd.revents = 0; if (poll(&pfd, 1, 1000) <= 0) { if (++sp->tx_timeouts == NETMAP_TX_TIMEOUT_SEC) { return -1; } return -2; } sp->tx_timeouts = 0; /* * Do not remove this even though it looks redundant. * Overall performance is increased with this restart * of the TX queue. * * This call increases the number of available slots from * 1 to all that are truly available. */ ioctl(sp->handle.fd, NIOCTXSYNC, NULL); } txring = NETMAP_TXRING(sp->nm_if, sp->cur_tx_ring); } /* * send */ cur = txring->cur; slot = &txring->slot[cur]; slot->flags = 0; pkt = NETMAP_BUF(txring, slot->buf_idx); memcpy(pkt, data, min(len, txring->nr_buf_size)); slot->len = len; if (avail <= 1) slot->flags = NS_REPORT; dbgx(3, "netmap cur=%d slot index=%d flags=0x%x empty=%d avail=%u bufsize=%d\n", cur, slot->buf_idx, slot->flags, NETMAP_TX_RING_EMPTY(txring), nm_ring_space(txring), txring->nr_buf_size); /* let kernel know that packet is available */ cur = NETMAP_RING_NEXT(txring, cur); #ifdef HAVE_NETMAP_RING_HEAD_TAIL txring->head = cur; #else txring->avail--; #endif txring->cur = cur; retcode = len; return retcode; }
static void * sender_body(void *data) { struct targ *targ = (struct targ *) data; struct pollfd fds[1]; struct netmap_if *nifp = targ->nifp; struct netmap_ring *txring; int i, n = targ->g->npackets / targ->g->nthreads, sent = 0; int options = targ->g->options | OPT_COPY; D("start"); if (setaffinity(targ->thread, targ->affinity)) goto quit; /* setup poll(2) mechanism. */ memset(fds, 0, sizeof(fds)); fds[0].fd = targ->fd; fds[0].events = (POLLOUT); /* main loop.*/ gettimeofday(&targ->tic, NULL); if (targ->g->use_pcap) { int size = targ->g->pkt_size; void *pkt = &targ->pkt; pcap_t *p = targ->g->p; for (i = 0; n == 0 || sent < n; i++) { if (pcap_inject(p, pkt, size) != -1) sent++; if (i > 10000) { targ->count = sent; i = 0; } } } else { while (n == 0 || sent < n) { /* * wait for available room in the send queue(s) */ if (poll(fds, 1, 2000) <= 0) { D("poll error/timeout on queue %d", targ->me); goto quit; } /* * scan our queues and send on those with room */ if (options & OPT_COPY && sent > 100000 && !(targ->g->options & OPT_COPY) ) { D("drop copy"); options &= ~OPT_COPY; } for (i = targ->qfirst; i < targ->qlast; i++) { int m, limit = targ->g->burst; if (n > 0 && n - sent < limit) limit = n - sent; txring = NETMAP_TXRING(nifp, i); if (txring->avail == 0) continue; m = send_packets(txring, &targ->pkt, targ->g->pkt_size, limit, options); sent += m; targ->count = sent; } } /* flush any remaining packets */ ioctl(fds[0].fd, NIOCTXSYNC, NULL); /* final part: wait all the TX queues to be empty. */ for (i = targ->qfirst; i < targ->qlast; i++) { txring = NETMAP_TXRING(nifp, i); while (!NETMAP_TX_RING_EMPTY(txring)) { ioctl(fds[0].fd, NIOCTXSYNC, NULL); usleep(1); /* wait 1 tick */ } } } gettimeofday(&targ->toc, NULL); targ->completed = 1; targ->count = sent; quit: /* reset the ``used`` flag. */ targ->used = 0; return (NULL); }