/* The exported init function * * ... -net netmap,ifname="..." */ int net_init_netmap(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { const NetdevNetmapOptions *netmap_opts = &netdev->u.netmap; struct nm_desc *nmd; NetClientState *nc; Error *err = NULL; NetmapState *s; nmd = netmap_open(netmap_opts, &err); if (err) { error_propagate(errp, err); return -1; } /* Create the object. */ nc = qemu_new_net_client(&net_netmap_info, peer, "netmap", name); s = DO_UPCAST(NetmapState, nc, nc); s->nmd = nmd; s->tx = NETMAP_TXRING(nmd->nifp, 0); s->rx = NETMAP_RXRING(nmd->nifp, 0); s->vnet_hdr_len = 0; pstrcpy(s->ifname, sizeof(s->ifname), netmap_opts->ifname); netmap_read_poll(s, true); /* Initially only poll for reads. */ return 0; }
pcap_t * pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *errbuf) { struct pcap_ring *me; int l; (void)snaplen; /* UNUSED */ (void)errbuf; /* UNUSED */ if (!device) { D("missing device name"); return NULL; } 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("error opening %s", device); free(me); return NULL; } me->to_ms = to_ms; return (pcap_t *)me; }
unsigned int peak_netmap_attach(const char *ifname) { struct my_ring *slot = NULL; struct my_ring **me = NULL; struct pollfd *fd = NULL; unsigned int i; NETMAP_LOCK(); /* lazy init */ if (!NETMAP_COUNT()) { bzero(self, sizeof(*self)); prealloc_init(&self->pkt_pool, NETMAP_MAX, sizeof(struct _peak_netmap)); prealloc_init(&self->me_pool, NETMAP_MAX, sizeof(struct my_ring)); } i = peak_netmap_find(ifname); if (i < NETMAP_COUNT()) { NETMAP_UNLOCK(); alert("netmap interface %s already attached\n"); return (1); } slot = NETMAP_GET(); if (!slot) { NETMAP_UNLOCK(); alert("netmap interface capacity reached\n"); return (1); } bzero(slot, sizeof(*slot)); me = &self->me[NETMAP_COUNT() - 1]; fd = &self->fd[NETMAP_COUNT() - 1]; slot->ifname = strdup(ifname); if (netmap_open(slot, 0, 1)) { free(slot->ifname); NETMAP_PUT(slot); NETMAP_UNLOCK(); alert("could not open netmap device %s\n", ifname); return (1); } *me = slot; fd->fd = slot->fd; NETMAP_UNLOCK(); 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 i, ch; u_int burst = 1024, wait_link = 4; struct my_ring me[2]; 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: 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 '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; } /* 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; } else { /* two different interfaces. Take all rings on if1 */ i = 0; // all hw rings } if (netmap_open(me, i, 1)) return (1); me[1].mem = me[0].mem; /* copy the pointer, so only one mmap */ if (netmap_open(me+1, 0, 1)) 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); } 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); /* 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(me, 0); n1 = pkt_queued(me + 1, 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(me, 0), me[0].rx->cur, pkt_queued(me, 1), pollfd[1].events, pollfd[1].revents, pkt_queued(me+1, 0), me[1].rx->cur, pkt_queued(me+1, 1) ); if (ret < 0) continue; if (pollfd[0].revents & POLLERR) { D("error on fd0, rxcur %d@%d", me[0].rx->avail, me[0].rx->cur); } if (pollfd[1].revents & POLLERR) { D("error on fd1, rxcur %d@%d", me[1].rx->avail, me[1].rx->cur); } if (pollfd[0].revents & POLLOUT) { move(me + 1, me, burst); // XXX we don't need the ioctl */ // ioctl(me[0].fd, NIOCTXSYNC, NULL); } if (pollfd[1].revents & POLLOUT) { move(me, me + 1, burst); // XXX we don't need the ioctl */ // ioctl(me[1].fd, NIOCTXSYNC, NULL); } } D("exiting"); netmap_close(me + 1); netmap_close(me + 0); return (0); }