Routing enhancement - reduce routing table locking

K. Macy kmacy at freebsd.org
Tue Apr 19 19:06:02 UTC 2011


On Tue, Apr 19, 2011 at 8:19 PM, Freddie Cash <fjwcash at gmail.com> wrote:
> On Tue, Apr 19, 2011 at 7:42 AM, K. Macy <kmacy at freebsd.org> wrote:
>>> I'm not able to find IFNET_MULTIQUEUE in a recent 8.2-STABLE, is this something
>>> present only in HEAD?
>>
>> It looks like it is now EM_MULTIQUEUE.
>
> Just curious, how would one enable this to test it?  We have igb(4)
> interfaces in our new storage boxes, and it would be interesting to
> test whether or not it helps in our setup.
>

It should automatically allocate a queue per core up to the max
supported. Post 8.0 it should be enabled by default for igb:


#if __FreeBSD_version >= 800000
/*
** Multiqueue Transmit driver
**
*/
static int
igb_mq_start(struct ifnet *ifp, struct mbuf *m)
{
	struct adapter		*adapter = ifp->if_softc;
	struct igb_queue	*que;
	struct tx_ring		*txr;
	int 			i = 0, err = 0;

	/* Which queue to use */
	if ((m->m_flags & M_FLOWID) != 0)
		i = m->m_pkthdr.flowid % adapter->num_queues;

	txr = &adapter->tx_rings[i];
	que = &adapter->queues[i];

	if (IGB_TX_TRYLOCK(txr)) {
		err = igb_mq_start_locked(ifp, txr, m);
		IGB_TX_UNLOCK(txr);
	} else {
		err = drbr_enqueue(ifp, txr->br, m);
		taskqueue_enqueue(que->tq, &que->que_task);
	}

	return (err);
}

static int
igb_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m)
{
	struct adapter  *adapter = txr->adapter;
        struct mbuf     *next;
        int             err = 0, enq;

	IGB_TX_LOCK_ASSERT(txr);

	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
	    IFF_DRV_RUNNING || adapter->link_active == 0) {
		if (m != NULL)
			err = drbr_enqueue(ifp, txr->br, m);
		return (err);
	}

	/* Call cleanup if number of TX descriptors low */
	if (txr->tx_avail <= IGB_TX_CLEANUP_THRESHOLD)
		igb_txeof(txr);

	enq = 0;
	if (m == NULL) {
		next = drbr_dequeue(ifp, txr->br);
	} else if (drbr_needs_enqueue(ifp, txr->br)) {
		if ((err = drbr_enqueue(ifp, txr->br, m)) != 0)
			return (err);
		next = drbr_dequeue(ifp, txr->br);
	} else
		next = m;

	/* Process the queue */
	while (next != NULL) {
		if ((err = igb_xmit(txr, &next)) != 0) {
			if (next != NULL)
				err = drbr_enqueue(ifp, txr->br, next);
			break;
		}
		enq++;
		drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags);
		ETHER_BPF_MTAP(ifp, next);
		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
			break;
		if (txr->tx_avail <= IGB_TX_OP_THRESHOLD) {
			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
			break;
		}
		next = drbr_dequeue(ifp, txr->br);
	}
	if (enq > 0) {
		/* Set the watchdog */
		txr->queue_status = IGB_QUEUE_WORKING;
		txr->watchdog_time = ticks;
	}
	return (err);
}



I haven't tested this to make sure there aren't any hidden locking
performance issues.

Cheers


More information about the freebsd-net mailing list