aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/netmap/netmap_monitor.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/netmap/netmap_monitor.c')
-rw-r--r--sys/dev/netmap/netmap_monitor.c231
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);