FreeBSD/sys/netpfil/ipfw/ip_dn_io.c
/*
 * dummynet hook for packets.
 * We use the argument to locate the flowset fs and the sched_set sch
 * associated to it. The we apply flow_mask and sched_mask to
 * determine the queue and scheduler instances.
 *
 * dir		where shall we send the packet after dummynet.
 * *m0		the mbuf with the packet
 * ifp		the 'ifp' parameter from the caller.
 *		NULL in ip_input, destination interface in ip_output,
 */
dummynet hook for packets.
We use the argument to locate the flowset fs and the sched_set sch
associated to it. The we apply flow_mask and sched_mask to
determine the queue and scheduler instances.

dir          where shall we send the packet after dummynet.
*m0          the mbuf with the packet
ifp          the 'ifp' parameter from the caller.
NULL in ip_input, destination interface in ip_output.
dummynet hook for packets . We use the argument to locate the flowset fs and the sched_set sch associated to it . The we apply flow_mask and sched_mask to determine the queue and scheduler instances . dir where shall we send the packet after dummynet . * m0 the mbuf with the packet ifp the ' ifp ' parameter from the caller . NULL in ip_input destination interface in ip_output .
int
dummynet_io(struct mbuf **m0, int dir, struct ip_fw_args *fwa)
{
	struct mbuf *m = *m0;
	struct dn_fsk *fs = NULL;
	struct dn_sch_inst *si;
	struct dn_queue *q = NULL;	
	int fs_id = (fwa->rule.info & IPFW_INFO_MASK) +
		((fwa->rule.info & IPFW_IS_PIPE) ? 2*DN_MAX_ID : 0);
	DN_BH_WLOCK();
	io_pkt++;
	if (tag_mbuf(m, dir, fwa))
		goto dropit;
	if (dn_cfg.busy) {
		mq_append(&dn_cfg.pending, m);
		m = *m0 = NULL; 
		goto done; 
	}
	fs = dn_ht_find(dn_cfg.fshash, fs_id, 0, NULL);
	if (fs == NULL)
		goto dropit;	
	if (fs->sched == NULL)	
		goto dropit;
	si = ipdn_si_find(fs->sched, &(fwa->f_id));
	if (si == NULL)
		goto dropit;
	if (fs->sched->fp->flags & DN_MULTIQUEUE) {
		q = ipdn_q_find(fs, si, &(fwa->f_id));
		if (q == NULL)
			goto dropit;
	}
	if (fs->sched->fp->enqueue(si, q, m)) {
		m = *m0 = NULL;
		io_pkt_drop--;
		goto dropit;
	}
	if (si->kflags & DN_ACTIVE) {
		m = *m0 = NULL; 
		goto done; 
	}
	if (si->idle_time < dn_cfg.curr_time) {
	    struct dn_link *p = &fs->sched->link;
	    si->sched_time = dn_cfg.curr_time;
	    si->credit = dn_cfg.io_fast ? p->bandwidth : 0;
	    if (p->burst) {
		uint64_t burst = (dn_cfg.curr_time - si->idle_time) * p->bandwidth;
		if (burst > p->burst)
			burst = p->burst;
		si->credit += burst;
	    }
	}
	m = serve_sched(NULL, si, dn_cfg.curr_time);
	if ( m == *m0 && (dir & PROTO_LAYER2) == 0 ) {
		struct m_tag *tag = m_tag_first(m);
		tag->m_tag_cookie = MTAG_IPFW_RULE;
		tag->m_tag_id = 0;
		io_pkt_fast++;
		if (m->m_nextpkt != NULL) {
			printf("dummynet: fast io: pkt chain detected!\n");
			m->m_nextpkt = NULL;
		}
		m = NULL;
	} else {
		*m0 = NULL;
	}
done:
	DN_BH_WUNLOCK();
	if (m)
		dummynet_send(m);
	return 0;
dropit:
	io_pkt_drop++;
	DN_BH_WUNLOCK();
	if (m)
		FREE_PKT(m);
	*m0 = NULL;
	return (fs && (fs->fs.flags & DN_NOERROR)) ? 0 : ENOBUFS;
}
int dummynet_io ( struct mbuf * * m0 , int dir , struct ip_fw_args * fwa ) { struct mbuf * m = * m0 ; struct dn_fsk * fs = NULL ; struct dn_sch_inst * si ; struct dn_queue * q = NULL ; int fs_id = ( fwa -> rule . info & IPFW_INFO_MASK ) + ( ( fwa -> rule . info & IPFW_IS_PIPE ) ? 2 * DN_MAX_ID : 0 ) ; DN_BH_WLOCK ( ) ; io_pkt ++ ; if ( tag_mbuf ( m , dir , fwa ) ) goto dropit ; if ( dn_cfg . busy ) { mq_append ( & dn_cfg . pending , m ) ; m = * m0 = NULL ; goto done ; } fs = dn_ht_find ( dn_cfg . fshash , fs_id , 0 , NULL ) ; if ( fs == NULL ) goto dropit ; if ( fs -> sched == NULL ) goto dropit ; si = ipdn_si_find ( fs -> sched , & ( fwa -> f_id ) ) ; if ( si == NULL ) goto dropit ; if ( fs -> sched -> fp -> flags & DN_MULTIQUEUE ) { q = ipdn_q_find ( fs , si , & ( fwa -> f_id ) ) ; if ( q == NULL ) goto dropit ; } if ( fs -> sched -> fp -> enqueue ( si , q , m ) ) { m = * m0 = NULL ; io_pkt_drop -- ; goto dropit ; } if ( si -> kflags & DN_ACTIVE ) { m = * m0 = NULL ; goto done ; } if ( si -> idle_time < dn_cfg . curr_time ) { struct dn_link * p = & fs -> sched -> link ; si -> sched_time = dn_cfg . curr_time ; si -> credit = dn_cfg . io_fast ? p -> bandwidth : 0 ; if ( p -> burst ) { uint64_t burst = ( dn_cfg . curr_time - si -> idle_time ) * p -> bandwidth ; if ( burst > p -> burst ) burst = p -> burst ; si -> credit += burst ; } } m = serve_sched ( NULL , si , dn_cfg . curr_time ) ; if ( m == * m0 && ( dir & PROTO_LAYER2 ) == 0 ) { struct m_tag * tag = m_tag_first ( m ) ; tag -> m_tag_cookie = MTAG_IPFW_RULE ; tag -> m_tag_id = 0 ; io_pkt_fast ++ ; if ( m -> m_nextpkt != NULL ) { printf ( " \n " ) ; m -> m_nextpkt = NULL ; } m = NULL ; } else { * m0 = NULL ; } done : DN_BH_WUNLOCK ( ) ; if ( m ) dummynet_send ( m ) ; return 0 ; dropit : io_pkt_drop ++ ; DN_BH_WUNLOCK ( ) ; if ( m ) FREE_PKT ( m ) ; * m0 = NULL ; return ( fs && ( fs -> fs . flags & DN_NOERROR ) ) ? 0 : ENOBUFS ; }
dummynet hook for packets.
dummynet hook for packets .
/* default */ /* we could actually tag outside the lock, but who cares... */ /* if the upper half is busy doing something expensive,
		 * lets queue the packet and move forward
		 */ /* consumed */ /* already active, nothing to do */ /* XXX locate_flowset could be optimised with a direct ref. */ /* This queue/pipe does not exist! */ /* should not happen */ /* find scheduler instance, possibly applying sched_mask */ /*
	 * If the scheduler supports multiple queues, find the right one
	 * (otherwise it will be ignored by enqueue).
	 */ /* packet was dropped by enqueue() */ /* dn_enqueue already increases io_pkt_drop */ /* consumed */ /* already active, nothing to do */ /* compute the initial allowance */ /* Do this only on the first packet on an idle pipe */ /* pass through scheduler and delay line */ /* optimization -- pass it back to ipfw for immediate send */ /* XXX Don't call dummynet_send() if scheduler return the packet
	 *     just enqueued. This avoid a lock order reversal.
	 *     
	 */ /*dn_cfg.io_fast &&*/ /* fast io, rename the tag * to carry reinject info. */