FreeBSD/sys/dev/netmap/netmap_monitor.c
/* check if nmr is a request for a monitor adapter that we can satisfy */
check if nmr is a request for a monitor adapter that we can satisfy
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; 
	struct netmap_monitor_adapter *mna;
	int i, error;
	enum txrx t;
	int zcopy = (nmr->nr_flags & NR_ZCOPY_MON);
	char monsuff[10] = "";
	if ((nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) {
		ND("not a monitor");
		return 0;
	}
	D("flags %x", nmr->nr_flags);
	mna = malloc(sizeof(*mna), M_DEVBUF, M_NOWAIT | M_ZERO);
	if (mna == NULL) {
		D("memory error");
		return ENOMEM;
	}
	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)) {
		D("%s not in netmap mode", pna->name);
		error = EINVAL;
		goto put_out;
	}
	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 (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,
			zcopy ? "z" : "",
			(nmr->nr_flags & NR_MONITOR_RX) ? "r" : "",
			(nmr->nr_flags & NR_MONITOR_TX) ? "t" : "");
	if (zcopy) {
		for_rx_tx(t) {
			if (! (nmr->nr_flags & nm_txrx2flag(t)))
				continue;
			for (i = mna->priv.np_qfirst[t]; i < mna->priv.np_qlast[t]; i++) {
				struct netmap_kring *kring = &NMR(pna, t)[i];
				if (kring->n_monitors > 0) {
					error = EBUSY;
					D("ring %s already monitored by %s", kring->name,
							kring->monitors[0]->name);
					goto put_out;
				}
			}
		}
		mna->up.nm_register = netmap_zmon_reg;
		mna->up.nm_dtor = netmap_zmon_dtor;
		mna->up.nm_mem = pna->nm_mem;
		mna->up.na_lut = pna->na_lut;
	} else {
		for_rx_tx(t) {
			if (! (nmr->nr_flags & nm_txrx2flag(t)))
				continue;
			for (i = mna->priv.np_qfirst[t]; i < mna->priv.np_qlast[t]; i++) {
				struct netmap_kring *kring = &NMR(pna, t)[i];
				if (kring->n_monitors > 0 &&
				    kring->monitors[0]->na->nm_register == netmap_zmon_reg)
				{
					error = EBUSY;
					D("ring busy");
					goto put_out;
				}
			}
		}
		mna->up.nm_rxsync = netmap_monitor_rxsync;
		mna->up.nm_register = netmap_monitor_reg;
		mna->up.nm_dtor = netmap_monitor_dtor;
	}
	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_krings_create = netmap_monitor_krings_create;
	mna->up.nm_krings_delete = netmap_monitor_krings_delete;
	mna->up.num_tx_rings = 1; 
	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;
	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 put_out;
	}
	mna->flags = (nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX));
	*na = &mna->up;
	netmap_adapter_get(*na);
	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;
	D("monitor ok");
	return 0;
put_out:
	netmap_adapter_put(pna);
	free(mna, M_DEVBUF);
	return error;
}
int netmap_get_monitor_na ( struct nmreq * nmr , struct netmap_adapter * * na , int create ) { struct nmreq pnmr ; struct netmap_adapter * pna ; struct netmap_monitor_adapter * mna ; int i , error ; enum txrx t ; int zcopy = ( nmr -> nr_flags & NR_ZCOPY_MON ) ; char monsuff [ 10 ] = " " ; if ( ( nmr -> nr_flags & ( NR_MONITOR_TX | NR_MONITOR_RX ) ) == 0 ) { ND ( " " ) ; return 0 ; } D ( " " , nmr -> nr_flags ) ; mna = malloc ( sizeof ( * mna ) , M_DEVBUF , M_NOWAIT | M_ZERO ) ; if ( mna == NULL ) { D ( " " ) ; return ENOMEM ; } memcpy ( & pnmr , nmr , sizeof ( pnmr ) ) ; pnmr . nr_flags &= ~ ( NR_MONITOR_TX | NR_MONITOR_RX ) ; error = netmap_get_na ( & pnmr , & pna , create ) ; if ( error ) { D ( " " , error ) ; return error ; } D ( " " , pna -> name ) ; if ( ! nm_netmap_on ( pna ) ) { D ( " " , pna -> name ) ; error = EINVAL ; goto put_out ; } mna -> priv . np_na = pna ; error = netmap_interp_ringid ( & mna -> priv , nmr -> nr_ringid , nmr -> nr_flags ) ; if ( error ) { D ( " " ) ; goto put_out ; } if ( mna -> priv . np_qlast [ NR_TX ] - mna -> priv . np_qfirst [ NR_TX ] == 1 ) { snprintf ( monsuff , 10 , " " , mna -> priv . np_qfirst [ NR_TX ] ) ; } snprintf ( mna -> up . name , sizeof ( mna -> up . name ) , " " , pna -> name , monsuff , zcopy ? " " : " " , ( nmr -> nr_flags & NR_MONITOR_RX ) ? " " : " " , ( nmr -> nr_flags & NR_MONITOR_TX ) ? " " : " " ) ; if ( zcopy ) { for_rx_tx ( t ) { if ( ! ( nmr -> nr_flags & nm_txrx2flag ( t ) ) ) continue ; for ( i = mna -> priv . np_qfirst [ t ] ; i < mna -> priv . np_qlast [ t ] ; i ++ ) { struct netmap_kring * kring = & NMR ( pna , t ) [ i ] ; if ( kring -> n_monitors > 0 ) { error = EBUSY ; D ( " " , kring -> name , kring -> monitors [ 0 ] -> name ) ; goto put_out ; } } } mna -> up . nm_register = netmap_zmon_reg ; mna -> up . nm_dtor = netmap_zmon_dtor ; mna -> up . nm_mem = pna -> nm_mem ; mna -> up . na_lut = pna -> na_lut ; } else { for_rx_tx ( t ) { if ( ! ( nmr -> nr_flags & nm_txrx2flag ( t ) ) ) continue ; for ( i = mna -> priv . np_qfirst [ t ] ; i < mna -> priv . np_qlast [ t ] ; i ++ ) { struct netmap_kring * kring = & NMR ( pna , t ) [ i ] ; if ( kring -> n_monitors > 0 && kring -> monitors [ 0 ] -> na -> nm_register == netmap_zmon_reg ) { error = EBUSY ; D ( " " ) ; goto put_out ; } } } mna -> up . nm_rxsync = netmap_monitor_rxsync ; mna -> up . nm_register = netmap_monitor_reg ; mna -> up . nm_dtor = netmap_monitor_dtor ; } 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_krings_create = netmap_monitor_krings_create ; mna -> up . nm_krings_delete = netmap_monitor_krings_delete ; mna -> up . num_tx_rings = 1 ; 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 ; 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 ( " " ) ; goto put_out ; } mna -> flags = ( nmr -> nr_flags & ( NR_MONITOR_TX | NR_MONITOR_RX ) ) ; * na = & mna -> up ; netmap_adapter_get ( * na ) ; 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 ; D ( " " ) ; return 0 ; put_out : netmap_adapter_put ( pna ) ; free ( mna , M_DEVBUF ) ; return error ; }
check if nmr is a request for a monitor adapter that we can satisfy
check if nmr is a request for a monitor adapter that we can satisfy
/* parent adapter */ /* this is a request for a monitor adapter */ /* 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.
	 */ /* 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)
		 */ /* grab all the rings we need in the parent */ /* zero copy monitors need exclusive access to the monitored rings */ /* to have zero copy, we need to use the same memory allocator
		 * as the monitored port
		 */ /* normal monitors are incompatible with zero copy ones */ /* the monitor supports the host rings iff the parent does */ /* a do-nothing txsync: monitors cannot be used to inject packets */ // 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
	 */ /* by default, the number of slots is the same as in
	 * the parent rings, but the user may ask for a different
	 * number
	 */ /* remember the traffic directions we have to monitor */ /* write the configuration back */ /* keep the reference to the parent */