/* netmap_pipe_krings_delete. * * There are two cases: * * 1) state is * * usr1 --> e1 --> e2 * * and we are e1 (e2 is not registered, so krings_delete cannot be * called on it); * * 2) state is * * usr1 --> e1 e2 <-- usr2 * * and we are either e1 or e2. * * In the former case we have to also delete the krings of e2; * in the latter case we do nothing (note that our krings * have already been hidden in the unregister callback). */ static void netmap_pipe_krings_delete(struct netmap_adapter *na) { struct netmap_pipe_adapter *pna = (struct netmap_pipe_adapter *)na; struct netmap_adapter *ona; /* na of the other end */ int i; if (!pna->peer_ref) { ND("%p: case 2, kept alive by peer", na); return; } /* case 1) above */ ND("%p: case 1, deleting everyhing", na); netmap_krings_delete(na); /* also zeroes tx_rings etc. */ /* restore the ring to be deleted on the peer */ ona = &pna->peer->up; if (ona->tx_rings == NULL) { /* already deleted, we must be on an * cleanup-after-error path */ return; } for (i = 0; i < ona->num_tx_rings + 1; i++) ona->tx_rings[i].ring = ona->tx_rings[i].save_ring; for (i = 0; i < ona->num_rx_rings + 1; i++) ona->rx_rings[i].ring = ona->rx_rings[i].save_ring; netmap_mem_rings_delete(ona); netmap_krings_delete(ona); }
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); ND("ring has %d pkts", ring->avail); if (ring->avail == 0) 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->cur = NETMAP_RING_NEXT(ring, i); ring->avail--; // if (ring->avail == 0) ioctl(me->fd, NIOCTXSYNC, NULL); return size; } errno = ENOBUFS; return -1; }
/* netmap_pipe_reg. * * There are two cases on registration (onoff==1) * * 1.a) state is * * usr1 --> e1 --> e2 * * and we are e1. Nothing special to do. * * 1.b) state is * * usr1 --> e1 --> e2 <-- usr2 * * and we are e2. Drop the ref e1 is holding. * * There are two additional cases on unregister (onoff==0) * * 2.a) state is * * usr1 --> e1 --> e2 * * and we are e1. Nothing special to do, e2 will * be cleaned up by the destructor of e1. * * 2.b) state is * * usr1 --> e1 e2 <-- usr2 * * and we are either e1 or e2. Add a ref from the * other end and hide our rings. */ static int netmap_pipe_reg(struct netmap_adapter *na, int onoff) { struct netmap_pipe_adapter *pna = (struct netmap_pipe_adapter *)na; struct ifnet *ifp = na->ifp; ND("%p: onoff %d", na, onoff); if (onoff) { ifp->if_capenable |= IFCAP_NETMAP; } else { ifp->if_capenable &= ~IFCAP_NETMAP; } if (pna->peer_ref) { ND("%p: case 1.a or 2.a, nothing to do", na); return 0; } if (onoff) { ND("%p: case 1.b, drop peer", na); pna->peer->peer_ref = 0; netmap_adapter_put(na); } else { int i; ND("%p: case 2.b, grab peer", na); netmap_adapter_get(na); pna->peer->peer_ref = 1; /* hide our rings from netmap_mem_rings_delete */ for (i = 0; i < na->num_tx_rings + 1; i++) { na->tx_rings[i].ring = NULL; } for (i = 0; i < na->num_rx_rings + 1; i++) { na->rx_rings[i].ring = NULL; } } return 0; }
static int mainloop(struct cfg_s *c) { int i; struct mbuf *m; for (i=0; i < c->loops; i++) { /* implement histeresis */ controller(c); DX(3, "loop %d enq %d send %p rx %d", i, c->_enqueue, c->tosend, c->can_dequeue); if ( (m = c->tosend) ) { c->_enqueue++; if (enqueue(c, m)) { drop(c, m); ND("loop %d enqueue fail", i ); } else { ND("enqueue ok"); c->pending++; } } if (c->can_dequeue) { c->dequeue++; if ((m = dequeue(c))) { c->pending--; drop(c, m); c->drop--; /* compensate */ } } } DX(1, "mainloop ends %d", i); return 0; }
static int set_seq_contains(intset_t *set, val_t val) { int result; node_t prev, next; #ifdef LOCKS global_lock(); #endif /* We have at least 2 elements */ LOAD_NODE(prev, set->head); LOAD_NODE(next, ND(prev.next)); while (next.val < val) { prev.next = next.next; LOAD_NODE(next, ND(prev.next)); } result = (next.val == val); #ifdef LOCKS global_lock_release(); #endif return result; }
/* remove the monitor mkring from the list of monitors of kring. * If this is the last monitor, restore the original callbacks */ static void netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring) { /* sinchronize with concurrently running nm_sync()s */ nm_kr_stop(kring, NM_KR_LOCKED); kring->n_monitors--; if (mkring->mon_pos != kring->n_monitors) { kring->monitors[mkring->mon_pos] = kring->monitors[kring->n_monitors]; kring->monitors[mkring->mon_pos]->mon_pos = mkring->mon_pos; } kring->monitors[kring->n_monitors] = NULL; if (kring->n_monitors == 0) { /* this was the last monitor, restore callbacks and delete monitor array */ ND("%s: restoring sync on %s: %p", mkring->name, kring->name, kring->mon_sync); kring->nm_sync = kring->mon_sync; kring->mon_sync = NULL; if (kring->tx == NR_RX) { ND("%s: restoring notify on %s: %p", mkring->name, kring->name, kring->mon_notify); kring->nm_notify = kring->mon_notify; kring->mon_notify = NULL; } nm_monitor_dealloc(kring); } nm_kr_start(kring); }
/* remove the monitor mkring from the list of monitors of kring. * If this is the last monitor, restore the original callbacks */ static void netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring) { struct netmap_zmon_list *mz = &mkring->zmon_list[kring->tx]; int zmon = nm_is_zmon(mkring->na); if (zmon && mz->prev != NULL) kring = mz->prev; /* sinchronize with concurrently running nm_sync()s */ nm_kr_stop(kring, NM_KR_LOCKED); if (zmon) { /* remove the monitor from the list */ if (mz->prev != NULL) mz->prev->zmon_list[kring->tx].next = mz->next; else kring->zmon_list[kring->tx].next = mz->next; if (mz->next != NULL) { mz->next->zmon_list[kring->tx].prev = mz->prev; } else { kring->zmon_list[kring->tx].prev = mz->prev; } } else { /* this is a copy monitor */ uint32_t mon_pos = mkring->mon_pos[kring->tx]; kring->n_monitors--; if (mon_pos != kring->n_monitors) { kring->monitors[mon_pos] = kring->monitors[kring->n_monitors]; kring->monitors[mon_pos]->mon_pos[kring->tx] = mon_pos; } kring->monitors[kring->n_monitors] = NULL; if (kring->n_monitors == 0) { nm_monitor_dealloc(kring); } } if (nm_monitor_none(kring)) { /* this was the last monitor, restore the callbacks */ ND("%s: restoring sync on %s: %p", mkring->name, kring->name, kring->mon_sync); kring->nm_sync = kring->mon_sync; kring->mon_sync = NULL; if (kring->tx == NR_RX) { ND("%s: restoring notify on %s: %p", mkring->name, kring->name, kring->mon_notify); kring->nm_notify = kring->mon_notify; kring->mon_notify = NULL; } } nm_kr_start(kring); }
void set_delete(intset_t *set) { node_t node, next; LOAD_NODE(node, set->head); nxt_t to_del = OF(set->head); while (node.next != 0) { to_del = node.next; LOAD_NODE(next, ND(node.next)); sys_shfree(ND(to_del)); node.next = next.next; } sys_shfree((void*) set); }
int set_add(intset_t* set, val_t val, int transactional) { int result = 0; if (!transactional) { return set_seq_add(set, val); } #ifdef SEQUENTIAL /* Unprotected */ return set_seq_add(set, val); #endif #ifdef EARLY_RELEASE return set_early_add(set, val); #endif #ifdef READ_VALIDATION return set_readval_add(set, val); #endif node_t prev, next; nxt_t to_store; TX_START; #ifdef DEBUG PRINT("++> set_add(%d)\tretry: %u", (int) val, tm2c_tx->retries); #endif to_store = OF(set->head); TX_LOAD_NODE(prev, set->head); TX_LOAD_NODE(next, ND(prev.next)); while (next.val < val) { to_store = prev.next; prev.val = next.val; prev.next = next.next; TX_LOAD_NODE(next, ND(prev.next)); } result = (next.val != val); if (result) { node_t* nn = new_node(val, prev.next, 1); prev.next = OF(nn); TX_STORE(ND(to_store), prev.to_int64, TYPE_INT); } TX_COMMIT_MEM; return result; }
/* nm_dtor callback for monitors */ static void netmap_monitor_dtor(struct netmap_adapter *na) { struct netmap_monitor_adapter *mna = (struct netmap_monitor_adapter *)na; struct netmap_priv_d *priv = &mna->priv; struct netmap_adapter *pna = priv->np_na; int i; ND("%p", na); if (nm_netmap_on(pna)) { /* parent still in netmap mode, mark its krings as free */ if (mna->flags & NR_MONITOR_TX) { for (i = priv->np_txqfirst; i < priv->np_txqlast; i++) { pna->tx_rings[i].monitor = NULL; } } if (mna->flags & NR_MONITOR_RX) { for (i = priv->np_rxqfirst; i < priv->np_rxqlast; i++) { pna->rx_rings[i].monitor = NULL; } } } netmap_adapter_put(pna); }
/* move packts from src to destination */ static int move(struct my_ring *src, struct my_ring *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) ? "host->net" : "net->host"; while (si < src->end && di < dst->end) { rxring = NETMAP_RXRING(src->nifp, si); txring = NETMAP_TXRING(dst->nifp, di); ND("txring %p rxring %p", txring, rxring); if (rxring->avail == 0) { si++; continue; } if (txring->avail == 0) { di++; continue; } m += process_rings(rxring, txring, limit, msg); } return (m); }
static int rr_free_sched(struct dn_sch_inst *_si) { ND("called"); /* Nothing to do? */ return 0; }
/* * Allocate n buffers from the ring, and fill the slot. * Buffer 0 is the 'junk' buffer. */ static void netmap_new_bufs(struct netmap_buf_pool *p, struct netmap_slot *slot, u_int n) { uint32_t bi = 0; /* index in the bitmap */ uint32_t mask, j, i = 0; /* slot counter */ if (n > p->free) { D("only %d out of %d buffers available", i, n); return; } /* termination is guaranteed by p->free */ while (i < n && p->free > 0) { uint32_t cur = p->bitmap[bi]; if (cur == 0) { /* bitmask is fully used */ bi++; continue; } /* locate a slot */ for (j = 0, mask = 1; (cur & mask) == 0; j++, mask <<= 1) ; p->bitmap[bi] &= ~mask; /* slot in use */ p->free--; slot[i].buf_idx = bi*32+j; slot[i].len = p->bufsize; slot[i].flags = NS_BUF_CHANGED; i++; } ND("allocated %d buffers, %d available", n, p->free); }
/* common functions for the nm_register() callbacks of both kind of * monitors. */ static int netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon) { struct netmap_monitor_adapter *mna = (struct netmap_monitor_adapter *)na; struct netmap_priv_d *priv = &mna->priv; struct netmap_adapter *pna = priv->np_na; struct netmap_kring *kring, *mkring; int i; enum txrx t; ND("%p: onoff %d", na, onoff); if (onoff) { if (pna == NULL) { /* parent left netmap mode, fatal */ D("%s: internal error", na->name); return ENXIO; } for_rx_tx(t) { if (mna->flags & nm_txrx2flag(t)) { for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) { kring = &NMR(pna, t)[i]; mkring = &na->rx_rings[i]; netmap_monitor_add(mkring, kring, zmon); } } } na->na_flags |= NAF_NETMAP_ON; } else { if (pna == NULL) {
/* move packts from src to destination */ static int move(struct thr_ctx *th, struct nm_desc *src, struct nm_desc *dst, u_int limit) { struct netmap_ring *txring, *rxring; 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->last_rx_ring && di <= dst->last_tx_ring) { rxring = NETMAP_RXRING(src->nifp, si); txring = NETMAP_TXRING(dst->nifp, di); ND("txring %p rxring %p", txring, rxring); if (nm_ring_empty(rxring)) { si++; continue; } if (nm_ring_empty(txring)) { di++; continue; } m += process_rings(th, rxring, txring, limit, msg); } return (m); }
static void netmap_pipe_dtor(struct netmap_adapter *na) { struct netmap_pipe_adapter *pna = (struct netmap_pipe_adapter *)na; ND("%p", na); if (pna->peer_ref) { ND("%p: clean up peer", na); pna->peer_ref = 0; netmap_adapter_put(&pna->peer->up); } if (pna->role == NR_REG_PIPE_MASTER) netmap_pipe_remove(pna->parent, pna); netmap_adapter_put(pna->parent); pna->parent = NULL; }
int pcap_get_selectable_fd(pcap_t *p) { struct my_ring *me = p; ND(""); return me->fd; }
/* nm_sync callback for the monitor's own rx rings. * Note that the lock in netmap_zmon_parent_sync only protects * writers among themselves. Synchronization between writers * (i.e., netmap_zmon_parent_txsync and netmap_zmon_parent_rxsync) * and readers (i.e., netmap_zmon_rxsync) relies on memory barriers. */ static int netmap_monitor_rxsync(struct netmap_kring *kring, int flags) { ND("%s %x", kring->name, flags); kring->nr_hwcur = kring->rhead; mb(); return 0; }
int set_size(intset_t* set) { int size = 0; node_t node, head; /* We have at least 2 elements */ LOAD_NODE(head, set->head); LOAD_NODE(node, ND(head.next)); while (node.next != 0) { size++; LOAD_NODE(node, ND(node.next)); } return size; }
/* nm_register callback for monitors. * * On registration, replace the nm_sync callbacks in the monitored * rings with our own, saving the previous ones in the monitored * rings themselves, where they are used by netmap_monitor_parent_sync. * * On de-registration, restore the original callbacks. We need to * stop traffic while we are doing this, since the monitored adapter may * have already started executing a netmap_monitor_parent_sync * and may not like the kring->save_sync pointer to become NULL. */ static int netmap_monitor_reg(struct netmap_adapter *na, int onoff) { struct netmap_monitor_adapter *mna = (struct netmap_monitor_adapter *)na; struct netmap_priv_d *priv = &mna->priv; struct netmap_adapter *pna = priv->np_na; struct netmap_kring *kring; int i; ND("%p: onoff %d", na, onoff); if (onoff) { if (!nm_netmap_on(pna)) { /* parent left netmap mode, fatal */ return ENXIO; } if (mna->flags & NR_MONITOR_TX) { for (i = priv->np_txqfirst; i < priv->np_txqlast; i++) { kring = &pna->tx_rings[i]; kring->save_sync = kring->nm_sync; kring->nm_sync = netmap_monitor_parent_txsync; } } if (mna->flags & NR_MONITOR_RX) { for (i = priv->np_rxqfirst; i < priv->np_rxqlast; i++) { kring = &pna->rx_rings[i]; kring->save_sync = kring->nm_sync; kring->nm_sync = netmap_monitor_parent_rxsync; } } na->na_flags |= NAF_NETMAP_ON; } else { if (!nm_netmap_on(pna)) { /* parent left netmap mode, nothing to restore */ return 0; } na->na_flags &= ~NAF_NETMAP_ON; if (mna->flags & NR_MONITOR_TX) { for (i = priv->np_txqfirst; i < priv->np_txqlast; i++) { netmap_set_txring(pna, i, 1 /* stopped */); kring = &pna->tx_rings[i]; kring->nm_sync = kring->save_sync; kring->save_sync = NULL; netmap_set_txring(pna, i, 0 /* enabled */); } } if (mna->flags & NR_MONITOR_RX) { for (i = priv->np_rxqfirst; i < priv->np_rxqlast; i++) { netmap_set_rxring(pna, i, 1 /* stopped */); kring = &pna->rx_rings[i]; kring->nm_sync = kring->save_sync; kring->save_sync = NULL; netmap_set_rxring(pna, i, 0 /* enabled */); } } } return 0; }
static int set_seq_add(intset_t* set, val_t val) { int result; node_t prev, nnext; #ifdef LOCKS global_lock(); #endif nxt_t to_store = OF(set->head); /* int seq = 0; */ node_t* hd = set->head; LOAD_NODE(prev, hd); /* PRINT("%3d LOAD: head: %10lu val: %10ld %d", seq++, to_store, prev.val, prev.next); */ node_t* nd = ND(prev.next); LOAD_NODE(nnext, nd); /* PRINT("%3d LOAD: addr: %10d val: %10ld %d", seq++, prev.next, nnext.val, nnext.next); */ while (nnext.val < val) { to_store = prev.next; prev.val = nnext.val; prev.next = nnext.next; node_t* nd = ND(prev.next); LOAD_NODE(nnext, nd); /* PRINT("%3d LOAD: addr: %10lu val: %10ld %d", seq++, prev.next, nnext.val, nnext.next); */ } result = (nnext.val != val); if (result) { node_t *nn = new_node(val, prev.next, 0); prev.next = OF(nn); node_t* nd = ND(to_store); NONTX_STORE(nd, prev.to_int64, TYPE_INT); /* PRINT("%3d STORE: addr: %10lu val: %10ld %d", seq++, to_store, prev.val, prev.next); */ } #ifdef LOCKS global_lock_release(); #endif return result; }
/* nm_sync callback for the monitor's own rx rings. * Note that the lock in netmap_monitor_parent_sync only protects * writers among themselves. Synchronization between writers * (i.e., netmap_monitor_parent_txsync and netmap_monitor_parent_rxsync) * and readers (i.e., netmap_monitor_rxsync) relies on memory barriers. */ static int netmap_monitor_rxsync(struct netmap_kring *kring, int flags) { ND("%s %x", kring->name, flags); kring->nr_hwcur = kring->rcur; rmb(); nm_rxsync_finalize(kring); return 0; }
int pcap_stats(pcap_t *p, struct pcap_stat *ps) { struct pcap_ring *me = p; ND(""); *ps = me->st; return 0; /* accumulate from pcap_dispatch() */ };
static int netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags) { struct netmap_kring *txkring = rxkring->pipe; uint32_t oldhwcur = rxkring->nr_hwcur; ND("%s %x <- %s", rxkring->name, flags, txkring->name); rxkring->nr_hwcur = rxkring->rhead; /* recover user-relased slots */ ND(5, "hwcur %d hwtail %d cur %d head %d tail %d", rxkring->nr_hwcur, rxkring->nr_hwtail, rxkring->rcur, rxkring->rhead, rxkring->rtail); mb(); /* paired with the first mb() in txsync */ if (oldhwcur != rxkring->nr_hwcur) { /* we have released some slots, notify the other end */ mb(); /* make sure nr_hwcur is updated before notifying */ txkring->nm_notify(txkring, 0); } return 0; }
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); ND("ring has %d pkts", ring->avail); if (ring->avail == 0) continue; pme->hdr.ts = ring->ts; /* * XXX a proper prefetch should be done as * prefetch(i); callback(i-1); ... */ while ((cnt == -1 || cnt != got) && ring->avail > 0) { 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->cur = NETMAP_RING_NEXT(ring, i); ring->avail--; got++; } } pme->st.ps_recv += got; return got; }
static int rr_new_sched(struct dn_sch_inst *_si) { struct rr_si *si = (struct rr_si *)(_si + 1); ND("called"); si->head = si->tail = NULL; return 0; }
int set_remove(intset_t* set, val_t val, int transactional) { int result = 0; #ifdef DEBUG PRINT("++> set_remove(%d)", (int) val); #endif #ifdef SEQUENTIAL /* Unprotected */ return set_seq_remove(set, val); #endif #ifdef EARLY_RELEASE return set_early_remove(set, val); #endif #ifdef READ_VALIDATION return set_readval_remove(set, val); #endif node_t prev, next; TX_START; nxt_t to_store = OF(set->head); TX_LOAD_NODE(prev, set->head); TX_LOAD_NODE(next, ND(prev.next)); while (val > next.val) { to_store = prev.next; prev.val = next.val; prev.next = next.next; TX_LOAD_NODE(next, ND(prev.next)); } result = (next.val == val); if (result) { TX_SHFREE(ND(prev.next)); prev.next = next.next; TX_STORE(ND(to_store), prev.to_int64, TYPE_INT); } TX_COMMIT_MEM; return result; }
static int linux_netmap_mmap(struct file *f, struct vm_area_struct *vma) { int error = 0; unsigned long off; u_int memsize, memflags; struct netmap_priv_d *priv = f->private_data; struct netmap_adapter *na = priv->np_na; /* * vma->vm_start: start of mapping user address space * vma->vm_end: end of the mapping user address space * vma->vm_pfoff: offset of first page in the device */ if (priv->np_nifp == NULL) { return -EINVAL; } mb(); /* check that [off, off + vsize) is within our memory */ error = netmap_mem_get_info(na->nm_mem, &memsize, &memflags, NULL); ND("get_info returned %d", error); if (error) return -error; off = vma->vm_pgoff << PAGE_SHIFT; ND("off %lx size %lx memsize %x", off, (vma->vm_end - vma->vm_start), memsize); if (off + (vma->vm_end - vma->vm_start) > memsize) return -EINVAL; if (memflags & NETMAP_MEM_IO) { vm_ooffset_t pa; /* the underlying memory is contiguous */ pa = netmap_mem_ofstophys(na->nm_mem, 0); if (pa == 0) return -EINVAL; return remap_pfn_range(vma, vma->vm_start, pa >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot); } else {
/* deallocate the parent array in the parent adapter */ void netmap_pipe_dealloc(struct netmap_adapter *na) { if (na->na_pipes) { ND("freeing pipes for %s", NM_IFPNAME(na->ifp)); free(na->na_pipes, M_DEVBUF); na->na_pipes = NULL; na->na_max_pipes = 0; na->na_next_pipe = 0; } }
static int rr_free_queue(struct dn_queue *_q) { struct rr_queue *q = (struct rr_queue *)_q; ND("called"); if (q->status == 1) { struct rr_si *si = (struct rr_si *)(_q->_si + 1); remove_queue_q(q, si); } return 0; }