static int thr_teardown(struct thr_ctx *ctx) { if (ctx->pa) nm_close(ctx->pa); if (ctx->pb) nm_close(ctx->pb); free(ctx->ifa); free(ctx->ifb); return (0); }
static void free_buffers(void) { struct netmap_ring *ring; if (pa == NULL) return; ring = NETMAP_RXRING(pa->nifp, pa->first_rx_ring); dedup_get_fifo_buffers(&dedup, ring, &pa->nifp->ni_bufs_head); nm_close(pa); nm_close(pb); }
static void free_buffers(void) { int i, tot = 0; struct port_des *rxport = &ports[glob_arg.output_rings]; /* build a netmap free list with the buffers in all the overflow queues */ for (i = 0; i < glob_arg.output_rings + 1; i++) { struct port_des *cp = &ports[i]; struct overflow_queue *q = cp->oq; if (!q) continue; while (q->n) { struct netmap_slot s = oq_deq(q); uint32_t *b = (uint32_t *)NETMAP_BUF(cp->ring, s.buf_idx); *b = rxport->nmd->nifp->ni_bufs_head; rxport->nmd->nifp->ni_bufs_head = s.buf_idx; tot++; } } D("added %d buffers to netmap free list", tot); for (i = 0; i < glob_arg.output_rings + 1; ++i) { nm_close(ports[i].nmd); } }
/* Close and destroy the Netmap port. The object pointed to by port is no longer valid after this operation. */ void fp_netmap_close(struct fp_device* device) { struct fp_netmap_device* dev = (struct fp_netmap_device*)device; nm_close(dev->handle); fp_deallocate(dev); }
/* Flush and close. */ static void netmap_cleanup(NetClientState *nc) { NetmapState *s = DO_UPCAST(NetmapState, nc, nc); qemu_purge_queued_packets(nc); netmap_poll(nc, false); nm_close(s->nmd); s->nmd = NULL; }
static PyObject * NetmapDesc_exit(NetmapDesc *self, PyObject *args) { if (self->nmd) { nm_close(self->nmd); self->nmd = NULL; } Py_RETURN_NONE; }
/* Destructor method for NetmapDescType. */ static void NetmapDesc_dealloc(NetmapDesc* self) { NetmapMemory_dealloc(&self->memory); if (self->nmd) { nm_close(self->nmd); self->nmd = NULL; } self->ob_type->tp_free((PyObject*)self); }
void nm_desc_destructor::operator()(nm_desc *d) const { // We wrap the fd in an asio handle, which takes care of closing it. // To prevent nm_close from closing it too, we nullify it here. d->fd = -1; int status = nm_close(d); if (status != 0) { std::error_code code(status, std::system_category()); log_warning("Failed to close the netmap fd: %1% (%2%)", code.value(), code.message()); } }
/** * Close netmap descriptors * * Can be reopened using netmap_start() function. * * @param pktio_entry Packet IO entry */ static inline void netmap_close_descriptors(pktio_entry_t *pktio_entry) { int i, j; pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; for (i = 0; i < PKTIO_MAX_QUEUES; i++) { for (j = 0; j < NM_MAX_DESC; j++) if (pkt_nm->rx_desc_ring[i].s.desc[j] != NULL) { nm_close(pkt_nm->rx_desc_ring[i].s.desc[j]); pkt_nm->rx_desc_ring[i].s.desc[j] = NULL; } for (j = 0; j < NM_MAX_DESC; j++) if (pkt_nm->tx_desc_ring[i].s.desc[j] != NULL) { nm_close(pkt_nm->tx_desc_ring[i].s.desc[j]); pkt_nm->tx_desc_ring[i].s.desc[j] = NULL; } } pkt_nm->num_rx_desc_rings = 0; pkt_nm->num_tx_desc_rings = 0; }
int main(int argc, char *argv[]) { struct nm_desc *d; struct pollfd pfd; char buf[2048]; int count = 0; if (argc < 2) { usage(argv[0]); } bzero(&pfd, sizeof(pfd)); d = nm_open(argv[1], NULL, 0, 0); if (d == NULL) { fprintf(stderr, "no netmap\n"); exit(0); } pfd.fd = d->fd; pfd.events = argv[2] && argv[2][0] == 'w' ? POLLOUT : POLLIN; fprintf(stderr, "working on %s in %s mode\n", argv[1], pfd.events == POLLIN ? "read" : "write"); for (;;) { if (pfd.events == POLLIN) { nm_dispatch(d, -1, my_cb, (void *)&count); } else { if (nm_inject(d, buf, 60) > 0) { count++; continue; } fprintf(stderr, "polling after sending %d\n", count); count = 0; } poll(&pfd, 1, 1000); } nm_close(d); return 0; }
static void pci_vtnet_netmap_setup(struct pci_vtnet_softc *sc, char *ifname) { sc->pci_vtnet_rx = pci_vtnet_netmap_rx; sc->pci_vtnet_tx = pci_vtnet_netmap_tx; sc->vsc_nmd = nm_open(ifname, NULL, 0, 0); if (sc->vsc_nmd == NULL) { WPRINTF(("open of netmap device %s failed\n", ifname)); return; } sc->vsc_mevp = mevent_add(sc->vsc_nmd->fd, EVF_READ, pci_vtnet_rx_callback, sc); if (sc->vsc_mevp == NULL) { WPRINTF(("Could not register event\n")); nm_close(sc->vsc_nmd); sc->vsc_nmd = NULL; } }
static int thr_ctx_setup(struct thr_ctx *th, char *ifa, char *ifb, int zerocopy, int burst, struct thr_ctx *parent, int cpuid) { int nm_flags = 0; struct nm_desc *p_pa = NULL; bzero(th, sizeof(struct thr_ctx)); th->ifa = strdup(ifa); th->ifb = strdup(ifb); th->zerocopy = zerocopy; th->burst = burst; th->cpuid = cpuid; /* Setup netmap rings */ if (parent) { nm_flags |= NM_OPEN_NO_MMAP; p_pa = parent->pa; } th->pa = nm_open(ifa, NULL, nm_flags, p_pa); if (th->pa == NULL) { D("cannot open %s", ifa); exit(1); } th->pb = nm_open(ifb, NULL, NM_OPEN_NO_MMAP, th->pa); if (th->pb == NULL) { D("cannot open %s", ifb); nm_close(th->pa); exit(1); } th->zerocopy = th->zerocopy && (th->pa->mem == th->pb->mem); /* Done */ return (0); }
void pico_netmap_destroy(struct pico_device *dev) { struct pico_device_netmap *netmap = (struct pico_device_netmap *) dev; nm_close(netmap->conn); }
void pcap_close(pcap_t *p) { nm_close(p); /* restore original flags ? */ }
static int pcap_netmap_dispatch(pcap_t *p, int cnt, pcap_handler cb, u_char *user) { int ret; struct pcap_netmap *pn = p->priv; struct nm_desc *d = pn->d; struct pollfd pfd = { .fd = p->fd, .events = POLLIN, .revents = 0 }; pn->cb = cb; pn->cb_arg = user; for (;;) { if (p->break_loop) { p->break_loop = 0; return PCAP_ERROR_BREAK; } /* nm_dispatch won't run forever */ ret = nm_dispatch((void *)d, cnt, (void *)pcap_netmap_filter, (void *)p); if (ret != 0) break; errno = 0; ret = poll(&pfd, 1, p->opt.timeout); } return ret; } /* XXX need to check the NIOCTXSYNC/poll */ static int pcap_netmap_inject(pcap_t *p, const void *buf, size_t size) { struct pcap_netmap *pn = p->priv; struct nm_desc *d = pn->d; return nm_inject(d, buf, size); } static int pcap_netmap_ioctl(pcap_t *p, u_long what, uint32_t *if_flags) { struct pcap_netmap *pn = p->priv; struct nm_desc *d = pn->d; struct ifreq ifr; int error, fd = d->fd; #ifdef linux fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { fprintf(stderr, "Error: cannot get device control socket.\n"); return -1; } #endif /* linux */ bzero(&ifr, sizeof(ifr)); strncpy(ifr.ifr_name, d->req.nr_name, sizeof(ifr.ifr_name)); switch (what) { case SIOCSIFFLAGS: /* * The flags we pass in are 32-bit and unsigned. * * On most if not all UN*Xes, ifr_flags is 16-bit and * signed, and the result of assigning a longer * unsigned value to a shorter signed value is * implementation-defined (even if, in practice, it'll * do what's intended on all platforms we support * result of assigning a 32-bit unsigned value). * So we mask out the upper 16 bits. */ ifr.ifr_flags = *if_flags & 0xffff; #ifdef __FreeBSD__ /* * In FreeBSD, we need to set the high-order flags, * as we're using IFF_PPROMISC, which is in those bits. * * XXX - DragonFly BSD? */ ifr.ifr_flagshigh = *if_flags >> 16; #endif /* __FreeBSD__ */ break; } error = ioctl(fd, what, &ifr); if (!error) { switch (what) { case SIOCGIFFLAGS: /* * The flags we return are 32-bit. * * On most if not all UN*Xes, ifr_flags is * 16-bit and signed, and will get sign- * extended, so that the upper 16 bits of * those flags will be forced on. So we * mask out the upper 16 bits of the * sign-extended value. */ *if_flags = ifr.ifr_flags & 0xffff; #ifdef __FreeBSD__ /* * In FreeBSD, we need to return the * high-order flags, as we're using * IFF_PPROMISC, which is in those bits. * * XXX - DragonFly BSD? */ *if_flags |= (ifr.ifr_flagshigh << 16); #endif /* __FreeBSD__ */ } } #ifdef linux close(fd); #endif /* linux */ return error ? -1 : 0; } static void pcap_netmap_close(pcap_t *p) { struct pcap_netmap *pn = p->priv; struct nm_desc *d = pn->d; uint32_t if_flags = 0; if (pn->must_clear_promisc) { pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */ if (if_flags & IFF_PPROMISC) { if_flags &= ~IFF_PPROMISC; pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags); } } nm_close(d); pcap_cleanup_live_common(p); } static int pcap_netmap_activate(pcap_t *p) { struct pcap_netmap *pn = p->priv; struct nm_desc *d; uint32_t if_flags = 0; d = nm_open(p->opt.device, NULL, 0, NULL); if (d == NULL) { pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "netmap open: cannot access %s", p->opt.device); pcap_cleanup_live_common(p); return (PCAP_ERROR); } if (0) fprintf(stderr, "%s device %s priv %p fd %d ports %d..%d\n", __FUNCTION__, p->opt.device, d, d->fd, d->first_rx_ring, d->last_rx_ring); pn->d = d; p->fd = d->fd; /* * Turn a negative snapshot value (invalid), a snapshot value of * 0 (unspecified), or a value bigger than the normal maximum * value, into the maximum allowed value. * * If some application really *needs* a bigger snapshot * length, we should just increase MAXIMUM_SNAPLEN. */ if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) p->snapshot = MAXIMUM_SNAPLEN; if (p->opt.promisc && !(d->req.nr_ringid & NETMAP_SW_RING)) { pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */ if (!(if_flags & IFF_PPROMISC)) { pn->must_clear_promisc = 1; if_flags |= IFF_PPROMISC; pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags); } } p->linktype = DLT_EN10MB; p->selectable_fd = p->fd; p->read_op = pcap_netmap_dispatch; p->inject_op = pcap_netmap_inject, p->setfilter_op = install_bpf_program; p->setdirection_op = NULL; p->set_datalink_op = NULL; p->getnonblock_op = pcap_getnonblock_fd; p->setnonblock_op = pcap_setnonblock_fd; p->stats_op = pcap_netmap_stats; p->cleanup_op = pcap_netmap_close; return (0); } pcap_t * pcap_netmap_create(const char *device, char *ebuf, int *is_ours) { pcap_t *p; *is_ours = (!strncmp(device, "netmap:", 7) || !strncmp(device, "vale", 4)); if (! *is_ours) return NULL; p = pcap_create_common(ebuf, sizeof (struct pcap_netmap)); if (p == NULL) return (NULL); p->activate_op = pcap_netmap_activate; return (p); }
int main(int argc, char **argv) { int index = 0; int channel_nums = 4; int member = 2; const char *ifname = NULL; struct thread_args_t targs[MAX_RINGS]; memset(targs, 0x0, sizeof(targs)); if (argc < 2 || argc > 3) { printf("Usage:%s [interface] <channel nums>\n", argv[1]); return 1; } ifname = argv[1]; if (argc == 3) { channel_nums = atoi(argv[2]); } if (channel_nums < 1 || channel_nums > MAX_RINGS || (MAX_RINGS % channel_nums) != 0 ) { printf("channel nums error.\n"); return 1; } member = MAX_RINGS / channel_nums; for (index = 0; index < channel_nums; index++) { char buff[64]; memset(buff,0x0, 64); struct thread_args_t *thread_arg = &targs[index]; unsigned short start = index * member; unsigned short end = start + member - 1; snprintf(buff, 63, "netmap:%s+%d.%d", ifname, start, end); thread_arg->desc = nm_open(buff, NULL, NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL, NULL); if ( thread_arg->desc == NULL) { D("cannot open eth0"); return 1; } printf("%d first_rx_ring:%d last_rx_rings:%d ", index, thread_arg->desc->first_rx_ring, thread_arg->desc->last_rx_ring); printf(" first_tx_ring:%d last_tx_rings:%d\n", thread_arg->desc->first_tx_ring, thread_arg->desc->last_tx_ring); thread_arg->affinity = index; pthread_create(&(thread_arg->thread), NULL, run, (void*)thread_arg); pthread_detach(thread_arg->thread); } main_loop_statistics(targs, channel_nums); for (index = 0; index < channel_nums; index ++) { nm_close(targs[index].desc); } D("exiting"); return (0); }
static int netmap_open(odp_pktio_t id ODP_UNUSED, pktio_entry_t *pktio_entry, const char *netdev, odp_pool_t pool) { int i; int err; int sockfd; int mtu; uint32_t buf_size; pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; struct nm_desc *desc; struct netmap_ring *ring; odp_pktin_hash_proto_t hash_proto; odp_pktio_stats_t cur_stats; if (getenv("ODP_PKTIO_DISABLE_NETMAP")) return -1; if (pool == ODP_POOL_INVALID) return -1; /* Init pktio entry */ memset(pkt_nm, 0, sizeof(*pkt_nm)); pkt_nm->sockfd = -1; pkt_nm->pool = pool; /* max frame len taking into account the l2-offset */ pkt_nm->max_frame_len = ODP_CONFIG_PACKET_BUF_LEN_MAX - odp_buffer_pool_headroom(pool) - odp_buffer_pool_tailroom(pool); snprintf(pktio_entry->s.name, sizeof(pktio_entry->s.name), "%s", netdev); snprintf(pkt_nm->nm_name, sizeof(pkt_nm->nm_name), "netmap:%s", netdev); /* Dummy open here to check if netmap module is available and to read * capability info. */ desc = nm_open(pkt_nm->nm_name, NULL, 0, NULL); if (desc == NULL) { ODP_ERR("nm_open(%s) failed\n", pkt_nm->nm_name); goto error; } if (desc->nifp->ni_rx_rings > NM_MAX_DESC) { ODP_ERR("Unable to store all rx rings\n"); nm_close(desc); goto error; } pkt_nm->num_rx_rings = desc->nifp->ni_rx_rings; pkt_nm->capa.max_input_queues = PKTIO_MAX_QUEUES; if (desc->nifp->ni_rx_rings < PKTIO_MAX_QUEUES) pkt_nm->capa.max_input_queues = desc->nifp->ni_rx_rings; if (desc->nifp->ni_tx_rings > NM_MAX_DESC) { ODP_ERR("Unable to store all tx rings\n"); nm_close(desc); goto error; } pkt_nm->num_tx_rings = desc->nifp->ni_tx_rings; pkt_nm->capa.max_output_queues = PKTIO_MAX_QUEUES; if (desc->nifp->ni_tx_rings < PKTIO_MAX_QUEUES) pkt_nm->capa.max_output_queues = desc->nifp->ni_tx_rings; ring = NETMAP_RXRING(desc->nifp, desc->cur_rx_ring); buf_size = ring->nr_buf_size; nm_close(desc); sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd == -1) { ODP_ERR("Cannot get device control socket\n"); goto error; } pkt_nm->sockfd = sockfd; /* Use either interface MTU (+ ethernet header length) or netmap buffer * size as MTU, whichever is smaller. */ mtu = mtu_get_fd(pktio_entry->s.pkt_nm.sockfd, pktio_entry->s.name) + ODPH_ETHHDR_LEN; if (mtu < 0) { ODP_ERR("Unable to read interface MTU\n"); goto error; } pkt_nm->mtu = ((uint32_t)mtu < buf_size) ? (uint32_t)mtu : buf_size; /* Check if RSS is supported. If not, set 'max_input_queues' to 1. */ if (rss_conf_get_supported_fd(sockfd, netdev, &hash_proto) == 0) { ODP_DBG("RSS not supported\n"); pkt_nm->capa.max_input_queues = 1; } err = netmap_do_ioctl(pktio_entry, SIOCGIFFLAGS, 0); if (err) goto error; if ((pkt_nm->if_flags & IFF_UP) == 0) ODP_DBG("%s is down\n", pktio_entry->s.name); err = mac_addr_get_fd(sockfd, netdev, pkt_nm->if_mac); if (err) goto error; for (i = 0; i < PKTIO_MAX_QUEUES; i++) { odp_ticketlock_init(&pkt_nm->rx_desc_ring[i].s.lock); odp_ticketlock_init(&pkt_nm->tx_desc_ring[i].s.lock); } /* netmap uses only ethtool to get statistics counters */ err = ethtool_stats_get_fd(pktio_entry->s.pkt_nm.sockfd, pktio_entry->s.name, &cur_stats); if (err) { ODP_ERR( "netmap pktio %s does not support statistics counters\n", pktio_entry->s.name); pktio_entry->s.stats_type = STATS_UNSUPPORTED; } else { pktio_entry->s.stats_type = STATS_ETHTOOL; } (void)netmap_stats_reset(pktio_entry); return 0; error: netmap_close(pktio_entry); return -1; }
int main(int argc, char **argv) { struct pollfd pollfd[2]; int ch; char *ifa = NULL, *ifb = NULL; int wait_link = 2; int win_size_usec = 50; unsigned int fifo_size = 10; int n; int hold = 0; struct nmreq base_req; uint32_t buf_head = 0; #ifdef DEDUP_HASH_STAT time_t last_hash_output = 0; #endif fprintf(stderr, "%s built %s %s\n\n", argv[0], __DATE__, __TIME__); while ((ch = getopt(argc, argv, "hci:vw:W:F:H")) != -1) { switch (ch) { default: D("bad option %c %s", ch, optarg); /* fallthrough */ case 'h': usage(); break; case 'i': /* interface */ if (ifa == NULL) ifa = optarg; else if (ifb == NULL) ifb = optarg; else D("%s ignored, already have 2 interfaces", optarg); break; case 'c': zerocopy = 0; /* do not zerocopy */ break; case 'v': verbose++; break; case 'w': wait_link = atoi(optarg); break; case 'W': win_size_usec = atoi(optarg); break; case 'F': fifo_size = atoi(optarg); break; case 'H': hold = 1; break; } } if (!ifa || !ifb) { D("missing interface"); usage(); } memset(&base_req, 0, sizeof(base_req)); if (!hold) { base_req.nr_arg3 = fifo_size; } pa = nm_open(ifa, &base_req, 0, NULL); if (pa == NULL) { D("cannot open %s", ifa); return (1); } if (!hold) { if (base_req.nr_arg3 != fifo_size) { D("failed to allocate %u extra buffers", fifo_size); return (1); // XXX failover to copy? } else { buf_head = pa->nifp->ni_bufs_head; } } if (pa->first_rx_ring != pa->last_rx_ring) { D("%s: too many RX rings (%d)", pa->req.nr_name, pa->last_rx_ring - pa->first_rx_ring + 1); return (1); } /* try to reuse the mmap() of the first interface, if possible */ pb = nm_open(ifb, NULL, NM_OPEN_NO_MMAP, pa); if (pb == NULL) { D("cannot open %s", ifb); nm_close(pa); return (1); } if (pb->first_tx_ring != pb->last_tx_ring) { D("%s: too many TX rings (%d)", pb->req.nr_name, pb->last_rx_ring - pb->first_rx_ring + 1); nm_close(pa); return (1); } memset(&dedup, 0, sizeof(dedup)); dedup.out_slot = dedup.out_ring->slot; if (dedup_init(&dedup, fifo_size, NETMAP_RXRING(pa->nifp, pa->first_rx_ring), NETMAP_TXRING(pb->nifp, pb->first_tx_ring)) < 0) { D("failed to initialize dedup with fifo_size %u", fifo_size); return (1); } if (fifo_size >= dedup.out_ring->num_slots - 1) { D("fifo_size %u too large (max %u)", fifo_size, dedup.out_ring->num_slots - 1); return (1); } if (dedup_set_fifo_buffers(&dedup, NULL, buf_head) != 0) { D("failed to set 'hold packets' option"); return (1); } pa->nifp->ni_bufs_head = 0; atexit(free_buffers); /* enable/disable zerocopy */ dedup.in_memid = pa->req.nr_arg2; dedup.out_memid = (zerocopy ? pb->req.nr_arg2 : -1 ); dedup.fifo_memid = hold ? dedup.out_memid : dedup.in_memid; D("memids: in %d out %d fifo %d", dedup.in_memid, dedup.out_memid, dedup.fifo_memid); dedup.win_size.tv_sec = win_size_usec / 1000000; dedup.win_size.tv_usec = win_size_usec % 1000000; D("win_size %lld+%lld", (long long) dedup.win_size.tv_sec, (long long) dedup.win_size.tv_usec); /* setup poll(2) array */ memset(pollfd, 0, sizeof(pollfd)); 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 -> %s", pa->req.nr_name, pb->req.nr_name); /* main loop */ signal(SIGINT, sigint_h); n = 0; while (!do_abort) { int ret; struct timeval now; pollfd[0].events = pollfd[1].events = 0; pollfd[0].revents = pollfd[1].revents = 0; if (!n) pollfd[0].events = POLLIN; else pollfd[1].events = POLLOUT; /* poll() also cause kernel to txsync/rxsync the NICs */ ret = poll(pollfd, 2, 1000); gettimeofday(&now, NULL); if (ret <= 0 || verbose) D("poll %s [0] ev %x %x" " [1] ev %x %x", ret <= 0 ? "timeout" : "ok", pollfd[0].events, pollfd[0].revents, pollfd[1].events, pollfd[1].revents ); n = dedup_push_in(&dedup, &now); #ifdef DEDUP_HASH_STAT if (now.tv_sec != last_hash_output) { unsigned int i; last_hash_output = now.tv_sec; printf("buckets: "); for (i = 0; i <= dedup.hashmap_mask; i++) { if (dedup.hashmap[i].bucket_size) printf("%u: %u, ", i, dedup.hashmap[i].bucket_size); } printf("\n"); } #endif } return (0); }
/* * bridge [-v] if1 [if2] * * If only one name, or the two interfaces are the same, * bridges userland and the adapter. Otherwise bridge * two intefaces. */ int main(int argc, char **argv) { struct pollfd pollfd[2]; int ch; u_int burst = 1024, wait_link = 4; struct nm_desc *pa = NULL, *pb = NULL; char *ifa = NULL, *ifb = NULL; char ifabuf[64] = { 0 }; fprintf(stderr, "%s built %s %s\n", argv[0], __DATE__, __TIME__); while ( (ch = getopt(argc, argv, "b:ci:vw:")) != -1) { switch (ch) { default: D("bad option %c %s", ch, optarg); usage(); break; case 'b': /* burst */ burst = atoi(optarg); break; case 'i': /* interface */ if (ifa == NULL) ifa = optarg; else if (ifb == NULL) ifb = optarg; else D("%s ignored, already have 2 interfaces", optarg); break; case 'c': zerocopy = 0; /* do not zerocopy */ break; case 'v': verbose++; break; case 'w': wait_link = atoi(optarg); break; } } argc -= optind; argv += optind; if (argc > 1) ifa = argv[1]; if (argc > 2) ifb = argv[2]; if (argc > 3) burst = atoi(argv[3]); if (!ifb) ifb = ifa; if (!ifa) { D("missing interface"); usage(); } if (burst < 1 || burst > 8192) { D("invalid burst %d, set to 1024", burst); burst = 1024; } if (wait_link > 100) { D("invalid wait_link %d, set to 4", wait_link); wait_link = 4; } if (!strcmp(ifa, ifb)) { D("same interface, endpoint 0 goes to host"); snprintf(ifabuf, sizeof(ifabuf) - 1, "%s^", ifa); ifa = ifabuf; } else { /* two different interfaces. Take all rings on if1 */ } pa = nm_open(ifa, NULL, 0, NULL); if (pa == NULL) { D("cannot open %s", ifa); return (1); } // XXX use a single mmap ? pb = nm_open(ifb, NULL, NM_OPEN_NO_MMAP, pa); if (pb == NULL) { D("cannot open %s", ifb); nm_close(pa); return (1); } zerocopy = zerocopy && (pa->mem == pb->mem); D("------- zerocopy %ssupported", zerocopy ? "" : "NOT "); /* setup poll(2) variables. */ memset(pollfd, 0, sizeof(pollfd)); 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.", 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); while (!do_abort) { int n0, n1, ret; pollfd[0].events = pollfd[1].events = 0; pollfd[0].revents = pollfd[1].revents = 0; n0 = pkt_queued(pa, 0); n1 = pkt_queued(pb, 0); if (n0) pollfd[1].events |= POLLOUT; else pollfd[0].events |= POLLIN; if (n1) pollfd[0].events |= POLLOUT; else pollfd[1].events |= POLLIN; ret = poll(pollfd, 2, 2500); if (ret <= 0 || verbose) D("poll %s [0] ev %x %x rx %d@%d tx %d," " [1] ev %x %x rx %d@%d tx %d", ret <= 0 ? "timeout" : "ok", pollfd[0].events, pollfd[0].revents, pkt_queued(pa, 0), NETMAP_RXRING(pa->nifp, pa->cur_rx_ring)->cur, pkt_queued(pa, 1), pollfd[1].events, pollfd[1].revents, pkt_queued(pb, 0), NETMAP_RXRING(pb->nifp, pb->cur_rx_ring)->cur, pkt_queued(pb, 1) ); if (ret < 0) continue; if (pollfd[0].revents & POLLERR) { struct netmap_ring *rx = NETMAP_RXRING(pa->nifp, pa->cur_rx_ring); D("error on fd0, rx [%d,%d,%d)", rx->head, rx->cur, rx->tail); } if (pollfd[1].revents & POLLERR) { struct netmap_ring *rx = NETMAP_RXRING(pb->nifp, pb->cur_rx_ring); D("error on fd1, rx [%d,%d,%d)", rx->head, rx->cur, rx->tail); } if (pollfd[0].revents & POLLOUT) { move(pb, pa, burst); // XXX we don't need the ioctl */ // ioctl(me[0].fd, NIOCTXSYNC, NULL); } if (pollfd[1].revents & POLLOUT) { move(pa, pb, burst); // XXX we don't need the ioctl */ // ioctl(me[1].fd, NIOCTXSYNC, NULL); } } D("exiting"); nm_close(pb); nm_close(pa); return (0); }
/* * bridge [-v] if1 [if2] * * If only one name, or the two interfaces are the same, * bridges userland and the adapter. Otherwise bridge * two intefaces. */ int main(int argc, char **argv) { struct pollfd pollfd[2]; int ch; u_int burst = 1024, wait_link = 4; struct nm_desc *pa = NULL, *pb = NULL; char *ifa = NULL, *ifb = NULL; char ifabuf[64] = { 0 }; int loopback = 0; fprintf(stderr, "%s built %s %s\n\n", argv[0], __DATE__, __TIME__); while ((ch = getopt(argc, argv, "hb:ci:vw:L")) != -1) { switch (ch) { default: D("bad option %c %s", ch, optarg); /* fallthrough */ case 'h': usage(); break; case 'b': /* burst */ burst = atoi(optarg); break; case 'i': /* interface */ if (ifa == NULL) ifa = optarg; else if (ifb == NULL) ifb = optarg; else D("%s ignored, already have 2 interfaces", optarg); break; case 'c': zerocopy = 0; /* do not zerocopy */ break; case 'v': verbose++; break; case 'w': wait_link = atoi(optarg); break; case 'L': loopback = 1; break; } } argc -= optind; argv += optind; if (argc > 0) ifa = argv[0]; if (argc > 1) ifb = argv[1]; if (argc > 2) burst = atoi(argv[2]); if (!ifb) ifb = ifa; if (!ifa) { D("missing interface"); usage(); } if (burst < 1 || burst > 8192) { D("invalid burst %d, set to 1024", burst); burst = 1024; } if (wait_link > 100) { D("invalid wait_link %d, set to 4", wait_link); wait_link = 4; } if (!strcmp(ifa, ifb)) { if (!loopback) { D("same interface, endpoint 0 goes to host"); snprintf(ifabuf, sizeof(ifabuf) - 1, "%s^", ifa); ifa = ifabuf; } else { D("same interface, loopbacking traffic"); } } else { /* two different interfaces. Take all rings on if1 */ } pa = nm_open(ifa, NULL, 0, NULL); if (pa == NULL) { D("cannot open %s", ifa); return (1); } /* try to reuse the mmap() of the first interface, if possible */ pb = nm_open(ifb, NULL, NM_OPEN_NO_MMAP, pa); if (pb == NULL) { D("cannot open %s", ifb); nm_close(pa); return (1); } zerocopy = zerocopy && (pa->mem == pb->mem); D("------- zerocopy %ssupported", zerocopy ? "" : "NOT "); /* setup poll(2) array */ memset(pollfd, 0, sizeof(pollfd)); 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.", 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); while (!do_abort) { int n0, n1, ret; pollfd[0].events = pollfd[1].events = 0; pollfd[0].revents = pollfd[1].revents = 0; n0 = pkt_queued(pa, 0); n1 = pkt_queued(pb, 0); #if defined(_WIN32) || defined(BUSYWAIT) if (n0) { ioctl(pollfd[1].fd, NIOCTXSYNC, NULL); pollfd[1].revents = POLLOUT; } else { ioctl(pollfd[0].fd, NIOCRXSYNC, NULL); } if (n1) { ioctl(pollfd[0].fd, NIOCTXSYNC, NULL); pollfd[0].revents = POLLOUT; } else { ioctl(pollfd[1].fd, NIOCRXSYNC, NULL); } ret = 1; #else if (n0) pollfd[1].events |= POLLOUT; else pollfd[0].events |= POLLIN; if (n1) pollfd[0].events |= POLLOUT; else pollfd[1].events |= POLLIN; /* poll() also cause kernel to txsync/rxsync the NICs */ ret = poll(pollfd, 2, 2500); #endif /* defined(_WIN32) || defined(BUSYWAIT) */ if (ret <= 0 || verbose) D("poll %s [0] ev %x %x rx %d@%d tx %d," " [1] ev %x %x rx %d@%d tx %d", ret <= 0 ? "timeout" : "ok", pollfd[0].events, pollfd[0].revents, pkt_queued(pa, 0), NETMAP_RXRING(pa->nifp, pa->cur_rx_ring)->cur, pkt_queued(pa, 1), pollfd[1].events, pollfd[1].revents, pkt_queued(pb, 0), NETMAP_RXRING(pb->nifp, pb->cur_rx_ring)->cur, pkt_queued(pb, 1) ); if (ret < 0) continue; if (pollfd[0].revents & POLLERR) { struct netmap_ring *rx = NETMAP_RXRING(pa->nifp, pa->cur_rx_ring); D("error on fd0, rx [%d,%d,%d)", rx->head, rx->cur, rx->tail); } if (pollfd[1].revents & POLLERR) { struct netmap_ring *rx = NETMAP_RXRING(pb->nifp, pb->cur_rx_ring); D("error on fd1, rx [%d,%d,%d)", rx->head, rx->cur, rx->tail); } if (pollfd[0].revents & POLLOUT) move(pb, pa, burst); if (pollfd[1].revents & POLLOUT) move(pa, pb, burst); /* We don't need ioctl(NIOCTXSYNC) on the two file descriptors here, * kernel will txsync on next poll(). */ } nm_close(pb); nm_close(pa); return (0); }
static int pcap_netmap_dispatch(pcap_t *p, int cnt, pcap_handler cb, u_char *user) { int ret; struct pcap_netmap *pn = NM_PRIV(p); struct nm_desc *d = pn->d; struct pollfd pfd = { .fd = p->fd, .events = POLLIN, .revents = 0 }; pn->cb = cb; pn->cb_arg = user; for (;;) { if (p->break_loop) { p->break_loop = 0; return PCAP_ERROR_BREAK; } /* nm_dispatch won't run forever */ ret = nm_dispatch((void *)d, cnt, (void *)pcap_netmap_filter, (void *)p); if (ret != 0) break; errno = 0; ret = poll(&pfd, 1, p->the_timeout); } return ret; } /* XXX need to check the NIOCTXSYNC/poll */ static int pcap_netmap_inject(pcap_t *p, const void *buf, size_t size) { struct nm_desc *d = NM_PRIV(p)->d; return nm_inject(d, buf, size); } static int pcap_netmap_ioctl(pcap_t *p, u_long what, uint32_t *if_flags) { struct pcap_netmap *pn = NM_PRIV(p); struct nm_desc *d = pn->d; struct ifreq ifr; int error, fd = d->fd; #ifdef linux fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { fprintf(stderr, "Error: cannot get device control socket.\n"); return -1; } #endif /* linux */ bzero(&ifr, sizeof(ifr)); strncpy(ifr.ifr_name, d->req.nr_name, sizeof(ifr.ifr_name)); switch (what) { case SIOCSIFFLAGS: ifr.ifr_flags = *if_flags; #ifdef __FreeBSD__ ifr.ifr_flagshigh = *if_flags >> 16; #endif /* __FreeBSD__ */ break; } error = ioctl(fd, what, &ifr); if (!error) { switch (what) { case SIOCGIFFLAGS: *if_flags = ifr.ifr_flags; #ifdef __FreeBSD__ *if_flags |= (ifr.ifr_flagshigh << 16); #endif /* __FreeBSD__ */ } } #ifdef linux close(fd); #endif /* linux */ return error ? -1 : 0; } static void pcap_netmap_close(pcap_t *p) { struct pcap_netmap *pn = NM_PRIV(p); struct nm_desc *d = pn->d; uint32_t if_flags = 0; if (pn->must_clear_promisc) { pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */ if (if_flags & IFF_PPROMISC) { if_flags &= ~IFF_PPROMISC; pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags); } } nm_close(d); #ifdef HAVE_NO_PRIV free(pn); SET_PRIV(p, NULL); // unnecessary #endif pcap_cleanup_live_common(p); } static int pcap_netmap_activate(pcap_t *p) { struct pcap_netmap *pn = NM_PRIV(p); struct nm_desc *d = nm_open(p->opt.source, NULL, 0, NULL); uint32_t if_flags = 0; if (d == NULL) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "netmap open: cannot access %s: %s\n", p->opt.source, pcap_strerror(errno)); #ifdef HAVE_NO_PRIV free(pn); SET_PRIV(p, NULL); // unnecessary #endif pcap_cleanup_live_common(p); return (PCAP_ERROR); } if (0) fprintf(stderr, "%s device %s priv %p fd %d ports %d..%d\n", __FUNCTION__, p->opt.source, d, d->fd, d->first_rx_ring, d->last_rx_ring); pn->d = d; p->fd = d->fd; if (p->opt.promisc && !(d->req.nr_ringid & NETMAP_SW_RING)) { pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */ if (!(if_flags & IFF_PPROMISC)) { pn->must_clear_promisc = 1; if_flags |= IFF_PPROMISC; pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags); } } p->linktype = DLT_EN10MB; p->selectable_fd = p->fd; p->read_op = pcap_netmap_dispatch; p->inject_op = pcap_netmap_inject, p->setfilter_op = install_bpf_program; p->setdirection_op = NULL; p->set_datalink_op = NULL; p->getnonblock_op = pcap_getnonblock_fd; p->setnonblock_op = pcap_setnonblock_fd; p->stats_op = pcap_netmap_stats; p->cleanup_op = pcap_netmap_close; return (0); } pcap_t * pcap_netmap_create(const char *device, char *ebuf, int *is_ours) { pcap_t *p; *is_ours = (!strncmp(device, "netmap:", 7) || !strncmp(device, "vale", 4)); if (! *is_ours) return NULL; #ifdef HAVE_NO_PRIV { void *pn = calloc(1, sizeof(struct pcap_netmap)); if (pn == NULL) return NULL; p = pcap_create_common(device, ebuf); if (p == NULL) { free(pn); return NULL; } SET_PRIV(p, pn); } #else p = pcap_create_common(device, ebuf, sizeof (struct pcap_netmap)); if (p == NULL) return (NULL); #endif p->activate_op = pcap_netmap_activate; return (p); }
void usnet_dispatch() { struct netmap_if *nifp; struct pollfd fds; struct netmap_ring *rxring; int ret; nifp = g_nmd->nifp; fds.fd = g_nmd->fd; while(!do_abort) { //fds.events = POLLIN | POLLOUT; fds.events = POLLIN; fds.revents = 0; ret = poll(&fds, 1, 3000); if (ret <= 0 ) { DEBUG("poll %s ev %x %x rx @%d:%d:%d ", ret <= 0 ? "timeout" : "ok", fds.events, fds.revents, NETMAP_RXRING(g_nmd->nifp, g_nmd->cur_rx_ring)->head, NETMAP_RXRING(g_nmd->nifp, g_nmd->cur_rx_ring)->cur, NETMAP_RXRING(g_nmd->nifp, g_nmd->cur_rx_ring)->tail); DEBUG("poll %s ev %x %x tx @%d:%d:%d ", ret <= 0 ? "timeout" : "ok", fds.events, fds.revents, NETMAP_RXRING(g_nmd->nifp, g_nmd->cur_tx_ring)->head, NETMAP_RXRING(g_nmd->nifp, g_nmd->cur_tx_ring)->cur, NETMAP_RXRING(g_nmd->nifp, g_nmd->cur_tx_ring)->tail); continue; } if (fds.revents & POLLERR) { struct netmap_ring *rx = NETMAP_RXRING(nifp, g_nmd->cur_rx_ring); (void)rx; DEBUG("error on em1, rx [%d,%d,%d]", rx->head, rx->cur, rx->tail); } /* if (fds.revents & POLLOUT) { for (int j = g_nmd->first_tx_ring; j <= g_nmd->last_tx_ring; j++) { txring = NETMAP_RXRING(nifp, j); DEBUG("Ring info tx(%d), head=%d, cur=%d, tail=%d", j, txring->head, txring->cur, txring->tail); if (nm_ring_empty(txring)) { continue; } //send_packets(rxring, 512, 1); } } */ if (fds.revents & POLLIN) { int j; for (j = g_nmd->first_rx_ring; j <= g_nmd->last_rx_ring; j++) { rxring = NETMAP_RXRING(nifp, j); DEBUG("Ring info rx(%d), head=%d, cur=%d, tail=%d", j, rxring->head, rxring->cur, rxring->tail); if (nm_ring_empty(rxring)) { continue; } receive_packets(rxring, 512, 1); } } } nm_close(g_nmd); return; }