From owner-svn-src-all@FreeBSD.ORG Thu Jan 16 00:20:44 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 46AEF1B9; Thu, 16 Jan 2014 00:20:44 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 30B5C1660; Thu, 16 Jan 2014 00:20:44 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id s0G0KiWN004091; Thu, 16 Jan 2014 00:20:44 GMT (envelope-from luigi@svn.freebsd.org) Received: (from luigi@localhost) by svn.freebsd.org (8.14.7/8.14.7/Submit) id s0G0KgwY004039; Thu, 16 Jan 2014 00:20:42 GMT (envelope-from luigi@svn.freebsd.org) Message-Id: <201401160020.s0G0KgwY004039@svn.freebsd.org> From: Luigi Rizzo Date: Thu, 16 Jan 2014 00:20:42 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r260700 - in head: sys/dev/netmap tools/tools/netmap X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 16 Jan 2014 00:20:44 -0000 Author: luigi Date: Thu Jan 16 00:20:42 2014 New Revision: 260700 URL: http://svnweb.freebsd.org/changeset/base/260700 Log: 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. Modified: head/sys/dev/netmap/netmap.c head/sys/dev/netmap/netmap_generic.c head/sys/dev/netmap/netmap_vale.c head/tools/tools/netmap/Makefile head/tools/tools/netmap/bridge.c head/tools/tools/netmap/nm_util.c head/tools/tools/netmap/nm_util.h head/tools/tools/netmap/pcap.c head/tools/tools/netmap/pkt-gen.c head/tools/tools/netmap/vale-ctl.c Modified: head/sys/dev/netmap/netmap.c ============================================================================== --- head/sys/dev/netmap/netmap.c Wed Jan 15 22:47:53 2014 (r260699) +++ head/sys/dev/netmap/netmap.c Thu Jan 16 00:20:42 2014 (r260700) @@ -1052,7 +1052,7 @@ netmap_get_hw_na(struct ifnet *ifp, stru * to use generic adapters, we cannot satisfy the request. */ if (!NETMAP_CAPABLE(ifp) && i == NETMAP_ADMODE_NATIVE) - return EINVAL; + return EOPNOTSUPP; /* Otherwise, create a generic adapter and return it, * saving the previously used netmap adapter, if any. @@ -1090,22 +1090,19 @@ netmap_get_hw_na(struct ifnet *ifp, stru /* * MUST BE CALLED UNDER NMG_LOCK() * - * get a refcounted reference to an interface. + * Get a refcounted reference to a netmap adapter attached + * to the interface specified by nmr. * This is always called in the execution of an ioctl(). * - * Return ENXIO if the interface does not exist, EINVAL if netmap - * is not supported by the interface. - * If successful, hold a reference. - * - * When the NIC is attached to a bridge, reference is managed - * at na->na_bdg_refcount using ADD/DROP_BDG_REF() as well as - * virtual ports. Hence, on the final DROP_BDG_REF(), the NIC - * is detached from the bridge, then ifp's refcount is dropped (this - * is equivalent to that ifp is destroyed in case of virtual ports. - * - * This function uses if_rele() when we want to prevent the NIC from - * being detached from the bridge in error handling. But once refcount - * is acquired by this function, it must be released using nm_if_rele(). + * Return ENXIO if the interface specified by the request does + * not exist, ENOTSUP if netmap is not supported by the interface, + * EBUSY if the interface is already attached to a bridge, + * EINVAL if parameters are invalid, ENOMEM if needed resources + * could not be allocated. + * If successful, hold a reference to the netmap adapter. + * + * No reference is kept on the real interface, which may then + * disappear at any time. */ int netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, int create) @@ -1135,7 +1132,7 @@ netmap_get_na(struct nmreq *nmr, struct if (ret != NULL) { /* Users cannot use the NIC attached to a bridge directly */ if (NETMAP_OWNED_BY_KERN(ret)) { - error = EINVAL; + error = EBUSY; goto out; } error = 0; Modified: head/sys/dev/netmap/netmap_generic.c ============================================================================== --- head/sys/dev/netmap/netmap_generic.c Wed Jan 15 22:47:53 2014 (r260699) +++ head/sys/dev/netmap/netmap_generic.c Thu Jan 16 00:20:42 2014 (r260700) @@ -261,7 +261,7 @@ generic_netmap_register(struct netmap_ad /* Prepare to intercept incoming traffic. */ error = netmap_catch_rx(na, 1); if (error) { - D("netdev_rx_handler_register() failed"); + D("netdev_rx_handler_register() failed (%d)", error); goto register_handler; } ifp->if_capenable |= IFCAP_NETMAP; @@ -283,7 +283,11 @@ generic_netmap_register(struct netmap_ad rate_ctx.refcount++; #endif /* RATE */ - } else { /* Disable netmap mode. */ + } else if (na->tx_rings[0].tx_pool) { + /* Disable netmap mode. We enter here only if the previous + generic_netmap_register(na, 1) was successfull. + If it was not, na->tx_rings[0].tx_pool was set to NULL by the + error handling code below. */ rtnl_lock(); ifp->if_capenable &= ~IFCAP_NETMAP; @@ -322,7 +326,7 @@ generic_netmap_register(struct netmap_ad #ifdef REG_RESET error = ifp->netdev_ops->ndo_open(ifp); if (error) { - goto alloc_tx_pool; + goto free_tx_pools; } #endif @@ -338,6 +342,11 @@ free_tx_pools: if (na->tx_rings[r].tx_pool[i]) m_freem(na->tx_rings[r].tx_pool[i]); free(na->tx_rings[r].tx_pool, M_DEVBUF); + na->tx_rings[r].tx_pool = NULL; + } + netmap_mitigation_cleanup(gna); + for (r=0; rnum_rx_rings; r++) { + mbq_safe_destroy(&na->rx_rings[r].rx_queue); } return error; Modified: head/sys/dev/netmap/netmap_vale.c ============================================================================== --- head/sys/dev/netmap/netmap_vale.c Wed Jan 15 22:47:53 2014 (r260699) +++ head/sys/dev/netmap/netmap_vale.c Thu Jan 16 00:20:42 2014 (r260700) @@ -515,7 +515,7 @@ netmap_get_bdg_na(struct nmreq *nmr, str b = nm_find_bridge(name, create); if (b == NULL) { D("no bridges available for '%s'", name); - return (ENXIO); + return (create ? ENOMEM : ENXIO); } /* Now we are sure that name starts with the bridge's name, @@ -547,7 +547,7 @@ netmap_get_bdg_na(struct nmreq *nmr, str needed = 2; /* in some cases we only need 1 */ if (b->bdg_active_ports + needed >= NM_BDG_MAXPORTS) { D("bridge full %d, cannot create new port", b->bdg_active_ports); - return EINVAL; + return ENOMEM; } /* record the next two ports available, but do not allocate yet */ cand = b->bdg_port_index[b->bdg_active_ports]; @@ -594,7 +594,7 @@ netmap_get_bdg_na(struct nmreq *nmr, str if (NETMAP_OWNED_BY_ANY(ret)) { D("NIC %s busy, cannot attach to bridge", NM_IFPNAME(ifp)); - error = EINVAL; + error = EBUSY; goto out; } /* create a fake interface */ @@ -658,11 +658,13 @@ nm_bdg_attach(struct nmreq *nmr) npriv = malloc(sizeof(*npriv), M_DEVBUF, M_NOWAIT|M_ZERO); if (npriv == NULL) return ENOMEM; + NMG_LOCK(); - /* XXX probably netmap_get_bdg_na() */ + error = netmap_get_bdg_na(nmr, &na, 1 /* create if not exists */); if (error) /* no device, or another bridge or user owns the device */ goto unlock_exit; + if (na == NULL) { /* VALE prefix missing */ error = EINVAL; goto unlock_exit; @@ -707,6 +709,7 @@ nm_bdg_detach(struct nmreq *nmr) if (error) { /* no device, or another bridge or user owns the device */ goto unlock_exit; } + if (na == NULL) { /* VALE prefix missing */ error = EINVAL; goto unlock_exit; @@ -1945,7 +1948,7 @@ netmap_bwrap_notify(struct netmap_adapte int error = 0; if (tx == NR_TX) - return ENXIO; + return EINVAL; kring = &na->rx_rings[ring_n]; hw_kring = &hwna->tx_rings[ring_n]; @@ -1999,7 +2002,7 @@ netmap_bwrap_host_notify(struct netmap_a struct netmap_bwrap_adapter *bna = na->na_private; struct netmap_adapter *port_na = &bna->up.up; if (tx == NR_TX || ring_n != 0) - return ENXIO; + return EINVAL; return netmap_bwrap_notify(port_na, port_na->num_rx_rings, NR_RX, flags); } Modified: head/tools/tools/netmap/Makefile ============================================================================== --- head/tools/tools/netmap/Makefile Wed Jan 15 22:47:53 2014 (r260699) +++ head/tools/tools/netmap/Makefile Thu Jan 16 00:20:42 2014 (r260700) @@ -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 .include Modified: head/tools/tools/netmap/bridge.c ============================================================================== --- head/tools/tools/netmap/bridge.c Wed Jan 15 22:47:53 2014 (r260699) +++ head/tools/tools/netmap/bridge.c Thu Jan 16 00:20:42 2014 (r260700) @@ -96,16 +96,16 @@ process_rings(struct netmap_ring *rxring /* 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 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); } Modified: head/tools/tools/netmap/nm_util.c ============================================================================== --- head/tools/tools/netmap/nm_util.c Wed Jan 15 22:47:53 2014 (r260699) +++ head/tools/tools/netmap/nm_util.c Thu Jan 16 00:20:42 2014 (r260700) @@ -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 w } #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 w 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 fro 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 fro 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 */ Modified: head/tools/tools/netmap/nm_util.h ============================================================================== --- head/tools/tools/netmap/nm_util.h Wed Jan 15 22:47:53 2014 (r260699) +++ head/tools/tools/netmap/nm_util.h Thu Jan 16 00:20:42 2014 (r260700) @@ -35,60 +35,31 @@ #define _GNU_SOURCE /* for CPU_SET() */ -#include -#include /* signal */ -#include -#include +#include /* fprintf */ +#include /* POLLIN */ #include /* PRI* macros */ -#include /* strcmp */ -#include /* open */ -#include /* close */ -#include /* getifaddrs */ +#include /* u_char */ -#include /* PROT_* */ -#include /* ioctl */ -#include -#include /* sockaddr.. */ #include /* ntohs */ -#include #include /* sysctl */ -#include /* timersub */ - -#include -#include /* ifreq */ +#include /* getifaddrs */ +#include /* ETHERTYPE_IP */ +#include /* IPPROTO_* */ +#include /* struct ip */ +#include /* struct udp */ -#include -#include -#include -#include +#define NETMAP_WITH_LIBS #include -#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 // XXX do we need it ? -#endif /* !NO_PCAP */ - -#endif // XXX hack - #include /* 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 #include @@ -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 /* 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 */ Modified: head/tools/tools/netmap/pcap.c ============================================================================== --- head/tools/tools/netmap/pcap.c Wed Jan 15 22:47:53 2014 (r260699) +++ head/tools/tools/netmap/pcap.c Thu Jan 16 00:20:42 2014 (r260700) @@ -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, uint3 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 s 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; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***