diff options
Diffstat (limited to 'sys/dev/netmap/netmap_monitor.c')
| -rw-r--r-- | sys/dev/netmap/netmap_monitor.c | 231 |
1 files changed, 143 insertions, 88 deletions
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c index 8b118ced9ad5..7e88ae02f9ba 100644 --- a/sys/dev/netmap/netmap_monitor.c +++ b/sys/dev/netmap/netmap_monitor.c @@ -152,6 +152,12 @@ netmap_monitor_txsync(struct netmap_kring *kring, int flags) static int netmap_monitor_rxsync(struct netmap_kring *kring, int flags) { + struct netmap_monitor_adapter *mna = + (struct netmap_monitor_adapter *)kring->na; + if (unlikely(mna->priv.np_na == NULL)) { + /* parent left netmap mode */ + return EIO; + } ND("%s %x", kring->name, flags); kring->nr_hwcur = kring->rhead; mb(); @@ -164,11 +170,20 @@ static int netmap_monitor_krings_create(struct netmap_adapter *na) { int error = netmap_krings_create(na, 0); + enum txrx t; + if (error) return error; /* override the host rings callbacks */ - na->tx_rings[na->num_tx_rings]->nm_sync = netmap_monitor_txsync; - na->rx_rings[na->num_rx_rings]->nm_sync = netmap_monitor_rxsync; + for_rx_tx(t) { + int i; + u_int first = nma_get_nrings(na, t); + for (i = 0; i < nma_get_host_nrings(na, t); i++) { + struct netmap_kring *kring = NMR(na, t)[first + i]; + kring->nm_sync = t == NR_TX ? netmap_monitor_txsync : + netmap_monitor_rxsync; + } + } return 0; } @@ -244,6 +259,48 @@ static int netmap_monitor_parent_txsync(struct netmap_kring *, int); static int netmap_monitor_parent_rxsync(struct netmap_kring *, int); static int netmap_monitor_parent_notify(struct netmap_kring *, int); +static void +nm_monitor_intercept_callbacks(struct netmap_kring *kring) +{ + ND("intercept callbacks on %s", kring->name); + kring->mon_sync = kring->nm_sync; + kring->mon_notify = kring->nm_notify; + if (kring->tx == NR_TX) { + kring->nm_sync = netmap_monitor_parent_txsync; + } else { + kring->nm_sync = netmap_monitor_parent_rxsync; + kring->nm_notify = netmap_monitor_parent_notify; + kring->mon_tail = kring->nr_hwtail; + } +} + +static void +nm_monitor_restore_callbacks(struct netmap_kring *kring) +{ + ND("restoring callbacks on %s", kring->name); + kring->nm_sync = kring->mon_sync; + kring->mon_sync = NULL; + if (kring->tx == NR_RX) { + kring->nm_notify = kring->mon_notify; + } + kring->mon_notify = NULL; +} + +static struct netmap_kring * +nm_zmon_list_head(struct netmap_kring *mkring, enum txrx t) +{ + struct netmap_adapter *na = mkring->na; + struct netmap_kring *kring = mkring; + struct netmap_zmon_list *z = &kring->zmon_list[t]; + /* reach the head of the list */ + while (nm_is_zmon(na) && z->prev != NULL) { + kring = z->prev; + na = kring->na; + z = &kring->zmon_list[t]; + } + return nm_is_zmon(na) ? NULL : kring; +} + /* add the monitor mkring to the list of monitors of kring. * If this is the first monitor, intercept the callbacks */ @@ -254,51 +311,34 @@ netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int enum txrx t = kring->tx; struct netmap_zmon_list *z = &kring->zmon_list[t]; struct netmap_zmon_list *mz = &mkring->zmon_list[t]; + struct netmap_kring *ikring = kring; /* a zero-copy monitor which is not the first in the list * must monitor the previous monitor */ if (zmon && z->prev != NULL) - kring = z->prev; + ikring = z->prev; /* tail of the list */ /* synchronize with concurrently running nm_sync()s */ nm_kr_stop(kring, NM_KR_LOCKED); - if (nm_monitor_none(kring)) { - /* this is the first monitor, intercept callbacks */ - ND("intercept callbacks on %s", kring->name); - kring->mon_sync = kring->nm_sync; - kring->mon_notify = kring->nm_notify; - if (kring->tx == NR_TX) { - kring->nm_sync = netmap_monitor_parent_txsync; - } else { - kring->nm_sync = netmap_monitor_parent_rxsync; - kring->nm_notify = netmap_monitor_parent_notify; - kring->mon_tail = kring->nr_hwtail; - } + if (nm_monitor_none(ikring)) { + /* this is the first monitor, intercept the callbacks */ + ND("%s: intercept callbacks on %s", mkring->name, ikring->name); + nm_monitor_intercept_callbacks(ikring); } if (zmon) { /* append the zmon to the list */ - struct netmap_monitor_adapter *mna = - (struct netmap_monitor_adapter *)mkring->na; - struct netmap_adapter *pna; - - if (z->prev != NULL) - z->prev->zmon_list[t].next = mkring; - mz->prev = z->prev; - z->prev = mkring; - if (z->next == NULL) - z->next = mkring; - - /* grap a reference to the previous netmap adapter + ikring->zmon_list[t].next = mkring; + z->prev = mkring; /* new tail */ + mz->prev = ikring; + mz->next = NULL; + /* grab a reference to the previous netmap adapter * in the chain (this may be the monitored port * or another zero-copy monitor) */ - pna = kring->na; - netmap_adapter_get(pna); - netmap_adapter_put(mna->priv.np_na); - mna->priv.np_na = pna; + netmap_adapter_get(ikring->na); } else { /* make sure the monitor array exists and is big enough */ error = nm_monitor_alloc(kring, kring->n_monitors + 1); @@ -318,29 +358,50 @@ out: * If this is the last monitor, restore the original callbacks */ static void -netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring) +netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring, enum txrx t) { - struct netmap_zmon_list *mz = &mkring->zmon_list[kring->tx]; int zmon = nm_is_zmon(mkring->na); + struct netmap_zmon_list *mz = &mkring->zmon_list[t]; + struct netmap_kring *ikring = kring; - if (zmon && mz->prev != NULL) - kring = mz->prev; + if (zmon) { + /* get to the head of the list */ + kring = nm_zmon_list_head(mkring, t); + ikring = mz->prev; + } - /* synchronize with concurrently running nm_sync()s */ - nm_kr_stop(kring, NM_KR_LOCKED); + /* synchronize with concurrently running nm_sync()s + * if kring is NULL (orphaned list) the monitored port + * has exited netmap mode, so there is nothing to stop + */ + if (kring != NULL) + 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; + mz->next->zmon_list[t].prev = mz->prev; + /* we also need to let the next monitor drop the + * reference to us and grab the reference to the + * previous ring owner, instead + */ + if (mz->prev != NULL) + netmap_adapter_get(mz->prev->na); + netmap_adapter_put(mkring->na); + } else if (kring != NULL) { + /* in the monitored kring, prev is actually the + * pointer to the tail of the list + */ + kring->zmon_list[t].prev = + (mz->prev != kring ? mz->prev : NULL); + } + if (mz->prev != NULL) { + netmap_adapter_put(mz->prev->na); + mz->prev->zmon_list[t].next = mz->next; } + mz->prev = NULL; + mz->next = NULL; } else { /* this is a copy monitor */ uint32_t mon_pos = mkring->mon_pos[kring->tx]; @@ -356,21 +417,13 @@ netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring) } } - if (nm_monitor_none(kring)) { + if (ikring != NULL && nm_monitor_none(ikring)) { /* 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_monitor_restore_callbacks(ikring); } - nm_kr_start(kring); + if (kring != NULL) + nm_kr_start(kring); } @@ -389,9 +442,9 @@ netmap_monitor_stop(struct netmap_adapter *na) for_rx_tx(t) { u_int i; - for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { + for (i = 0; i < netmap_all_rings(na, t); i++) { struct netmap_kring *kring = NMR(na, t)[i]; - struct netmap_kring *zkring; + struct netmap_zmon_list *z = &kring->zmon_list[t]; u_int j; for (j = 0; j < kring->n_monitors; j++) { @@ -404,29 +457,33 @@ netmap_monitor_stop(struct netmap_adapter *na) netmap_adapter_put(mna->priv.np_na); mna->priv.np_na = NULL; } + kring->monitors[j] = NULL; } - zkring = kring->zmon_list[kring->tx].next; - if (zkring != NULL) { - struct netmap_monitor_adapter *next = - (struct netmap_monitor_adapter *)zkring->na; - struct netmap_monitor_adapter *this = - (struct netmap_monitor_adapter *)na; - struct netmap_adapter *pna = this->priv.np_na; - /* let the next monitor forget about us */ - if (next->priv.np_na != NULL) { - netmap_adapter_put(next->priv.np_na); + if (!nm_is_zmon(na)) { + /* we are the head of at most one list */ + struct netmap_kring *zkring; + for (zkring = z->next; zkring != NULL; + zkring = zkring->zmon_list[t].next) + { + struct netmap_monitor_adapter *next = + (struct netmap_monitor_adapter *)zkring->na; + /* let the monitor forget about us */ + netmap_adapter_put(next->priv.np_na); /* nop if null */ + next->priv.np_na = NULL; } - if (pna != NULL && nm_is_zmon(na)) { - /* we are a monitor ourselves and we may - * need to pass down the reference to - * the previous adapter in the chain - */ - netmap_adapter_get(pna); - next->priv.np_na = pna; - continue; - } - next->priv.np_na = NULL; + /* orhpan the zmon list */ + if (z->next != NULL) + z->next->zmon_list[t].prev = NULL; + z->next = NULL; + z->prev = NULL; + } + + if (!nm_monitor_none(kring)) { + + kring->n_monitors = 0; + nm_monitor_dealloc(kring); + nm_monitor_restore_callbacks(kring); } } } @@ -455,7 +512,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon) return ENXIO; } for_rx_tx(t) { - for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { + for (i = 0; i < netmap_all_rings(na, t); i++) { mkring = NMR(na, t)[i]; if (!nm_kring_pending_on(mkring)) continue; @@ -477,7 +534,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon) if (na->active_fds == 0) na->na_flags &= ~NAF_NETMAP_ON; for_rx_tx(t) { - for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { + for (i = 0; i < netmap_all_rings(na, t); i++) { mkring = NMR(na, t)[i]; if (!nm_kring_pending_off(mkring)) continue; @@ -495,7 +552,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon) continue; if (mna->flags & nm_txrx2flag(s)) { kring = NMR(pna, s)[i]; - netmap_monitor_del(mkring, kring); + netmap_monitor_del(mkring, kring, s); } } } @@ -593,6 +650,7 @@ netmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx) ms->len = s->len; s->len = tmp; + ms->flags = s->flags; s->flags |= NS_BUF_CHANGED; beg = nm_next(beg, lim); @@ -710,6 +768,7 @@ netmap_monitor_parent_sync(struct netmap_kring *kring, u_int first_new, int new_ memcpy(dst, src, copy_len); ms->len = copy_len; + ms->flags = s->flags; sent++; beg = nm_next(beg, lim); @@ -836,7 +895,6 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na, struct ifnet *ifp = NULL; int error; int zcopy = (req->nr_flags & NR_ZCOPY_MON); - char monsuff[10] = ""; if (zcopy) { req->nr_flags |= (NR_MONITOR_TX | NR_MONITOR_RX); @@ -890,14 +948,11 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na, D("ringid error"); goto free_out; } - if (mna->priv.np_qlast[NR_TX] - mna->priv.np_qfirst[NR_TX] == 1) { - snprintf(monsuff, 10, "-%d", mna->priv.np_qfirst[NR_TX]); - } - snprintf(mna->up.name, sizeof(mna->up.name), "%s%s/%s%s%s", pna->name, - monsuff, + snprintf(mna->up.name, sizeof(mna->up.name), "%s/%s%s%s#%lu", pna->name, zcopy ? "z" : "", (req->nr_flags & NR_MONITOR_RX) ? "r" : "", - (req->nr_flags & NR_MONITOR_TX) ? "t" : ""); + (req->nr_flags & NR_MONITOR_TX) ? "t" : "", + pna->monitor_id++); /* the monitor supports the host rings iff the parent does */ mna->up.na_flags |= (pna->na_flags & NAF_HOST_RINGS); |
