static int netmap_pipe_txsync(struct netmap_kring *txkring, int flags) { struct netmap_kring *rxkring = txkring->pipe; u_int limit; /* slots to transfer */ u_int j, k, lim_tx = txkring->nkr_num_slots - 1, lim_rx = rxkring->nkr_num_slots - 1; int m, busy; ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name); ND(2, "before: hwcur %d hwtail %d cur %d head %d tail %d", txkring->nr_hwcur, txkring->nr_hwtail, txkring->rcur, txkring->rhead, txkring->rtail); j = rxkring->nr_hwtail; /* RX */ k = txkring->nr_hwcur; /* TX */ m = txkring->rhead - txkring->nr_hwcur; /* new slots */ if (m < 0) m += txkring->nkr_num_slots; limit = m; m = lim_rx; /* max avail space on destination */ busy = j - rxkring->nr_hwcur; /* busy slots */ if (busy < 0) busy += rxkring->nkr_num_slots; m -= busy; /* subtract busy slots */ ND(2, "m %d limit %d", m, limit); if (m < limit) limit = m; if (limit == 0) { /* either the rxring is full, or nothing to send */ return 0; } while (limit-- > 0) { struct netmap_slot *rs = &rxkring->ring->slot[j]; struct netmap_slot *ts = &txkring->ring->slot[k]; struct netmap_slot tmp; /* swap the slots */ tmp = *rs; *rs = *ts; *ts = tmp; /* report the buffer change */ ts->flags |= NS_BUF_CHANGED; rs->flags |= NS_BUF_CHANGED; j = nm_next(j, lim_rx); k = nm_next(k, lim_tx); } mb(); /* make sure the slots are updated before publishing them */ rxkring->nr_hwtail = j; txkring->nr_hwcur = k; txkring->nr_hwtail = nm_prev(k, lim_tx); ND(2, "after: hwcur %d hwtail %d cur %d head %d tail %d j %d", txkring->nr_hwcur, txkring->nr_hwtail, txkring->rcur, txkring->rhead, txkring->rtail, j); mb(); /* make sure rxkring->nr_hwtail is updated before notifying */ rxkring->nm_notify(rxkring, 0); return 0; }
/* monitor works by replacing the nm_sync callbacks in the monitored rings. * The actions to be performed are the same on both tx and rx rings, so we * have collected them here */ static int netmap_monitor_parent_sync(struct netmap_kring *kring, int flags, u_int* ringptr) { struct netmap_monitor_adapter *mna = kring->monitor; struct netmap_kring *mkring = &mna->up.rx_rings[kring->ring_id]; struct netmap_ring *ring = kring->ring, *mring = mkring->ring; int error; int rel_slots, free_slots, busy; u_int beg, end, i; u_int lim = kring->nkr_num_slots - 1, mlim = mkring->nkr_num_slots - 1; /* get the relased slots (rel_slots) */ beg = *ringptr; error = kring->save_sync(kring, flags); if (error) return error; end = *ringptr; rel_slots = end - beg; if (rel_slots < 0) rel_slots += kring->nkr_num_slots; if (!rel_slots) { return 0; } /* we need to lock the monitor receive ring, since it * is the target of bot tx and rx traffic from the monitored * adapter */ mtx_lock(&mkring->q_lock); /* get the free slots available on the monitor ring */ i = mkring->nr_hwtail; busy = i - mkring->nr_hwcur; if (busy < 0) busy += mkring->nkr_num_slots; free_slots = mlim - busy; if (!free_slots) { mtx_unlock(&mkring->q_lock); return 0; } /* swap min(free_slots, rel_slots) slots */ if (free_slots < rel_slots) { beg += (rel_slots - free_slots); if (beg > lim) beg = 0; rel_slots = free_slots; } for ( ; rel_slots; rel_slots--) { struct netmap_slot *s = &ring->slot[beg]; struct netmap_slot *ms = &mring->slot[i]; uint32_t tmp; tmp = ms->buf_idx; ms->buf_idx = s->buf_idx; s->buf_idx = tmp; tmp = ms->len; ms->len = s->len; s->len = tmp; s->flags |= NS_BUF_CHANGED; beg = nm_next(beg, lim); i = nm_next(i, mlim); } wmb(); mkring->nr_hwtail = i; mtx_unlock(&mkring->q_lock); /* notify the new frames to the monitor */ mna->up.nm_notify(&mna->up, mkring->ring_id, NR_RX, 0); return 0; }