diff options
author | luigi <luigi@FreeBSD.org> | 2014-01-16 00:20:42 +0000 |
---|---|---|
committer | luigi <luigi@FreeBSD.org> | 2014-01-16 00:20:42 +0000 |
commit | f11710f12662dac786d2374fc46763513e07e8fd (patch) | |
tree | 688605057e1e80e90412871111aef8f69489508b /tools | |
parent | 868757e5acb94dcbe381a221550b055d2fa83549 (diff) | |
download | FreeBSD-src-f11710f12662dac786d2374fc46763513e07e8fd.zip FreeBSD-src-f11710f12662dac786d2374fc46763513e07e8fd.tar.gz |
netmap_user.h:
add separate rx/tx ring indexes
add ring specifier in nm_open device name
netmap.c, netmap_vale.c
more consistent errno numbers
netmap_generic.c
correctly handle failure in registering interfaces.
tools/tools/netmap/
massive cleanup of the example programs
(a lot of common code is now in netmap_user.h.)
nm_util.[ch] are going away soon.
pcap.c will also go when i commit the native netmap support for libpcap.
Diffstat (limited to 'tools')
-rw-r--r-- | tools/tools/netmap/Makefile | 7 | ||||
-rw-r--r-- | tools/tools/netmap/bridge.c | 89 | ||||
-rw-r--r-- | tools/tools/netmap/nm_util.c | 173 | ||||
-rw-r--r-- | tools/tools/netmap/nm_util.h | 118 | ||||
-rw-r--r-- | tools/tools/netmap/pcap.c | 184 | ||||
-rw-r--r-- | tools/tools/netmap/pkt-gen.c | 147 | ||||
-rw-r--r-- | tools/tools/netmap/vale-ctl.c | 26 |
7 files changed, 263 insertions, 481 deletions
diff --git a/tools/tools/netmap/Makefile b/tools/tools/netmap/Makefile index d737bac..e873389 100644 --- a/tools/tools/netmap/Makefile +++ b/tools/tools/netmap/Makefile @@ -10,7 +10,12 @@ NO_MAN= CFLAGS += -Werror -Wall -nostdinc -I/usr/include -I../../../sys CFLAGS += -Wextra -LDFLAGS += -lpthread -lpcap +LDFLAGS += -lpthread +.ifdef WITHOUT_PCAP +CFLAGS += -DNO_PCAP +.else +LDFLAGS += -lpcap +.endif .include <bsd.prog.mk> .include <bsd.lib.mk> diff --git a/tools/tools/netmap/bridge.c b/tools/tools/netmap/bridge.c index 6dc77e4..cab545b 100644 --- a/tools/tools/netmap/bridge.c +++ b/tools/tools/netmap/bridge.c @@ -96,16 +96,16 @@ process_rings(struct netmap_ring *rxring, struct netmap_ring *txring, /* move packts from src to destination */ static int -move(struct my_ring *src, struct my_ring *dst, u_int limit) +move(struct nm_desc_t *src, struct nm_desc_t *dst, u_int limit) { struct netmap_ring *txring, *rxring; - u_int m = 0, si = src->begin, di = dst->begin; - const char *msg = (src->queueid & NETMAP_SW_RING) ? + u_int m = 0, si = src->first_rx_ring, di = dst->first_tx_ring; + const char *msg = (src->req.nr_ringid & NETMAP_SW_RING) ? "host->net" : "net->host"; - while (si < src->end && di < dst->end) { - rxring = NETMAP_RXRING(src->nifp, si); - txring = NETMAP_TXRING(dst->nifp, di); + while (si <= src->last_rx_ring && di <= dst->last_tx_ring) { + rxring = src->tx + si; + txring = dst->tx + di; ND("txring %p rxring %p", txring, rxring); if (nm_ring_empty(rxring)) { si++; @@ -121,28 +121,6 @@ move(struct my_ring *src, struct my_ring *dst, u_int limit) return (m); } -/* - * how many packets on this set of queues ? - */ -static int -pkt_queued(struct my_ring *me, int tx) -{ - u_int i, tot = 0; - - ND("me %p begin %d end %d", me, me->begin, me->end); - for (i = me->begin; i < me->end; i++) { - struct netmap_ring *ring = tx ? - NETMAP_TXRING(me->nifp, i) : NETMAP_RXRING(me->nifp, i); - tot += nm_ring_space(ring); - } - if (0 && verbose && tot && !tx) - D("ring %s %s %s has %d avail at %d", - me->ifname, tx ? "tx": "rx", - me->end >= me->nifp->ni_tx_rings ? // XXX who comes first ? - "host":"net", - tot, NETMAP_TXRING(me->nifp, me->begin)->cur); - return tot; -} static void usage(void) @@ -165,14 +143,12 @@ main(int argc, char **argv) struct pollfd pollfd[2]; int i, ch; u_int burst = 1024, wait_link = 4; - struct my_ring me[2]; + struct nm_desc_t *pa = NULL, *pb = NULL; char *ifa = NULL, *ifb = NULL; fprintf(stderr, "%s %s built %s %s\n", argv[0], version, __DATE__, __TIME__); - bzero(me, sizeof(me)); - while ( (ch = getopt(argc, argv, "b:i:vw:")) != -1) { switch (ch) { default: @@ -224,9 +200,6 @@ main(int argc, char **argv) D("invalid wait_link %d, set to 4", wait_link); wait_link = 4; } - /* setup netmap interface #1. */ - me[0].ifname = ifa; - me[1].ifname = ifb; if (!strcmp(ifa, ifb)) { D("same interface, endpoint 0 goes to host"); i = NETMAP_SW_RING; @@ -234,24 +207,26 @@ main(int argc, char **argv) /* two different interfaces. Take all rings on if1 */ i = 0; // all hw rings } - if (netmap_open(me, i, 1)) + pa = netmap_open(ifa, i, 1); + if (pa == NULL) return (1); - me[1].mem = me[0].mem; /* copy the pointer, so only one mmap */ - if (netmap_open(me+1, 0, 1)) + // XXX use a single mmap ? + pb = netmap_open(ifb, 0, 1); + if (pb == NULL) { + nm_close(pa); return (1); + } /* setup poll(2) variables. */ memset(pollfd, 0, sizeof(pollfd)); - for (i = 0; i < 2; i++) { - pollfd[i].fd = me[i].fd; - pollfd[i].events = (POLLIN); - } + pollfd[0].fd = pa->fd; + pollfd[1].fd = pb->fd; D("Wait %d secs for link to come up...", wait_link); sleep(wait_link); D("Ready to go, %s 0x%x/%d <-> %s 0x%x/%d.", - me[0].ifname, me[0].queueid, me[0].nifp->ni_rx_rings, - me[1].ifname, me[1].queueid, me[1].nifp->ni_rx_rings); + pa->req.nr_name, pa->first_rx_ring, pa->req.nr_rx_rings, + pb->req.nr_name, pb->first_rx_ring, pb->req.nr_rx_rings); /* main loop */ signal(SIGINT, sigint_h); @@ -259,8 +234,8 @@ main(int argc, char **argv) int n0, n1, ret; pollfd[0].events = pollfd[1].events = 0; pollfd[0].revents = pollfd[1].revents = 0; - n0 = pkt_queued(me, 0); - n1 = pkt_queued(me + 1, 0); + n0 = pkt_queued(pa, 0); + n1 = pkt_queued(pb, 0); if (n0) pollfd[1].events |= POLLOUT; else @@ -276,39 +251,39 @@ main(int argc, char **argv) ret <= 0 ? "timeout" : "ok", pollfd[0].events, pollfd[0].revents, - pkt_queued(me, 0), - me[0].rx->cur, - pkt_queued(me, 1), + pkt_queued(pa, 0), + pa->rx->cur, + pkt_queued(pa, 1), pollfd[1].events, pollfd[1].revents, - pkt_queued(me+1, 0), - me[1].rx->cur, - pkt_queued(me+1, 1) + pkt_queued(pb, 0), + pb->rx->cur, + pkt_queued(pb, 1) ); if (ret < 0) continue; if (pollfd[0].revents & POLLERR) { D("error on fd0, rx [%d,%d)", - me[0].rx->cur, me[0].rx->tail); + pa->rx->cur, pa->rx->tail); } if (pollfd[1].revents & POLLERR) { D("error on fd1, rx [%d,%d)", - me[1].rx->cur, me[1].rx->tail); + pb->rx->cur, pb->rx->tail); } if (pollfd[0].revents & POLLOUT) { - move(me + 1, me, burst); + move(pb, pa, burst); // XXX we don't need the ioctl */ // ioctl(me[0].fd, NIOCTXSYNC, NULL); } if (pollfd[1].revents & POLLOUT) { - move(me, me + 1, burst); + move(pa, pb, burst); // XXX we don't need the ioctl */ // ioctl(me[1].fd, NIOCTXSYNC, NULL); } } D("exiting"); - netmap_close(me + 1); - netmap_close(me + 0); + nm_close(pb); + nm_close(pa); return (0); } diff --git a/tools/tools/netmap/nm_util.c b/tools/tools/netmap/nm_util.c index 1268840..deb52bb 100644 --- a/tools/tools/netmap/nm_util.c +++ b/tools/tools/netmap/nm_util.c @@ -37,16 +37,21 @@ extern int verbose; int -nm_do_ioctl(struct my_ring *me, u_long what, int subcmd) +nm_do_ioctl(struct nm_desc_t *me, u_long what, int subcmd) { struct ifreq ifr; int error; + int fd; + #if defined( __FreeBSD__ ) || defined (__APPLE__) - int fd = me->fd; + (void)subcmd; // only used on Linux + fd = me->fd; #endif + #ifdef linux struct ethtool_value eval; - int fd; + + bzero(&eval, sizeof(eval)); fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { printf("Error: cannot get device control socket.\n"); @@ -54,9 +59,8 @@ nm_do_ioctl(struct my_ring *me, u_long what, int subcmd) } #endif /* linux */ - (void)subcmd; // unused bzero(&ifr, sizeof(ifr)); - strncpy(ifr.ifr_name, me->ifname, sizeof(ifr.ifr_name)); + strncpy(ifr.ifr_name, me->req.nr_name, sizeof(ifr.ifr_name)); switch (what) { case SIOCSIFFLAGS: #ifndef __APPLE__ @@ -71,6 +75,7 @@ nm_do_ioctl(struct my_ring *me, u_long what, int subcmd) ifr.ifr_curcap = me->if_curcap; break; #endif + #ifdef linux case SIOCETHTOOL: eval.cmd = subcmd; @@ -115,108 +120,47 @@ done: * Returns the file descriptor. * The extra flag checks configures promisc mode. */ -int -netmap_open(struct my_ring *me, int ringid, int promisc) +struct nm_desc_t * +netmap_open(const char *name, int ringid, int promisc) { - int fd, err, l; - struct nmreq req; + struct nm_desc_t *d = nm_open(name, NULL, ringid, 0); - me->fd = fd = open("/dev/netmap", O_RDWR); - if (fd < 0) { - D("Unable to open /dev/netmap"); - return (-1); - } - bzero(&req, sizeof(req)); - req.nr_version = NETMAP_API; - strncpy(req.nr_name, me->ifname, sizeof(req.nr_name)); - req.nr_ringid = ringid; - err = ioctl(fd, NIOCREGIF, &req); - if (err) { - D("Unable to register %s", me->ifname); - goto error; - } - me->memsize = l = req.nr_memsize; - if (verbose) - D("memsize is %d MB", l>>20); - - if (me->mem == NULL) { - me->mem = mmap(0, l, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0); - if (me->mem == MAP_FAILED) { - D("Unable to mmap"); - me->mem = NULL; - goto error; - } - } + if (d == NULL) + return d; + if (verbose) + D("memsize is %d MB", d->req.nr_memsize>>20); /* Set the operating mode. */ if (ringid != NETMAP_SW_RING) { - nm_do_ioctl(me, SIOCGIFFLAGS, 0); - if ((me[0].if_flags & IFF_UP) == 0) { - D("%s is down, bringing up...", me[0].ifname); - me[0].if_flags |= IFF_UP; + nm_do_ioctl(d, SIOCGIFFLAGS, 0); + if ((d->if_flags & IFF_UP) == 0) { + D("%s is down, bringing up...", name); + d->if_flags |= IFF_UP; } if (promisc) { - me[0].if_flags |= IFF_PPROMISC; - nm_do_ioctl(me, SIOCSIFFLAGS, 0); + d->if_flags |= IFF_PPROMISC; + nm_do_ioctl(d, SIOCSIFFLAGS, 0); } + /* disable GSO, TSO, RXCSUM, TXCSUM... + * TODO: set them back when done. + */ #ifdef __FreeBSD__ - /* also disable checksums etc. */ - nm_do_ioctl(me, SIOCGIFCAP, 0); - me[0].if_reqcap = me[0].if_curcap; - me[0].if_reqcap &= ~(IFCAP_HWCSUM | IFCAP_TSO | IFCAP_TOE); - nm_do_ioctl(me+0, SIOCSIFCAP, 0); + nm_do_ioctl(d, SIOCGIFCAP, 0); + d->if_reqcap = d->if_curcap; + d->if_reqcap &= ~(IFCAP_HWCSUM | IFCAP_TSO | IFCAP_TOE); + nm_do_ioctl(d, SIOCSIFCAP, 0); #endif #ifdef linux - /* disable: - * - generic-segmentation-offload - * - tcp-segmentation-offload - * - rx-checksumming - * - tx-checksumming - * XXX check how to set back the caps. - */ - nm_do_ioctl(me, SIOCETHTOOL, ETHTOOL_SGSO); - nm_do_ioctl(me, SIOCETHTOOL, ETHTOOL_STSO); - nm_do_ioctl(me, SIOCETHTOOL, ETHTOOL_SRXCSUM); - nm_do_ioctl(me, SIOCETHTOOL, ETHTOOL_STXCSUM); + nm_do_ioctl(d, SIOCETHTOOL, ETHTOOL_SGSO); + nm_do_ioctl(d, SIOCETHTOOL, ETHTOOL_STSO); + nm_do_ioctl(d, SIOCETHTOOL, ETHTOOL_SRXCSUM); + nm_do_ioctl(d, SIOCETHTOOL, ETHTOOL_STXCSUM); #endif /* linux */ } - me->nifp = NETMAP_IF(me->mem, req.nr_offset); - me->queueid = ringid; - if (ringid & NETMAP_SW_RING) { - me->begin = req.nr_rx_rings; - me->end = me->begin + 1; - me->tx = NETMAP_TXRING(me->nifp, req.nr_tx_rings); - me->rx = NETMAP_RXRING(me->nifp, req.nr_rx_rings); - } else if (ringid & NETMAP_HW_RING) { - D("XXX check multiple threads"); - me->begin = ringid & NETMAP_RING_MASK; - me->end = me->begin + 1; - me->tx = NETMAP_TXRING(me->nifp, me->begin); - me->rx = NETMAP_RXRING(me->nifp, me->begin); - } else { - me->begin = 0; - me->end = req.nr_rx_rings; // XXX max of the two - me->tx = NETMAP_TXRING(me->nifp, 0); - me->rx = NETMAP_RXRING(me->nifp, 0); - } - return (0); -error: - close(me->fd); - return -1; -} - - -int -netmap_close(struct my_ring *me) -{ - D(""); - if (me->mem) - munmap(me->mem, me->memsize); - close(me->fd); - return (0); + return d; } @@ -224,22 +168,18 @@ netmap_close(struct my_ring *me) * how many packets on this set of queues ? */ int -pkt_queued(struct my_ring *me, int tx) +pkt_queued(struct nm_desc_t *d, int tx) { u_int i, tot = 0; ND("me %p begin %d end %d", me, me->begin, me->end); - for (i = me->begin; i < me->end; i++) { - struct netmap_ring *ring = tx ? - NETMAP_TXRING(me->nifp, i) : NETMAP_RXRING(me->nifp, i); - tot += nm_ring_space(ring); + if (tx) { + for (i = d->first_tx_ring; i <= d->last_tx_ring; i++) + tot += nm_ring_space(d->tx + i); + } else { + for (i = d->first_rx_ring; i <= d->last_rx_ring; i++) + tot += nm_ring_space(d->rx + i); } - if (0 && verbose && tot && !tx) - D("ring %s %s %s has %d avail at %d", - me->ifname, tx ? "tx": "rx", - me->end >= me->nifp->ni_tx_rings ? // XXX who comes first ? - "host":"net", - tot, NETMAP_TXRING(me->nifp, me->begin)->cur); return tot; } @@ -258,7 +198,7 @@ Helper routines for multiple readers from the same queue In particular we have a shared head+tail pointers that work together with cur and available ON RETURN FROM THE SYSCALL: - shadow->head = ring->cur + shadow->cur = ring->cur shadow->tail = ring->tail shadow->link[i] = i for all slots // mark invalid @@ -267,7 +207,7 @@ Helper routines for multiple readers from the same queue struct nm_q_arg { u_int want; /* Input */ u_int have; /* Output, 0 on error */ - u_int head; + u_int cur; u_int tail; struct netmap_ring *ring; }; @@ -280,24 +220,26 @@ my_grab(struct nm_q_arg q) { const u_int ns = q.ring->num_slots; + // lock(ring); for (;;) { - q.head = (volatile u_int)q.ring->head; + q.cur = (volatile u_int)q.ring->head; q.have = ns + q.head - (volatile u_int)q.ring->tail; if (q.have >= ns) q.have -= ns; - if (q.have == 0) /* no space */ + if (q.have == 0) /* no space; caller may ioctl/retry */ break; if (q.want < q.have) q.have = q.want; - q.tail = q.head + q.have; + q.tail = q.cur + q.have; if (q.tail >= ns) q.tail -= ns; - if (atomic_cmpset_int(&q.ring->head, q.head, q.tail) + if (atomic_cmpset_int(&q.ring->cur, q.cur, q.tail) break; /* success */ } + // unlock(ring); D("returns %d out of %d at %d,%d", - q.have, q.want, q.head, q.tail); + q.have, q.want, q.cur, q.tail); /* the last one can clear avail ? */ return q; } @@ -306,16 +248,18 @@ my_grab(struct nm_q_arg q) int my_release(struct nm_q_arg q) { - u_int head = q.head, tail = q.tail, i; + u_int cur = q.cur, tail = q.tail, i; struct netmap_ring *r = q.ring; /* link the block to the next one. * there is no race here because the location is mine. */ - r->slot[head].ptr = tail; /* this is mine */ + r->slot[cur].ptr = tail; /* this is mine */ + r->slot[cur].flags |= NM_SLOT_PTR; // points to next block // memory barrier - if (r->head != head) - return; /* not my turn to release */ + // lock(ring); + if (r->head != cur) + goto done; for (;;) { // advance head r->head = head = r->slot[head].ptr; @@ -327,5 +271,8 @@ my_release(struct nm_q_arg q) * further down. */ // do an ioctl/poll to flush. +done: + // unlock(ring); + return; /* not my turn to release */ } #endif /* unused */ diff --git a/tools/tools/netmap/nm_util.h b/tools/tools/netmap/nm_util.h index d8f8f94..0ab2e2e 100644 --- a/tools/tools/netmap/nm_util.h +++ b/tools/tools/netmap/nm_util.h @@ -35,60 +35,31 @@ #define _GNU_SOURCE /* for CPU_SET() */ -#include <errno.h> -#include <signal.h> /* signal */ -#include <stdlib.h> -#include <stdio.h> +#include <stdio.h> /* fprintf */ +#include <sys/poll.h> /* POLLIN */ #include <inttypes.h> /* PRI* macros */ -#include <string.h> /* strcmp */ -#include <fcntl.h> /* open */ -#include <unistd.h> /* close */ -#include <ifaddrs.h> /* getifaddrs */ +#include <sys/types.h> /* u_char */ -#include <sys/mman.h> /* PROT_* */ -#include <sys/ioctl.h> /* ioctl */ -#include <sys/poll.h> -#include <sys/socket.h> /* sockaddr.. */ #include <arpa/inet.h> /* ntohs */ -#include <sys/param.h> #include <sys/sysctl.h> /* sysctl */ -#include <sys/time.h> /* timersub */ - -#include <net/ethernet.h> -#include <net/if.h> /* ifreq */ +#include <ifaddrs.h> /* getifaddrs */ +#include <net/ethernet.h> /* ETHERTYPE_IP */ +#include <netinet/in.h> /* IPPROTO_* */ +#include <netinet/ip.h> /* struct ip */ +#include <netinet/udp.h> /* struct udp */ -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/udp.h> -#include <net/netmap.h> +#define NETMAP_WITH_LIBS #include <net/netmap_user.h> -#ifndef MY_PCAP /* use the system's pcap if available */ - -#ifdef NO_PCAP -#define PCAP_ERRBUF_SIZE 512 -typedef void pcap_t; -struct pcap_pkthdr; -#define pcap_inject(a,b,c) ((void)a, (void)b, (void)c, -1) -#define pcap_dispatch(a, b, c, d) (void)c -#define pcap_open_live(a, b, c, d, e) ((void)e, NULL) -#else /* !NO_PCAP */ -#include <pcap/pcap.h> // XXX do we need it ? -#endif /* !NO_PCAP */ - -#endif // XXX hack - #include <pthread.h> /* pthread_* */ #ifdef linux #define cpuset_t cpu_set_t -#define ifr_flagshigh ifr_flags -#define ifr_curcap ifr_flags -#define ifr_reqcap ifr_flags -#define IFF_PPROMISC IFF_PROMISC +#define ifr_flagshigh ifr_flags /* only the low 16 bits here */ +#define IFF_PPROMISC IFF_PROMISC /* IFF_PPROMISC does not exist */ #include <linux/ethtool.h> #include <linux/sockios.h> @@ -107,6 +78,20 @@ struct pcap_pkthdr; #endif /* __FreeBSD__ */ #ifdef __APPLE__ + +#define cpuset_t uint64_t // XXX +static inline void CPU_ZERO(cpuset_t *p) +{ + *p = 0; +} + +static inline void CPU_SET(uint32_t i, cpuset_t *p) +{ + *p |= 1<< (i & 0x3f); +} + +#define pthread_setaffinity_np(a, b, c) ((void)a, 0) + #define ifr_flagshigh ifr_flags // XXX #define IFF_PPROMISC IFF_PROMISC #include <net/if_dl.h> /* LLADDR */ @@ -136,54 +121,7 @@ extern int time_second; -// XXX does it work on 32-bit machines ? -static inline void prefetch (const void *x) -{ - __asm volatile("prefetcht0 %0" :: "m" (*(const unsigned long *)x)); -} - -// XXX only for multiples of 64 bytes, non overlapped. -static inline void -pkt_copy(const void *_src, void *_dst, int l) -{ - const 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++; - } -} - -/* - * info on a ring we handle - */ -struct my_ring { - const char *ifname; - int fd; - char *mem; /* userspace mmap address */ - u_int memsize; - u_int queueid; - u_int begin, end; /* first..last+1 rings to check */ - struct netmap_if *nifp; - struct netmap_ring *tx, *rx; /* shortcuts */ - - uint32_t if_flags; - uint32_t if_reqcap; - uint32_t if_curcap; -}; -int netmap_open(struct my_ring *me, int ringid, int promisc); -int netmap_close(struct my_ring *me); -int nm_do_ioctl(struct my_ring *me, u_long what, int subcmd); +struct nm_desc_t * netmap_open(const char *name, int ringid, int promisc); +int nm_do_ioctl(struct nm_desc_t *me, u_long what, int subcmd); +int pkt_queued(struct nm_desc_t *d, int tx); #endif /* _NM_UTIL_H */ diff --git a/tools/tools/netmap/pcap.c b/tools/tools/netmap/pcap.c index dd87c4a..b3c2be5 100644 --- a/tools/tools/netmap/pcap.c +++ b/tools/tools/netmap/pcap.c @@ -65,7 +65,7 @@ struct pcap_stat { #endif /* WIN32 */ }; -typedef void pcap_t; +typedef struct nm_desc_t pcap_t; typedef enum { PCAP_D_INOUT = 0, PCAP_D_IN, @@ -107,41 +107,6 @@ struct eproto { char pcap_version[] = "libnetmap version 0.3"; -/* - * Our equivalent of pcap_t - */ -struct pcap_ring { - struct my_ring me; -#if 0 - const char *ifname; - - //struct nmreq nmr; - - int fd; - char *mem; /* userspace mmap address */ - u_int memsize; - u_int queueid; - u_int begin, end; /* first..last+1 rings to check */ - struct netmap_if *nifp; - - uint32_t if_flags; - uint32_t if_reqcap; - uint32_t if_curcap; -#endif - int snaplen; - char *errbuf; - int promisc; - int to_ms; - - struct pcap_pkthdr hdr; - - - struct pcap_stat st; - - char msg[PCAP_ERRBUF_SIZE]; -}; - - /* * There is a set of functions that tcpdump expects even if probably @@ -279,7 +244,7 @@ pcap_can_set_rfmon(pcap_t *p) int pcap_set_snaplen(pcap_t *p, int snaplen) { - struct pcap_ring *me = p; + struct nm_desc_t *me = p; D("len %d", snaplen); me->snaplen = snaplen; @@ -289,7 +254,7 @@ pcap_set_snaplen(pcap_t *p, int snaplen) int pcap_snapshot(pcap_t *p) { - struct pcap_ring *me = p; + struct nm_desc_t *me = p; D("len %d", me->snaplen); return me->snaplen; @@ -310,17 +275,15 @@ pcap_lookupnet(const char *device, uint32_t *netp, int pcap_set_promisc(pcap_t *p, int promisc) { - struct pcap_ring *me = p; - D("promisc %d", promisc); - if (nm_do_ioctl(&me->me, SIOCGIFFLAGS, 0)) + if (nm_do_ioctl(p, SIOCGIFFLAGS, 0)) D("SIOCGIFFLAGS failed"); if (promisc) { - me->me.if_flags |= IFF_PPROMISC; + p->if_flags |= IFF_PPROMISC; } else { - me->me.if_flags &= ~IFF_PPROMISC; + p->if_flags &= ~IFF_PPROMISC; } - if (nm_do_ioctl(&me->me, SIOCSIFFLAGS, 0)) + if (nm_do_ioctl(p, SIOCSIFFLAGS, 0)) D("SIOCSIFFLAGS failed"); return 0; } @@ -328,10 +291,8 @@ pcap_set_promisc(pcap_t *p, int promisc) int pcap_set_timeout(pcap_t *p, int to_ms) { - struct pcap_ring *me = p; - D("%d ms", to_ms); - me->to_ms = to_ms; + p->to_ms = to_ms; return 0; } @@ -384,31 +345,24 @@ struct pcap_stat; int pcap_stats(pcap_t *p, struct pcap_stat *ps) { - struct pcap_ring *me = p; - ND(""); - - *ps = me->st; + *ps = *(struct pcap_stat *)(void *)&(p->st); return 0; /* accumulate from pcap_dispatch() */ }; char * pcap_geterr(pcap_t *p) { - struct pcap_ring *me = p; - D(""); - return me->msg; + return p->msg; } pcap_t * pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *errbuf) { - struct pcap_ring *me; + struct nm_desc_t *d; int l; - (void)snaplen; /* UNUSED */ - (void)errbuf; /* UNUSED */ if (!device) { D("missing device name"); return NULL; @@ -417,54 +371,40 @@ pcap_open_live(const char *device, int snaplen, l = strlen(device) + 1; D("request to open %s snaplen %d promisc %d timeout %dms", device, snaplen, promisc, to_ms); - me = calloc(1, sizeof(*me) + l); - if (me == NULL) { - D("failed to allocate struct for %s", device); - return NULL; - } - me->me.ifname = (char *)(me + 1); - strcpy((char *)me->me.ifname, device); - if (netmap_open(&me->me, 0, promisc)) { + d = nm_open(device, NULL, 0, 0); + if (d == NULL) { D("error opening %s", device); - free(me); return NULL; } - me->to_ms = to_ms; + d->to_ms = to_ms; + d->snaplen = snaplen; + d->errbuf = errbuf; + d->promisc = promisc; - return (pcap_t *)me; + return d; } void pcap_close(pcap_t *p) { - struct my_ring *me = p; - - D(""); - if (!me) - return; - if (me->mem) - munmap(me->mem, me->memsize); + nm_close(p); /* restore original flags ? */ - close(me->fd); - bzero(me, sizeof(*me)); - free(me); } int pcap_fileno(pcap_t *p) { - struct my_ring *me = p; - D("returns %d", me->fd); - return me->fd; + struct nm_desc_t *d = p; + D("returns %d", d->fd); + return d->fd; } int pcap_get_selectable_fd(pcap_t *p) { - struct my_ring *me = p; + struct nm_desc_t *d = p; - ND(""); - return me->fd; + return d->fd; } int @@ -488,94 +428,32 @@ pcap_setdirection(pcap_t *p, pcap_direction_t d) int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { - struct pcap_ring *pme = p; - struct my_ring *me = &pme->me; - int got = 0; - u_int si; - - ND("cnt %d", cnt); - if (cnt == 0) - cnt = -1; - /* scan all rings */ - for (si = me->begin; si < me->end; si++) { - struct netmap_ring *ring = NETMAP_RXRING(me->nifp, si); - if (nm_ring_empty(ring)) - continue; - pme->hdr.ts = ring->ts; - /* - * XXX a proper prefetch should be done as - * prefetch(i); callback(i-1); ... - */ - while ((cnt == -1 || cnt != got) && !nm_ring_empty(ring)) { - u_int i = ring->cur; - u_int idx = ring->slot[i].buf_idx; - if (idx < 2) { - D("%s bogus RX index %d at offset %d", - me->nifp->ni_name, idx, i); - sleep(2); - } - u_char *buf = (u_char *)NETMAP_BUF(ring, idx); - prefetch(buf); - pme->hdr.len = pme->hdr.caplen = ring->slot[i].len; - // D("call %p len %d", p, me->hdr.len); - callback(user, &pme->hdr, buf); - ring->head = ring->cur = nm_ring_next(ring, i); - got++; - } - } - pme->st.ps_recv += got; - return got; + return nm_dispatch(p, cnt, (void *)callback, user); } int pcap_inject(pcap_t *p, const void *buf, size_t size) { - struct my_ring *me = p; - u_int si; - - ND("cnt %d", cnt); - /* scan all rings */ - for (si = me->begin; si < me->end; si++) { - struct netmap_ring *ring = NETMAP_TXRING(me->nifp, si); - - if (nm_ring_empty(ring)) - continue; - u_int i = ring->cur; - u_int idx = ring->slot[i].buf_idx; - if (idx < 2) { - D("%s bogus TX index %d at offset %d", - me->nifp->ni_name, idx, i); - sleep(2); - } - u_char *dst = (u_char *)NETMAP_BUF(ring, idx); - ring->slot[i].len = size; - pkt_copy(buf, dst, size); - ring->head = ring->cur = nm_ring_next(ring, i); - // if (ring->cur == ring->tail) ioctl(me->fd, NIOCTXSYNC, NULL); - return size; - } - errno = ENOBUFS; - return -1; + return nm_inject(p, buf, size); } int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { - struct pcap_ring *me = p; struct pollfd fds[1]; int i; ND("cnt %d", cnt); memset(fds, 0, sizeof(fds)); - fds[0].fd = me->me.fd; + fds[0].fd = p->fd; fds[0].events = (POLLIN); while (cnt == -1 || cnt > 0) { - if (poll(fds, 1, me->to_ms) <= 0) { + if (poll(fds, 1, p->to_ms) <= 0) { D("poll error/timeout"); continue; } - i = pcap_dispatch(p, cnt, callback, user); + i = nm_dispatch(p, cnt, (void *)callback, user); if (cnt > 0) cnt -= i; } @@ -640,9 +518,9 @@ main(int argc, char **argv) if (ret < 0) continue; if (pollfd[0].revents & POLLIN) - pcap_dispatch(p0, burst, do_send, p1); + pcap_dispatch(p0, burst, do_send, (void *)p1); if (pollfd[1].revents & POLLIN) - pcap_dispatch(p1, burst, do_send, p0); + pcap_dispatch(p1, burst, do_send, (void *)p0); } return (0); diff --git a/tools/tools/netmap/pkt-gen.c b/tools/tools/netmap/pkt-gen.c index c1d0840..3fb7702 100644 --- a/tools/tools/netmap/pkt-gen.c +++ b/tools/tools/netmap/pkt-gen.c @@ -37,10 +37,15 @@ * */ +#define MY_PCAP #include "nm_util.h" +// #include <net/netmap_user.h> #include <ctype.h> // isprint() +#ifndef NO_PCAP +#include <pcap/pcap.h> +#endif const char *default_payload="netmap pkt-gen DIRECT payload\n" "http://info.iet.unipi.it/~luigi/netmap/ "; @@ -105,14 +110,16 @@ struct glob_arg { #define OPT_INDIRECT 32 /* use indirect buffers, tx only */ #define OPT_DUMP 64 /* dump rx/tx traffic */ int dev_type; +#ifndef NO_PCAP pcap_t *p; +#endif int tx_rate; struct timespec tx_period; int affinity; int main_fd; - int report_interval; + int report_interval; /* milliseconds between prints */ void *(*td_body)(void *); void *mmap_addr; int mmap_size; @@ -486,17 +493,18 @@ update_addresses(struct pkt *pkt, struct glob_arg *g) struct ip *ip = &pkt->ip; struct udphdr *udp = &pkt->udp; + do { p = ntohs(udp->uh_sport); if (p < g->src_ip.port1) { /* just inc, no wrap */ udp->uh_sport = htons(p + 1); - return; + break; } udp->uh_sport = htons(g->src_ip.port0); a = ntohl(ip->ip_src.s_addr); if (a < g->src_ip.end) { /* just inc, no wrap */ ip->ip_src.s_addr = htonl(a + 1); - return; + break; } ip->ip_src.s_addr = htonl(g->src_ip.start); @@ -504,17 +512,18 @@ update_addresses(struct pkt *pkt, struct glob_arg *g) p = ntohs(udp->uh_dport); if (p < g->dst_ip.port1) { /* just inc, no wrap */ udp->uh_dport = htons(p + 1); - return; + break; } udp->uh_dport = htons(g->dst_ip.port0); a = ntohl(ip->ip_dst.s_addr); if (a < g->dst_ip.end) { /* just inc, no wrap */ ip->ip_dst.s_addr = htonl(a + 1); - return; + break; } ip->ip_dst.s_addr = htonl(g->dst_ip.start); - + } while (0); + // update checksum } /* @@ -531,13 +540,13 @@ initialize_packet(struct targ *targ) uint16_t paylen = targ->g->pkt_size - sizeof(*eh) - sizeof(struct ip); const char *payload = targ->g->options & OPT_INDIRECT ? indirect_payload : default_payload; - int i, l, l0 = strlen(payload); + int i, l0 = strlen(payload); /* create a nice NUL-terminated string */ - for (i = 0; i < paylen;) { - l = min(l0, paylen - i); - bcopy(payload, pkt->body + i, l); - i += l; + for (i = 0; i < paylen; i += l0) { + if (l0 > paylen - i) + l0 = paylen - i; // last round + bcopy(payload, pkt->body + i, l0); } pkt->body[i-1] = '\0'; ip = &pkt->ip; @@ -593,7 +602,7 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame, u_int nfrags) { u_int n, sent, cur = ring->cur; - int fcnt; + u_int fcnt; n = nm_ring_space(ring); if (n < count) @@ -608,7 +617,7 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame, struct netmap_slot *slot = &ring->slot[cur]; char *p = NETMAP_BUF(ring, slot->buf_idx); - prefetch(p); + __builtin_prefetch(p); cur = nm_ring_next(ring, cur); } cur = ring->cur; @@ -624,14 +633,14 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame, slot->ptr = (uint64_t)frame; } else if (options & OPT_COPY) { pkt_copy(frame, p, size); - if (fcnt == 1) + if (fcnt == nfrags) update_addresses(pkt, g); } else if (options & OPT_MEMCPY) { memcpy(p, frame, size); - if (fcnt == 1) + if (fcnt == nfrags) update_addresses(pkt, g); } else if (options & OPT_PREFETCH) { - prefetch(p); + __builtin_prefetch(p); } if (options & OPT_DUMP) dump_payload(p, size, ring, cur); @@ -947,11 +956,11 @@ sender_body(void *data) wait_time(targ->tic); nexttime = targ->tic; } - if (targ->g->dev_type == DEV_PCAP) { - pcap_t *p = targ->g->p; + if (targ->g->dev_type == DEV_TAP) { + D("writing to file desc %d", targ->g->main_fd); for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { - if (pcap_inject(p, frame, size) != -1) + if (write(targ->g->main_fd, frame, size) != -1) sent++; update_addresses(pkt, targ->g); if (i > 10000) { @@ -959,11 +968,12 @@ sender_body(void *data) i = 0; } } - } else if (targ->g->dev_type == DEV_TAP) { /* tap */ - D("writing to file desc %d", targ->g->main_fd); +#ifndef NO_PCAP + } else if (targ->g->dev_type == DEV_PCAP) { + pcap_t *p = targ->g->p; for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { - if (write(targ->g->main_fd, frame, size) != -1) + if (pcap_inject(p, frame, size) != -1) sent++; update_addresses(pkt, targ->g); if (i > 10000) { @@ -971,6 +981,7 @@ sender_body(void *data) i = 0; } } +#endif /* NO_PCAP */ } else { int tosend = 0; int frags = targ->g->frags; @@ -1016,8 +1027,8 @@ sender_body(void *data) m = send_packets(txring, pkt, frame, size, targ->g, limit, options, frags); - ND("limit %d avail %d frags %d m %d", - limit, txring->avail, frags, m); + ND("limit %d tail %d frags %d m %d", + limit, txring->tail, frags, m); sent += m; targ->count = sent; if (rate_limit) { @@ -1038,7 +1049,7 @@ sender_body(void *data) usleep(1); /* wait 1 tick */ } } - } + } /* end DEV_NETMAP */ clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); targ->completed = 1; @@ -1052,6 +1063,7 @@ quit: } +#ifndef NO_PCAP static void receive_pcap(u_char *user, const struct pcap_pkthdr * h, const u_char * bytes) @@ -1061,6 +1073,7 @@ receive_pcap(u_char *user, const struct pcap_pkthdr * h, (void)bytes; /* UNUSED */ (*count)++; } +#endif /* !NO_PCAP */ static int receive_packets(struct netmap_ring *ring, u_int limit, int dump) @@ -1113,12 +1126,7 @@ receiver_body(void *data) /* main loop, exit after 1s silence */ clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); - if (targ->g->dev_type == DEV_PCAP) { - while (!targ->cancel) { - /* XXX should we poll ? */ - pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap, NULL); - } - } else if (targ->g->dev_type == DEV_TAP) { + if (targ->g->dev_type == DEV_TAP) { D("reading from %s fd %d", targ->g->ifname, targ->g->main_fd); while (!targ->cancel) { char buf[2048]; @@ -1126,6 +1134,13 @@ receiver_body(void *data) if (read(targ->g->main_fd, buf, sizeof(buf)) > 0) targ->count++; } +#ifndef NO_PCAP + } else if (targ->g->dev_type == DEV_PCAP) { + while (!targ->cancel) { + /* XXX should we poll ? */ + pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap, NULL); + } +#endif /* !NO_PCAP */ } else { int dump = targ->g->options & OPT_DUMP; while (!targ->cancel) { @@ -1533,7 +1548,7 @@ main(int arc, char **argv) g.virt_header = 0; while ( (ch = getopt(arc, argv, - "a:f:F:n:i:It:r:l:d:s:D:S:b:c:o:p:PT:w:WvR:XC:H:h")) != -1) { + "a:f:F:n:i:It:r:l:d:s:D:S:b:c:o:p:T:w:WvR:XC:H:h")) != -1) { struct sf *fn; switch(ch) { @@ -1575,13 +1590,28 @@ main(int arc, char **argv) break; case 'i': /* interface */ + /* a prefix of tap: netmap: or pcap: forces the mode. + * otherwise we guess + */ + D("interface is %s", optarg); g.ifname = optarg; - if (!strncmp(optarg, "tap", 3)) - g.dev_type = DEV_TAP; - else + if (!strcmp(optarg, "null")) { g.dev_type = DEV_NETMAP; - if (!strcmp(g.ifname, "null")) g.dummy_send = 1; + } else if (!strncmp(optarg, "tap:", 4)) { + g.dev_type = DEV_TAP; + g.ifname = optarg + 4; + } else if (!strncmp(optarg, "pcap:", 5)) { + g.dev_type = DEV_PCAP; + g.ifname = optarg + 5; + } else if (!strncmp(optarg, "netmap:", 7)) { + g.dev_type = DEV_NETMAP; + g.ifname = optarg + 7; + } else if (!strncmp(optarg, "tap", 3)) { + g.dev_type = DEV_TAP; + } else { + g.dev_type = DEV_NETMAP; + } break; case 'I': @@ -1634,10 +1664,6 @@ main(int arc, char **argv) g.nthreads = atoi(optarg); break; - case 'P': - g.dev_type = DEV_PCAP; - break; - case 'D': /* destination mac */ g.dst_mac.name = optarg; break; @@ -1659,8 +1685,10 @@ main(int arc, char **argv) break; case 'H': g.virt_header = atoi(optarg); + break; case 'h': g.host_ring = 1; + break; } } @@ -1697,6 +1725,12 @@ main(int arc, char **argv) extract_mac_range(&g.src_mac); extract_mac_range(&g.dst_mac); + if (g.src_ip.start != g.src_ip.end || + g.src_ip.port0 != g.src_ip.port1 || + g.dst_ip.start != g.dst_ip.end || + g.dst_ip.port0 != g.dst_ip.port1) + g.options |= OPT_COPY; + if (g.virt_header != 0 && g.virt_header != VIRT_HDR_1 && g.virt_header != VIRT_HDR_2) { D("bad virtio-net-header length"); @@ -1710,7 +1744,8 @@ main(int arc, char **argv) D("cannot open tap %s", g.ifname); usage(); } - } else if (g.dev_type > DEV_NETMAP) { +#ifndef NO_PCAP + } else if (g.dev_type == DEV_PCAP) { char pcap_errbuf[PCAP_ERRBUF_SIZE]; D("using pcap on %s", g.ifname); @@ -1720,7 +1755,8 @@ main(int arc, char **argv) D("cannot open pcap on %s", g.ifname); usage(); } - } else if (g.dummy_send) { +#endif /* !NO_PCAP */ + } else if (g.dummy_send) { /* but DEV_NETMAP */ D("using a dummy send routine"); } else { bzero(&nmr, sizeof(nmr)); @@ -1758,9 +1794,6 @@ main(int arc, char **argv) ND("%s: txr %d txd %d rxr %d rxd %d", g.ifname, nmr.nr_tx_rings, nmr.nr_tx_slots, nmr.nr_rx_rings, nmr.nr_rx_slots); - if ((ioctl(g.main_fd, NIOCGINFO, &nmr)) == -1) { - D("Unable to get if info for %s: %s", g.ifname, strerror(errno)); - } devqueues = nmr.nr_rx_rings; /* validate provided nthreads. */ @@ -1784,7 +1817,21 @@ main(int arc, char **argv) // continue, fail later } + if (verbose) { + struct netmap_if *nifp = NETMAP_IF(g.mmap_addr, nmr.nr_offset); + D("nifp at offset %d, %d tx %d rx rings %s", + nmr.nr_offset, nmr.nr_tx_rings, nmr.nr_rx_rings, + nmr.nr_ringid & NETMAP_PRIV_MEM ? "PRIVATE" : "common" ); + for (i = 0; i <= nmr.nr_tx_rings; i++) { + D(" TX%d at 0x%lx", i, + (char *)NETMAP_TXRING(nifp, i) - (char *)nifp); + } + for (i = 0; i <= nmr.nr_rx_rings; i++) { + D(" RX%d at 0x%lx", i, + (char *)NETMAP_RXRING(nifp, i) - (char *)nifp); + } + } /* Print some debug information. */ fprintf(stdout, @@ -1846,16 +1893,6 @@ main(int arc, char **argv) global_nthreads = g.nthreads; signal(SIGINT, sigint_h); -#if 0 // XXX this is not needed, i believe - if (g.dev_type > DEV_NETMAP) { - g.p = pcap_open_live(g.ifname, 0, 1, 100, NULL); - if (g.p == NULL) { - D("cannot open pcap on %s", g.ifname); - usage(); - } else - D("using pcap %p on %s", g.p, g.ifname); - } -#endif // XXX start_threads(&g); main_thread(&g); return 0; diff --git a/tools/tools/netmap/vale-ctl.c b/tools/tools/netmap/vale-ctl.c index c0cf574..eb6c48d 100644 --- a/tools/tools/netmap/vale-ctl.c +++ b/tools/tools/netmap/vale-ctl.c @@ -69,20 +69,22 @@ bdg_ctl(const char *name, int nr_cmd, int nr_arg) nr_arg = 0; nmr.nr_arg1 = nr_arg; error = ioctl(fd, NIOCREGIF, &nmr); - if (error == -1) - D("Unable to %s %s to the bridge", nr_cmd == + if (error == -1) { + ND("Unable to %s %s to the bridge", nr_cmd == NETMAP_BDG_DETACH?"detach":"attach", name); - else - D("Success to %s %s to the bridge\n", nr_cmd == + perror(name); + } else + ND("Success to %s %s to the bridge", nr_cmd == NETMAP_BDG_DETACH?"detach":"attach", name); break; case NETMAP_BDG_LIST: if (strlen(nmr.nr_name)) { /* name to bridge/port info */ error = ioctl(fd, NIOCGINFO, &nmr); - if (error) - D("Unable to obtain info for %s", name); - else + if (error) { + ND("Unable to obtain info for %s", name); + perror(name); + } else D("%s at bridge:%d port:%d", name, nmr.nr_arg1, nmr.nr_arg2); break; @@ -101,9 +103,10 @@ bdg_ctl(const char *name, int nr_cmd, int nr_arg) default: /* GINFO */ nmr.nr_cmd = nmr.nr_arg1 = nmr.nr_arg2 = 0; error = ioctl(fd, NIOCGINFO, &nmr); - if (error) - D("Unable to get if info for %s", name); - else + if (error) { + ND("Unable to get if info for %s", name); + perror(name); + } else D("%s: %d queues.", name, nmr.nr_rx_rings); break; } @@ -164,6 +167,5 @@ usage: } if (argc == 1) nr_cmd = NETMAP_BDG_LIST; - bdg_ctl(name, nr_cmd, nr_arg); - return 0; + return bdg_ctl(name, nr_cmd, nr_arg) ? 1 : 0; } |