/* This is called when the monitored adapter leaves netmap mode * (see netmap_do_unregif). * We need to notify the monitors that the monitored rings are gone. * We do this by setting their mna->priv.np_na to NULL. * Note that the rings are already stopped when this happens, so * no monitor ring callback can be active. */ void netmap_monitor_stop(struct netmap_adapter *na) { enum txrx t; for_rx_tx(t) { u_int i; for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { struct netmap_kring *kring = &NMR(na, t)[i]; struct netmap_kring *zkring; u_int j; for (j = 0; j < kring->n_monitors; j++) { struct netmap_kring *mkring = kring->monitors[j]; struct netmap_monitor_adapter *mna = (struct netmap_monitor_adapter *)mkring->na; /* forget about this adapter */ if (mna->priv.np_na != NULL) { netmap_adapter_put(mna->priv.np_na); mna->priv.np_na = 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 (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; } } } }
/* 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; }
/* 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); }
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; }
/* This is called when the monitored adapter leaves netmap mode * (see netmap_do_unregif). * We need to notify the monitors that the monitored rings are gone. * We do this by setting their mna->priv.np_na to NULL. * Note that the rings are already stopped when this happens, so * no monitor ring callback can be active. */ void netmap_monitor_stop(struct netmap_adapter *na) { enum txrx t; for_rx_tx(t) { u_int i; for (i = 0; i < nma_get_nrings(na, t); i++) { struct netmap_kring *kring = &NMR(na, t)[i]; u_int j; for (j = 0; j < kring->n_monitors; j++) { struct netmap_kring *mkring = kring->monitors[j]; struct netmap_monitor_adapter *mna = (struct netmap_monitor_adapter *)mkring->na; /* forget about this adapter */ netmap_adapter_put(mna->priv.np_na); mna->priv.np_na = NULL; } } } }
/* add the monitor mkring to the list of monitors of kring. * If this is the first monitor, intercept the callbacks */ static int netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int zmon) { int error = NM_IRQ_COMPLETED; enum txrx t = kring->tx; struct netmap_zmon_list *z = &kring->zmon_list[t]; struct netmap_zmon_list *mz = &mkring->zmon_list[t]; /* 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; /* sinchronize 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 (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 * 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; } else { /* make sure the monitor array exists and is big enough */ error = nm_monitor_alloc(kring, kring->n_monitors + 1); if (error) goto out; kring->monitors[kring->n_monitors] = mkring; mkring->mon_pos[kring->tx] = kring->n_monitors; kring->n_monitors++; } out: nm_kr_start(kring); return error; }
int netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na, int create) { struct nmreq pnmr; struct netmap_adapter *pna; /* parent adapter */ struct netmap_pipe_adapter *mna, *sna, *req; struct ifnet *ifp, *ifp2; u_int pipe_id; int role = nmr->nr_flags & NR_REG_MASK; int error; ND("flags %x", nmr->nr_flags); if (role != NR_REG_PIPE_MASTER && role != NR_REG_PIPE_SLAVE) { ND("not a pipe"); return 0; } role = nmr->nr_flags & NR_REG_MASK; /* first, try to find the parent adapter */ bzero(&pnmr, sizeof(pnmr)); memcpy(&pnmr.nr_name, nmr->nr_name, IFNAMSIZ); /* pass to parent the requested number of pipes */ pnmr.nr_arg1 = nmr->nr_arg1; error = netmap_get_na(&pnmr, &pna, create); if (error) { ND("parent lookup failed: %d", error); return error; } ND("found parent: %s", NM_IFPNAME(pna->ifp)); if (NETMAP_OWNED_BY_KERN(pna)) { ND("parent busy"); error = EBUSY; goto put_out; } /* next, lookup the pipe id in the parent list */ req = NULL; pipe_id = nmr->nr_ringid & NETMAP_RING_MASK; mna = netmap_pipe_find(pna, pipe_id); if (mna) { if (mna->role == role) { ND("found %d directly at %d", pipe_id, mna->parent_slot); req = mna; } else { ND("found %d indirectly at %d", pipe_id, mna->parent_slot); req = mna->peer; } /* the pipe we have found already holds a ref to the parent, * so we need to drop the one we got from netmap_get_na() */ netmap_adapter_put(pna); goto found; } ND("pipe %d not found, create %d", pipe_id, create); if (!create) { error = ENODEV; goto put_out; } /* we create both master and slave. * The endpoint we were asked for holds a reference to * the other one. */ ifp = malloc(sizeof(*ifp), M_DEVBUF, M_NOWAIT | M_ZERO); if (!ifp) { error = ENOMEM; goto put_out; } strcpy(ifp->if_xname, NM_IFPNAME(pna->ifp)); mna = malloc(sizeof(*mna), M_DEVBUF, M_NOWAIT | M_ZERO); if (mna == NULL) { error = ENOMEM; goto free_ifp; } mna->up.ifp = ifp; mna->id = pipe_id; mna->role = NR_REG_PIPE_MASTER; mna->parent = pna; mna->up.nm_txsync = netmap_pipe_txsync; mna->up.nm_rxsync = netmap_pipe_rxsync; mna->up.nm_register = netmap_pipe_reg; mna->up.nm_dtor = netmap_pipe_dtor; mna->up.nm_krings_create = netmap_pipe_krings_create; mna->up.nm_krings_delete = netmap_pipe_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.num_tx_rings = 1; mna->up.num_rx_rings = 1; mna->up.num_tx_desc = nmr->nr_tx_slots; nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc, 1, NM_PIPE_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_PIPE_MAXSLOTS, NULL); error = netmap_attach_common(&mna->up); if (error) goto free_ifp; /* register the master with the parent */ error = netmap_pipe_add(pna, mna); if (error) goto free_mna; /* create the slave */ ifp2 = malloc(sizeof(*ifp), M_DEVBUF, M_NOWAIT | M_ZERO); if (!ifp) { error = ENOMEM; goto free_mna; } strcpy(ifp2->if_xname, NM_IFPNAME(pna->ifp)); sna = malloc(sizeof(*mna), M_DEVBUF, M_NOWAIT | M_ZERO); if (sna == NULL) { error = ENOMEM; goto free_ifp2; } /* most fields are the same, copy from master and then fix */ *sna = *mna; sna->up.ifp = ifp2; sna->role = NR_REG_PIPE_SLAVE; error = netmap_attach_common(&sna->up); if (error) goto free_sna; /* join the two endpoints */ mna->peer = sna; sna->peer = mna; /* we already have a reference to the parent, but we * need another one for the other endpoint we created */ netmap_adapter_get(pna); if (role == NR_REG_PIPE_MASTER) { req = mna; mna->peer_ref = 1; netmap_adapter_get(&sna->up); } else { req = sna; sna->peer_ref = 1; netmap_adapter_get(&mna->up); } ND("created master %p and slave %p", mna, sna); found: ND("pipe %d %s at %p", pipe_id, (req->role == NR_REG_PIPE_MASTER ? "master" : "slave"), req); *na = &req->up; netmap_adapter_get(*na); /* write the configuration back */ nmr->nr_tx_rings = req->up.num_tx_rings; nmr->nr_rx_rings = req->up.num_rx_rings; nmr->nr_tx_slots = req->up.num_tx_desc; nmr->nr_rx_slots = req->up.num_rx_desc; /* keep the reference to the parent. * It will be released by the req destructor */ return 0; free_sna: free(sna, M_DEVBUF); free_ifp2: free(ifp2, M_DEVBUF); free_mna: free(mna, M_DEVBUF); free_ifp: free(ifp, M_DEVBUF); put_out: netmap_adapter_put(pna); return error; }
/* 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; }