struct if_netmap_host_context * if_netmap_register_if(int nmfd, const char *ifname, unsigned int isvale, unsigned int qno) { struct if_netmap_host_context *ctx; ctx = calloc(1, sizeof(struct if_netmap_host_context)); if (NULL == ctx) return (NULL); ctx->fd = nmfd; ctx->isvale = isvale; ctx->ifname = ifname; /* * Disable TCP and checksum offload, which can impact throughput * and also cause packets to be dropped or modified gratuitously. * * Also disable VLAN offload/filtering - we want to talk straight to * the wire. * */ if (!ctx->isvale) { if (0 != if_netmap_set_offload(ctx, 0)) { goto fail; } if (0 != if_netmap_set_promisc(ctx, 1)) { goto fail; } } ctx->req.nr_version = NETMAP_API; ctx->req.nr_ringid = NETMAP_NO_TX_POLL | NETMAP_HW_RING | qno; snprintf(ctx->req.nr_name, sizeof(ctx->req.nr_name), "%s", ifname); if (-1 == ioctl(ctx->fd, NIOCREGIF, &ctx->req)) { goto fail; } ctx->mem = uhi_mmap(NULL, ctx->req.nr_memsize, UHI_PROT_READ | UHI_PROT_WRITE, UHI_MAP_NOCORE | UHI_MAP_SHARED, ctx->fd, 0); if (MAP_FAILED == ctx->mem) { goto fail; } ctx->hw_rx_ring = NETMAP_RXRING(NETMAP_IF(ctx->mem, ctx->req.nr_offset), qno); ctx->hw_tx_ring = NETMAP_TXRING(NETMAP_IF(ctx->mem, ctx->req.nr_offset), qno); /* NIOCREGIF will reset the hardware rings, but the reserved count * might still be non-zero from a previous user's activities */ ctx->hw_rx_ring->reserved = 0; return (ctx); fail: free(ctx); return(NULL); }
struct netmap_if * get_if() { void *mmap_addr; uint32_t off; char *arg; /* defaults */ off = curr_nmr.nr_offset; mmap_addr = last_mmap_addr; /* first arg: if offset */ arg = nextarg(); if (!arg) { goto doit; } off = strtoul(arg, NULL, 0); /* second arg: mmap address */ arg = nextarg(); if (!arg) { goto doit; } mmap_addr = (void*)strtoul(arg, NULL, 0); doit: return NETMAP_IF(mmap_addr, off); }
int nm_ring (char * ifname, int q, struct netmap_ring ** ring, int x, int w) { int fd; char * mem; struct nmreq nmr; struct netmap_if * nifp; /* open netmap for ring */ fd = open ("/dev/netmap", O_RDWR); if (fd < 0) { D ("unable to open /dev/netmap"); return -1; } memset (&nmr, 0, sizeof (nmr)); strcpy (nmr.nr_name, ifname); nmr.nr_version = NETMAP_API; nmr.nr_ringid = q | (NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL); if (w) nmr.nr_flags |= NR_REG_ONE_NIC; else nmr.nr_flags |= NR_REG_ALL_NIC; if (vale_rings && strncmp (ifname, "vale", 4) == 0) { nmr.nr_rx_rings = vale_rings; nmr.nr_tx_rings = vale_rings; } if (ioctl (fd, NIOCREGIF, &nmr) < 0) { D ("unable to register interface %s", ifname); return -1; } mem = mmap (NULL, nmr.nr_memsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (mem == MAP_FAILED) { D ("unable to mmap"); return -1; } nifp = NETMAP_IF (mem, nmr.nr_offset); if (x > 0) *ring = NETMAP_TXRING (nifp, q); else *ring = NETMAP_RXRING (nifp, q); return fd; }
static int opennetmap(const char *devstr, struct virtif_user *viu, uint8_t *enaddr) { int fd = -1; struct nmreq req; int err = 0; /* fprintf(stderr, "trying to use netmap on %s\n", devstr); */ fd = open("/dev/netmap", O_RDWR); if (fd == -1) { fprintf(stderr, "Unable to open /dev/netmap\n"); goto out; } bzero(&req, sizeof(req)); req.nr_version = NETMAP_API; strncpy(req.nr_name, devstr, sizeof(req.nr_name)); req.nr_ringid = NETMAP_NO_TX_POLL; err = ioctl(fd, NIOCREGIF, &req); if (err) { fprintf(stderr, "Unable to register %s errno %d\n", req.nr_name, errno); goto out; } /* fprintf(stderr, "need %d MB\n", req.nr_memsize >> 20); */ viu->nm_mem = mmap(0, req.nr_memsize, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0); if (viu->nm_mem == MAP_FAILED) { fprintf(stderr, "Unable to mmap\n"); viu->nm_mem = NULL; goto out; } viu->nm_nifp = NETMAP_IF(viu->nm_mem, req.nr_offset); /* fprintf(stderr, "netmap:%s mem %d\n", devstr, req.nr_memsize); */ if (source_hwaddr(devstr, enaddr) != 0) { if (strncmp(devstr, "vale", 4) != 0) { fprintf(stderr, "netmap:%s: failed to retrieve " "MAC address\n", devstr); } } out: if (err && fd != -1) { close(fd); fd = -1; } return fd; }
static int netmap_port_open(uint32_t idx) { int err; struct netmap_port *port; struct nmreq req; port = ports.p + idx; port->fd = rte_netmap_open("/dev/netmap", O_RDWR); snprintf(req.nr_name, sizeof(req.nr_name), "%s", port->str); req.nr_version = NETMAP_API; req.nr_ringid = 0; err = rte_netmap_ioctl(port->fd, NIOCGINFO, &req); if (err) { printf("[E] NIOCGINFO ioctl failed (error %d)\n", err); return err; } snprintf(req.nr_name, sizeof(req.nr_name), "%s", port->str); req.nr_version = NETMAP_API; req.nr_ringid = 0; err = rte_netmap_ioctl(port->fd, NIOCREGIF, &req); if (err) { printf("[E] NIOCREGIF ioctl failed (error %d)\n", err); return err; } /* mmap only once. */ if (ports.mem == NULL) ports.mem = rte_netmap_mmap(NULL, req.nr_memsize, PROT_WRITE | PROT_READ, MAP_PRIVATE, port->fd, 0); if (ports.mem == MAP_FAILED) { printf("[E] NETMAP mmap failed for fd: %d)\n", port->fd); return -ENOMEM; } port->nmif = NETMAP_IF(ports.mem, req.nr_offset); port->tx_ring = NETMAP_TXRING(port->nmif, 0); port->rx_ring = NETMAP_RXRING(port->nmif, 0); return 0; }
/** * Open netmap ring. * @param[in,out] ring * @param[in] ringid Ring ID. * @param[in] cached_mmap_mem Pointer to already mmapped shared netmap memory. */ int znm_open(struct znm_ring *ring, const char *ifname, uint16_t ringid, void *cached_mmap_mem) { struct nmreq req; ring->fd = open(ZNM_DEVICE, O_RDWR); if (ring->fd < 0) { ZERO_ELOG(LOG_ERR, "Unable to open %s", ZNM_DEVICE); return -1; } memset(&req, 0, sizeof(req)); req.nr_version = NETMAP_API; strncpy(req.nr_name, ifname, sizeof(req.nr_name)); req.nr_ringid = ringid; req.nr_flags = NR_REG_ONE_NIC; if (0 == ioctl(ring->fd, NIOCGINFO, &req)) { ring->memsize = req.nr_memsize; if (0 == ioctl(ring->fd, NIOCREGIF, &req)) { if (NULL != cached_mmap_mem) { ring->mem = cached_mmap_mem; } else { ring->mem = mmap(0, ring->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, ring->fd, 0); ring->own_mmap = 1; } if (MAP_FAILED != ring->mem) { ZERO_LOG(LOG_DEBUG, "Attached to %s HW ring %u", ifname, ringid); ring->nifp = NETMAP_IF(ring->mem, req.nr_offset); ring->tx = NETMAP_TXRING(ring->nifp, ringid); ring->rx = NETMAP_RXRING(ring->nifp, ringid); // Success. return 0; } else { ring->mem = NULL; ZERO_ELOG(LOG_ERR, "Unable to mmap netmap shared memory"); } } else { ZERO_ELOG(LOG_ERR, "Unable to register %s with netmap", ifname); } } else { ZERO_ELOG(LOG_ERR, "Unable to query netmap for '%s' info", ifname); } close(ring->fd); return -1; }
/** * Inner sendpacket_open() method for using netmap */ void * sendpacket_open_netmap(const char *device, char *errbuf, void *arg) { tcpreplay_t *ctx = (tcpreplay_t*)arg; sendpacket_t *sp = NULL; nmreq_t nmr; char ifname_buf[MAX_IFNAMELEN]; const char *ifname; const char *port = NULL; size_t namelen; u_int32_t nr_ringid = 0; u_int32_t nr_flags = NR_REG_DEFAULT; int is_default = 0; assert(device); assert(errbuf); dbg(1, "sendpacket_open_netmap: using netmap"); bzero(&nmr, sizeof(nmr)); /* prep & return our sp handle */ sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t)); if (strlen(device) > MAX_IFNAMELEN - 8) { snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Interface name is to long: %s\n", device); goto IFACENAME_INVALID; } /* get the version of the netmap driver. If < 0, driver is not installed */ sp->netmap_version = get_netmap_version(); if (sp->netmap_version < 0) { snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to determine the running netmap version.\n" "See INSTALL document for details on installing or upgrading netmap."); goto NETMAP_NOT_INSTALLED; } /* * Sort out interface names * * ifname (foo, netmap:foo or vale:foo) is the port name * foo bind to a single NIC hardware queue * netmap:foo bind to a single NIC hardware queue * vale:foo bind to the Vale virtual interface * * for netmap version 10+ a suffix can indicate the following: * netmap:foo! bind to all NIC hardware queues (may cause TX reordering) * netmap:foo^ bind to the host (sw) ring pair * netmap:foo* bind to the host (sw) and NIC ring pairs (transparent) * netmap:foo-NN bind to the individual NIC ring pair (queue) where NN = the ring number * netmap:foo{NN bind to the master side of pipe NN * netmap:foo}NN bind to the slave side of pipe NN */ if (strncmp(device, "netmap:", 7) && strncmp(device, "vale", 4)) { snprintf(ifname_buf, sizeof(ifname_buf), "netmap:%s", device); ifname = ifname_buf; } else { ifname = device; } if (!strncmp("vale", device, 4)) sp->is_vale = 1; if (ifname[0] == 'n') ifname += 7; /* scan for a separator */ for (port = ifname; *port && !index("!-*^{}", *port); port++) ; namelen = port - ifname; if (namelen > sizeof(nmr.nr_name)) { snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Interface name is to long: %s\n", device); goto IFACENAME_INVALID; } /* * Open the netmap device to fetch the number of queues of our * interface. * * The first NIOCREGIF also detaches the card from the * protocol stack and may cause a reset of the card, * which in turn may take some time for the PHY to * reconfigure. */ if ((sp->handle.fd = open("/dev/netmap", O_RDWR)) < 0) { dbg(1, "sendpacket_open_netmap: Unable to access netmap"); snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to access netmap.\n" "See INSTALL to learn which NICs are supported and\n" "how to set up netmap-capable network drivers."); goto OPEN_FAILED; } /* * The nmreq structure must have the NETMAP_API version for the running machine. * However the binary may have been compiled on a different machine than the * running machine. Discover the true netmap API version, and be careful to call * fuctions that are available on all netmap versions. */ if (sp->netmap_version >= 10) { switch (*port) { case '-': /* one NIC */ nr_flags = NR_REG_ONE_NIC; nr_ringid = atoi(port + 1); break; case '*': /* NIC and SW, ignore port */ nr_flags = NR_REG_NIC_SW; if (port[1]) { snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "invalid netmap port for nic+sw"); goto NETMAP_IF_PARSE_FAIL; } break; case '^': /* only sw ring */ nr_flags = NR_REG_SW; if (port[1]) { snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "invalid port for sw ring"); goto NETMAP_IF_PARSE_FAIL; } break; case '{': nr_flags = NR_REG_PIPE_MASTER; nr_ringid = atoi(port + 1); break; case '}': nr_flags = NR_REG_PIPE_SLAVE; nr_ringid = atoi(port + 1); break; case '!': nr_flags = NR_REG_ALL_NIC; break; default: /* '\0', no suffix */ nr_flags = NR_REG_ALL_NIC; is_default = 1; break; } if (nr_ringid >= NETMAP_RING_MASK) { snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "invalid ringid"); goto NETMAP_IF_PARSE_FAIL; } nmr.nr_ringid = nr_ringid; nmr.nr_flags = nr_flags; } nmr.nr_version = sp->netmap_version; memcpy(nmr.nr_name, ifname, namelen); nmr.nr_name[namelen] = '\0'; strlcpy(sp->device, nmr.nr_name, sizeof(sp->device)); /* * Register the interface on the netmap device: from now on, * we can operate on the network interface without any * interference from the legacy network stack. * * Cards take a long time to reset the PHY. */ fprintf(stderr, "Switching network driver for %s to netmap bypass mode... ", sp->device); fflush(NULL); sleep(1); /* ensure message prints when user is connected via ssh */ if (ioctl (sp->handle.fd, NIOCREGIF, &nmr)) { snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Failure accessing netmap.\n" "\tRequest for netmap version %u failed.\n\tCompiled netmap driver is version %u.\n\tError=%s\n", sp->netmap_version, NETMAP_API, strerror(errno)); goto NETMAP_IF_FAILED; } if (!nmr.nr_memsize) { snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Netmap interface '%s' not configured.\n", device); goto NETMAP_IF_FAILED; } sp->mmap_size = nmr.nr_memsize; sp->mmap_addr = (struct netmap_d *)mmap (0, sp->mmap_size, PROT_WRITE | PROT_READ, MAP_SHARED, sp->handle.fd, 0); if (!sp->mmap_addr || sp->mmap_addr == MAP_FAILED) { snprintf (errbuf, SENDPACKET_ERRBUF_SIZE, "mmap: %s", strerror (errno)); goto MMAP_FAILED; } dbgx(1, "sendpacket_open_netmap: mapping %d Kbytes queues=%d", sp->mmap_size >> 10, nmr.nr_tx_rings); sp->nm_if = NETMAP_IF(sp->mmap_addr, nmr.nr_offset); sp->nmr = nmr; sp->handle_type = SP_TYPE_NETMAP; /* set up ring IDs */ sp->cur_tx_ring = 0; switch(nr_flags) { case NR_REG_DEFAULT: /* only use one queue to prevent TX reordering */ sp->first_tx_ring = sp->last_tx_ring = sp->cur_tx_ring = 0; break; case NR_REG_ALL_NIC: if (is_default) { sp->first_tx_ring = sp->last_tx_ring = sp->cur_tx_ring = 0; } else { sp->first_tx_ring = sp->cur_tx_ring = 0; sp->last_tx_ring = nmr.nr_tx_rings - 1; } break; case NR_REG_SW: sp->first_tx_ring = sp->last_tx_ring = sp->cur_tx_ring = nmr.nr_tx_rings; break; case NR_REG_NIC_SW: sp->first_tx_ring = sp->cur_tx_ring = 0; sp->last_tx_ring = nmr.nr_tx_rings; break; case NR_REG_ONE_NIC: sp->first_tx_ring = sp->last_tx_ring = sp->cur_tx_ring = nr_ringid; break; default: sp->first_tx_ring = sp->last_tx_ring = sp->cur_tx_ring = 0; } { /* debugging code */ int i; dbgx(1, "%s tx first=%d last=%d num=%d", ifname, sp->first_tx_ring, sp->last_tx_ring, sp->nmr.nr_tx_rings); for (i = 0; i <= sp->nmr.nr_tx_rings; i++) { #ifdef HAVE_NETMAP_RING_HEAD_TAIL dbgx(1, "TX%d 0x%p head=%d cur=%d tail=%d", i, NETMAP_TXRING(sp->nm_if, i), (NETMAP_TXRING(sp->nm_if, i))->head, (NETMAP_TXRING(sp->nm_if, i))->cur, (NETMAP_TXRING(sp->nm_if, i))->tail); #else dbgx(1, "TX%d 0x%p cur=%d avail=%d", i, NETMAP_TXRING(sp->nm_if, i), (NETMAP_TXRING(sp->nm_if, i))->cur, (NETMAP_TXRING(sp->nm_if, i))->avail); #endif } } dbgx(2, "Waiting %d seconds for phy reset...", ctx->options->netmap_delay); sleep(ctx->options->netmap_delay); dbg(2, "Ready!"); if (!sp->is_vale) { if (nm_do_ioctl(sp, SIOCGIFFLAGS, 0) < 0) goto NM_DO_IOCTL_FAILED; if ((sp->if_flags & IFF_RUNNING) == 0) { dbgx(1, "sendpacket_open_netmap: %s is not running", sp->device); snprintf (errbuf, SENDPACKET_ERRBUF_SIZE, "interface %s is not running - check cables\n", sp->device); goto NETMAP_IF_NOT_RUNNING; } if ((sp->if_flags & IFF_UP) == 0) { dbgx(1, "%s is down, bringing up...", sp->device); sp->if_flags |= IFF_UP; } /* set promiscuous mode */ sp->if_flags |= IFF_PROMISC; if (nm_do_ioctl(sp, SIOCSIFFLAGS, 0) < 0) goto NM_DO_IOCTL_FAILED; #ifdef linux /* disable: * - generic-segmentation-offload * - tcp-segmentation-offload * - rx-checksumming * - tx-checksumming */ if (nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GGSO) < 0 || nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GTSO) < 0 || nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GRXCSUM) < 0 || nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GTXCSUM) < 0) goto NM_DO_IOCTL_FAILED; sp->data = 0; if (nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_SGSO) < 0 || nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_STSO) < 0 || nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_SRXCSUM) < 0 || nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_STXCSUM)) goto NM_DO_IOCTL_FAILED; #endif } if(sp->abort) goto NETMAP_ABORT; notice("done!"); return sp; NM_DO_IOCTL_FAILED: snprintf (errbuf, SENDPACKET_ERRBUF_SIZE, "nm_do_ioctl: %s", strerror (errno)); NETMAP_IF_NOT_RUNNING: notice("failed!"); NETMAP_ABORT: fprintf(stderr, " Switching network driver for %s to normal mode... ", sp->device); fflush(NULL); munmap(sp->mmap_addr, sp->mmap_size); MMAP_FAILED: #if NETMAP_API < 10 ioctl(sp->handle.fd, NIOCUNREGIF, NULL); #endif NETMAP_IF_FAILED: NETMAP_IF_PARSE_FAIL: close (sp->handle.fd); OPEN_FAILED: safe_free(sp); IFACENAME_INVALID: NETMAP_NOT_INSTALLED: return NULL; }
static void start_threads(struct glob_arg *g) { int i; targs = calloc(g->nthreads, sizeof(*targs)); /* * Now create the desired number of threads, each one * using a single descriptor. */ for (i = 0; i < g->nthreads; i++) { bzero(&targs[i], sizeof(targs[i])); targs[i].fd = -1; /* default, with pcap */ targs[i].g = g; if (g->dev_type == DEV_NETMAP) { struct nmreq tifreq; int tfd; /* register interface. */ tfd = open("/dev/netmap", O_RDWR); if (tfd == -1) { D("Unable to open /dev/netmap: %s", strerror(errno)); continue; } targs[i].fd = tfd; bzero(&tifreq, sizeof(tifreq)); strncpy(tifreq.nr_name, g->ifname, sizeof(tifreq.nr_name)); tifreq.nr_version = NETMAP_API; if (g->host_ring) { tifreq.nr_ringid = NETMAP_SW_RING; } else { tifreq.nr_ringid = (g->nthreads > 1) ? (i | NETMAP_HW_RING) : 0; } parse_nmr_config(g->nmr_config, &tifreq); /* * if we are acting as a receiver only, do not touch the transmit ring. * This is not the default because many apps may use the interface * in both directions, but a pure receiver does not. */ if (g->td_body == receiver_body) { tifreq.nr_ringid |= NETMAP_NO_TX_POLL; } if ((ioctl(tfd, NIOCREGIF, &tifreq)) == -1) { D("Unable to register %s: %s", g->ifname, strerror(errno)); continue; } D("memsize is %d MB", tifreq.nr_memsize >> 20); targs[i].nmr = tifreq; targs[i].nifp = NETMAP_IF(g->mmap_addr, tifreq.nr_offset); D("nifp flags 0x%x", targs[i].nifp->ni_flags); /* start threads. */ if (g->host_ring) { targs[i].qfirst = (g->td_body == receiver_body ? tifreq.nr_rx_rings : tifreq.nr_tx_rings); targs[i].qlast = targs[i].qfirst + 1; } else { targs[i].qfirst = (g->nthreads > 1) ? i : 0; targs[i].qlast = (g->nthreads > 1) ? i+1 : (g->td_body == receiver_body ? tifreq.nr_rx_rings : tifreq.nr_tx_rings); } } else { targs[i].fd = g->main_fd; } targs[i].used = 1; targs[i].me = i; if (g->affinity >= 0) { if (g->affinity < g->cpus) targs[i].affinity = g->affinity; else targs[i].affinity = i % g->cpus; } else targs[i].affinity = -1; /* default, init packets */ initialize_packet(&targs[i]); if (pthread_create(&targs[i].thread, NULL, g->td_body, &targs[i]) == -1) { D("Unable to create thread %d: %s", i, strerror(errno)); targs[i].used = 0; } }
int netmap_open(struct nm_if *nmif) { char ifbuf[IF_NAMESIZE], *p; const char *ifname; int len; struct nmreq nmreq; if (nmif->nm_if_vale) { /* Attach hw interface to VALE switch. */ if (netmap_vale_attach(nmif) != 0) { netmap_close(nmif); return (-1); } /* Attach netmap-fwd to VALE switch. */ p = strchr(nmif->nm_if_name, ':'); len = 0; if (p) len = p - nmif->nm_if_name; memset(ifbuf, 0, sizeof(ifbuf)); snprintf(ifbuf, sizeof(ifbuf) - 1, "%.*s:nmfwd0", len, nmif->nm_if_name); ifname = ifbuf; } else ifname = nmif->nm_if_name; nmif->nm_if_fd = open("/dev/netmap", O_RDWR); if (nmif->nm_if_fd == -1) { perror("open"); return (-1); } memset(&nmreq, 0, sizeof(nmreq)); strlcpy(nmreq.nr_name, ifname, sizeof(nmreq.nr_name)); nmreq.nr_version = NETMAP_API; if (nohostring || nmif->nm_if_vale) nmreq.nr_flags = NR_REG_ALL_NIC; else nmreq.nr_flags = NR_REG_NIC_SW; if (nmif->nm_if_vale) nmreq.nr_tx_rings = nmreq.nr_rx_rings = 4; if (ioctl(nmif->nm_if_fd, NIOCREGIF, &nmreq) == -1) { perror("ioctl"); netmap_close(nmif); return (-1); } DPRINTF("fd: %d\n", nmif->nm_if_fd); DPRINTF("name: %s\n", nmreq.nr_name); DPRINTF("version: %d\n", nmreq.nr_version); DPRINTF("offset: %d\n", nmreq.nr_offset); DPRINTF("memsize: %d\n", nmreq.nr_memsize); DPRINTF("tx_slots: %d\n", nmreq.nr_tx_slots); DPRINTF("rx_slots: %d\n", nmreq.nr_rx_slots); DPRINTF("tx_rings: %d\n", nmreq.nr_tx_rings); DPRINTF("rx_rings: %d\n", nmreq.nr_rx_rings); DPRINTF("ringid: %#x\n", nmreq.nr_ringid); DPRINTF("flags: %#x\n", nmreq.nr_flags); nmif->nm_if_memsize = nmreq.nr_memsize; nmif->nm_if_mem = mmap(NULL, nmif->nm_if_memsize, PROT_READ | PROT_WRITE, MAP_SHARED, nmif->nm_if_fd, 0); if (nmif->nm_if_mem == MAP_FAILED) { perror("mmap"); netmap_close(nmif); return (-1); } nmif->nm_if_ifp = NETMAP_IF(nmif->nm_if_mem, nmreq.nr_offset); nmif->nm_if_ev_read = event_new(ev_get_base(), nmif->nm_if_fd, EV_READ | EV_PERSIST, netmap_read, nmif); event_add(nmif->nm_if_ev_read, NULL); return (0); }