예제 #1
0
/* 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;
			}
		}
	}
}
예제 #2
0
/* 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;
}
예제 #3
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);
}
예제 #4
0
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;
}
예제 #5
0
/* 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;
			}
		}
	}
}
예제 #6
0
/* 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;
}
예제 #7
0
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;
}
예제 #8
0
/* 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;
}