/* 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; }
void generic_timer_handler(struct hrtimer *t) { DbgPrint("unimplemented generic_timer_handler %p\n", t); #if 0 struct nm_generic_mit *mit = container_of(t, struct nm_generic_mit, mit_timer); u_int work_done; if (!mit->mit_pending) { return HRTIMER_NORESTART; } /* Some work arrived while the timer was counting down: * Reset the pending work flag, restart the timer and send * a notification. */ mit->mit_pending = 0; /* below is a variation of netmap_generic_irq XXX revise */ if (nm_netmap_on(mit->mit_na)) { netmap_common_irq(mit->mit_na->ifp, mit->mit_ring_idx, &work_done); generic_rate(0, 0, 0, 0, 0, 1); } nm_os_mitigation_restart(mit); return HRTIMER_RESTART; #endif }
/* 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); }
/* check if nmr is a request for a monitor adapter that we can satisfy */ int netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na, int create) { struct nmreq pnmr; struct netmap_adapter *pna; /* parent adapter */ struct netmap_monitor_adapter *mna; int i, error; if ((nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) { ND("not a monitor"); return 0; } /* this is a request for a monitor adapter */ D("flags %x", nmr->nr_flags); mna = malloc(sizeof(*mna), M_DEVBUF, M_NOWAIT | M_ZERO); if (mna == NULL) { D("memory error"); return ENOMEM; } /* first, try to find the adapter that we want to monitor * We use the same nmr, after we have turned off the monitor flags. * In this way we can potentially monitor everything netmap understands, * except other monitors. */ memcpy(&pnmr, nmr, sizeof(pnmr)); pnmr.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX); error = netmap_get_na(&pnmr, &pna, create); if (error) { D("parent lookup failed: %d", error); return error; } D("found parent: %s", pna->name); if (!nm_netmap_on(pna)) { /* parent not in netmap mode */ /* XXX we can wait for the parent to enter netmap mode, * by intercepting its nm_register callback (2014-03-16) */ D("%s not in netmap mode", pna->name); error = EINVAL; goto put_out; } /* grab all the rings we need in the parent */ mna->priv.np_na = pna; error = netmap_interp_ringid(&mna->priv, nmr->nr_ringid, nmr->nr_flags); if (error) { D("ringid error"); goto put_out; } if (nmr->nr_flags & NR_MONITOR_TX) { for (i = mna->priv.np_txqfirst; i < mna->priv.np_txqlast; i++) { struct netmap_kring *kring = &pna->tx_rings[i]; if (kring->monitor) { error = EBUSY; D("ring busy"); goto release_out; } kring->monitor = mna; } } if (nmr->nr_flags & NR_MONITOR_RX) { for (i = mna->priv.np_rxqfirst; i < mna->priv.np_rxqlast; i++) { struct netmap_kring *kring = &pna->rx_rings[i]; if (kring->monitor) { error = EBUSY; D("ring busy"); goto release_out; } kring->monitor = mna; } } snprintf(mna->up.name, sizeof(mna->up.name), "mon:%s", pna->name); /* the monitor supports the host rings iff the parent does */ mna->up.na_flags = (pna->na_flags & NAF_HOST_RINGS); mna->up.nm_txsync = netmap_monitor_txsync; mna->up.nm_rxsync = netmap_monitor_rxsync; mna->up.nm_register = netmap_monitor_reg; mna->up.nm_dtor = netmap_monitor_dtor; mna->up.nm_krings_create = netmap_monitor_krings_create; mna->up.nm_krings_delete = netmap_monitor_krings_delete; mna->up.nm_mem = pna->nm_mem; mna->up.na_lut = pna->na_lut; mna->up.na_lut_objtotal = pna->na_lut_objtotal; mna->up.na_lut_objsize = pna->na_lut_objsize; mna->up.num_tx_rings = 1; // XXX we don't need it, but field can't be zero /* we set the number of our rx_rings to be max(num_rx_rings, num_rx_rings) * in the parent */ mna->up.num_rx_rings = pna->num_rx_rings; if (pna->num_tx_rings > pna->num_rx_rings) mna->up.num_rx_rings = pna->num_tx_rings; /* by default, the number of slots is the same as in * the parent rings, but the user may ask for a different * number */ mna->up.num_tx_desc = nmr->nr_tx_slots; nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc, 1, NM_MONITOR_MAXSLOTS, NULL); mna->up.num_rx_desc = nmr->nr_rx_slots; nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc, 1, NM_MONITOR_MAXSLOTS, NULL); error = netmap_attach_common(&mna->up); if (error) { D("attach_common error"); goto release_out; } /* remember the traffic directions we have to monitor */ mna->flags = (nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)); *na = &mna->up; netmap_adapter_get(*na); /* write the configuration back */ nmr->nr_tx_rings = mna->up.num_tx_rings; nmr->nr_rx_rings = mna->up.num_rx_rings; nmr->nr_tx_slots = mna->up.num_tx_desc; nmr->nr_rx_slots = mna->up.num_rx_desc; /* keep the reference to the parent */ D("monitor ok"); return 0; release_out: D("monitor error"); for (i = mna->priv.np_txqfirst; i < mna->priv.np_txqlast; i++) { if (pna->tx_rings[i].monitor == mna) pna->tx_rings[i].monitor = NULL; } for (i = mna->priv.np_rxqfirst; i < mna->priv.np_rxqlast; i++) { if (pna->rx_rings[i].monitor == mna) pna->rx_rings[i].monitor = NULL; } put_out: netmap_adapter_put(pna); free(mna, M_DEVBUF); return error; }