1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-17 15:27:36 +00:00

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.
This commit is contained in:
Luigi Rizzo 2014-01-16 00:20:42 +00:00
parent 7855b0bd68
commit f263752668
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=260700
10 changed files with 303 additions and 512 deletions

View File

@ -1052,7 +1052,7 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_adapter **na)
* 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, struct netmap_adapter **na)
/*
* 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.
* 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.
*
* 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().
* 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 netmap_adapter **na, int create)
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;

View File

@ -261,7 +261,7 @@ generic_netmap_register(struct netmap_adapter *na, int enable)
/* 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_adapter *na, int enable)
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_adapter *na, int enable)
#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 @@ generic_netmap_register(struct netmap_adapter *na, int enable)
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; r<na->num_rx_rings; r++) {
mbq_safe_destroy(&na->rx_rings[r].rx_queue);
}
return error;

View File

@ -515,7 +515,7 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create)
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, struct netmap_adapter **na, int create)
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, struct netmap_adapter **na, int create)
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_adapter *na, u_int ring_n, enum txrx tx, int f
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_adapter *na, u_int ring_n, enum txrx tx,
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);
}

View File

@ -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>

View File

@ -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);
}

View File

@ -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 @@ nm_do_ioctl(struct my_ring *me, u_long what, int subcmd)
* 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);
if (d == NULL)
return d;
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;
}
}
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 */

View File

@ -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 <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 <net/ethernet.h>
#include <net/if.h> /* ifreq */
#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 */

View File

@ -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);

View File

@ -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,19 +956,7 @@ sender_body(void *data)
wait_time(targ->tic);
nexttime = targ->tic;
}
if (targ->g->dev_type == DEV_PCAP) {
pcap_t *p = targ->g->p;
for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) {
if (pcap_inject(p, frame, size) != -1)
sent++;
update_addresses(pkt, targ->g);
if (i > 10000) {
targ->count = sent;
i = 0;
}
}
} else if (targ->g->dev_type == DEV_TAP) { /* tap */
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++) {
@ -971,6 +968,20 @@ sender_body(void *data)
i = 0;
}
}
#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 (pcap_inject(p, frame, size) != -1)
sent++;
update_addresses(pkt, targ->g);
if (i > 10000) {
targ->count = sent;
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 @@ sender_body(void *data)
}
#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;

View File

@ -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 @@ main(int argc, char *argv[])
}
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;
}