xref: /freebsd/sys/netpfil/ipfw/dn_sched_rr.c (revision 2ff63af9b88c7413b7d71715b5532625752a248e)
1fe267a55SPedro F. Giffuni /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni  *
43b3a8eb9SGleb Smirnoff  * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa
53b3a8eb9SGleb Smirnoff  * All rights reserved
63b3a8eb9SGleb Smirnoff  *
73b3a8eb9SGleb Smirnoff  * Redistribution and use in source and binary forms, with or without
83b3a8eb9SGleb Smirnoff  * modification, are permitted provided that the following conditions
93b3a8eb9SGleb Smirnoff  * are met:
103b3a8eb9SGleb Smirnoff  * 1. Redistributions of source code must retain the above copyright
113b3a8eb9SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer.
123b3a8eb9SGleb Smirnoff  * 2. Redistributions in binary form must reproduce the above copyright
133b3a8eb9SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer in the
143b3a8eb9SGleb Smirnoff  *    documentation and/or other materials provided with the distribution.
153b3a8eb9SGleb Smirnoff  *
163b3a8eb9SGleb Smirnoff  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
173b3a8eb9SGleb Smirnoff  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
183b3a8eb9SGleb Smirnoff  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
193b3a8eb9SGleb Smirnoff  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
203b3a8eb9SGleb Smirnoff  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
213b3a8eb9SGleb Smirnoff  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
223b3a8eb9SGleb Smirnoff  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
233b3a8eb9SGleb Smirnoff  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
243b3a8eb9SGleb Smirnoff  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
253b3a8eb9SGleb Smirnoff  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
263b3a8eb9SGleb Smirnoff  * SUCH DAMAGE.
273b3a8eb9SGleb Smirnoff  */
283b3a8eb9SGleb Smirnoff 
293b3a8eb9SGleb Smirnoff /*
303b3a8eb9SGleb Smirnoff  */
313b3a8eb9SGleb Smirnoff 
323b3a8eb9SGleb Smirnoff #ifdef _KERNEL
333b3a8eb9SGleb Smirnoff #include <sys/malloc.h>
343b3a8eb9SGleb Smirnoff #include <sys/socket.h>
353b3a8eb9SGleb Smirnoff #include <sys/socketvar.h>
363b3a8eb9SGleb Smirnoff #include <sys/kernel.h>
374001fcbeSDon Lewis #include <sys/lock.h>
383b3a8eb9SGleb Smirnoff #include <sys/mbuf.h>
393b3a8eb9SGleb Smirnoff #include <sys/module.h>
404001fcbeSDon Lewis #include <sys/rwlock.h>
413b3a8eb9SGleb Smirnoff #include <net/if.h>	/* IFNAMSIZ */
423b3a8eb9SGleb Smirnoff #include <netinet/in.h>
433b3a8eb9SGleb Smirnoff #include <netinet/ip_var.h>		/* ipfw_rule_ref */
443b3a8eb9SGleb Smirnoff #include <netinet/ip_fw.h>	/* flow_id */
453b3a8eb9SGleb Smirnoff #include <netinet/ip_dummynet.h>
464001fcbeSDon Lewis #include <netpfil/ipfw/ip_fw_private.h>
473b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/dn_heap.h>
483b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/ip_dn_private.h>
4991336b40SDon Lewis #ifdef NEW_AQM
5091336b40SDon Lewis #include <netpfil/ipfw/dn_aqm.h>
5191336b40SDon Lewis #endif
523b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/dn_sched.h>
533b3a8eb9SGleb Smirnoff #else
543b3a8eb9SGleb Smirnoff #include <dn_test.h>
553b3a8eb9SGleb Smirnoff #endif
563b3a8eb9SGleb Smirnoff 
573b3a8eb9SGleb Smirnoff #define DN_SCHED_RR	3 // XXX Where?
583b3a8eb9SGleb Smirnoff 
593b3a8eb9SGleb Smirnoff struct rr_queue {
603b3a8eb9SGleb Smirnoff 	struct dn_queue q;		/* Standard queue */
613b3a8eb9SGleb Smirnoff 	int status;			/* 1: queue is in the list */
62f6a5c664SLuigi Rizzo 	uint32_t credit;		/* max bytes we can transmit */
63f6a5c664SLuigi Rizzo 	uint32_t quantum;		/* quantum * weight */
643b3a8eb9SGleb Smirnoff 	struct rr_queue *qnext;		/* */
653b3a8eb9SGleb Smirnoff };
663b3a8eb9SGleb Smirnoff 
673b3a8eb9SGleb Smirnoff /* struct rr_schk contains global config parameters
683b3a8eb9SGleb Smirnoff  * and is right after dn_schk
693b3a8eb9SGleb Smirnoff  */
703b3a8eb9SGleb Smirnoff struct rr_schk {
71f6a5c664SLuigi Rizzo 	uint32_t min_q;		/* Min quantum */
72f6a5c664SLuigi Rizzo 	uint32_t max_q;		/* Max quantum */
73f6a5c664SLuigi Rizzo 	uint32_t q_bytes;	/* default quantum in bytes */
743b3a8eb9SGleb Smirnoff };
753b3a8eb9SGleb Smirnoff 
763b3a8eb9SGleb Smirnoff /* per-instance round robin list, right after dn_sch_inst */
773b3a8eb9SGleb Smirnoff struct rr_si {
783b3a8eb9SGleb Smirnoff 	struct rr_queue *head, *tail;	/* Pointer to current queue */
793b3a8eb9SGleb Smirnoff };
803b3a8eb9SGleb Smirnoff 
813b3a8eb9SGleb Smirnoff /* Append a queue to the rr list */
823b3a8eb9SGleb Smirnoff static inline void
rr_append(struct rr_queue * q,struct rr_si * si)833b3a8eb9SGleb Smirnoff rr_append(struct rr_queue *q, struct rr_si *si)
843b3a8eb9SGleb Smirnoff {
853b3a8eb9SGleb Smirnoff 	q->status = 1;		/* mark as in-rr_list */
863b3a8eb9SGleb Smirnoff 	q->credit = q->quantum;	/* initialize credit */
873b3a8eb9SGleb Smirnoff 
883b3a8eb9SGleb Smirnoff 	/* append to the tail */
893b3a8eb9SGleb Smirnoff 	if (si->head == NULL)
903b3a8eb9SGleb Smirnoff 		si->head = q;
913b3a8eb9SGleb Smirnoff 	else
923b3a8eb9SGleb Smirnoff 		si->tail->qnext = q;
933b3a8eb9SGleb Smirnoff 	si->tail = q;		/* advance the tail pointer */
943b3a8eb9SGleb Smirnoff 	q->qnext = si->head;	/* make it circular */
953b3a8eb9SGleb Smirnoff }
963b3a8eb9SGleb Smirnoff 
973b3a8eb9SGleb Smirnoff /* Remove the head queue from circular list. */
983b3a8eb9SGleb Smirnoff static inline void
rr_remove_head(struct rr_si * si)993b3a8eb9SGleb Smirnoff rr_remove_head(struct rr_si *si)
1003b3a8eb9SGleb Smirnoff {
1013b3a8eb9SGleb Smirnoff 	if (si->head == NULL)
1023b3a8eb9SGleb Smirnoff 		return; /* empty queue */
1033b3a8eb9SGleb Smirnoff 	si->head->status = 0;
1043b3a8eb9SGleb Smirnoff 
1053b3a8eb9SGleb Smirnoff 	if (si->head == si->tail) {
1063b3a8eb9SGleb Smirnoff 		si->head = si->tail = NULL;
1073b3a8eb9SGleb Smirnoff 		return;
1083b3a8eb9SGleb Smirnoff 	}
1093b3a8eb9SGleb Smirnoff 
1103b3a8eb9SGleb Smirnoff 	si->head = si->head->qnext;
1113b3a8eb9SGleb Smirnoff 	si->tail->qnext = si->head;
1123b3a8eb9SGleb Smirnoff }
1133b3a8eb9SGleb Smirnoff 
1143b3a8eb9SGleb Smirnoff /* Remove a queue from circular list.
1153b3a8eb9SGleb Smirnoff  * XXX see if ti can be merge with remove_queue()
1163b3a8eb9SGleb Smirnoff  */
1173b3a8eb9SGleb Smirnoff static inline void
remove_queue_q(struct rr_queue * q,struct rr_si * si)1183b3a8eb9SGleb Smirnoff remove_queue_q(struct rr_queue *q, struct rr_si *si)
1193b3a8eb9SGleb Smirnoff {
1203b3a8eb9SGleb Smirnoff 	struct rr_queue *prev;
1213b3a8eb9SGleb Smirnoff 
1223b3a8eb9SGleb Smirnoff 	if (q->status != 1)
1233b3a8eb9SGleb Smirnoff 		return;
1243b3a8eb9SGleb Smirnoff 	if (q == si->head) {
1253b3a8eb9SGleb Smirnoff 		rr_remove_head(si);
1263b3a8eb9SGleb Smirnoff 		return;
1273b3a8eb9SGleb Smirnoff 	}
1283b3a8eb9SGleb Smirnoff 
1293b3a8eb9SGleb Smirnoff 	for (prev = si->head; prev; prev = prev->qnext) {
1303b3a8eb9SGleb Smirnoff 		if (prev->qnext != q)
1313b3a8eb9SGleb Smirnoff 			continue;
1323b3a8eb9SGleb Smirnoff 		prev->qnext = q->qnext;
1333b3a8eb9SGleb Smirnoff 		if (q == si->tail)
1343b3a8eb9SGleb Smirnoff 			si->tail = prev;
1353b3a8eb9SGleb Smirnoff 		q->status = 0;
1363b3a8eb9SGleb Smirnoff 		break;
1373b3a8eb9SGleb Smirnoff 	}
1383b3a8eb9SGleb Smirnoff }
1393b3a8eb9SGleb Smirnoff 
1403b3a8eb9SGleb Smirnoff static inline void
next_pointer(struct rr_si * si)1413b3a8eb9SGleb Smirnoff next_pointer(struct rr_si *si)
1423b3a8eb9SGleb Smirnoff {
1433b3a8eb9SGleb Smirnoff 	if (si->head == NULL)
1443b3a8eb9SGleb Smirnoff 		return; /* empty queue */
1453b3a8eb9SGleb Smirnoff 
1463b3a8eb9SGleb Smirnoff 	si->head = si->head->qnext;
1473b3a8eb9SGleb Smirnoff 	si->tail = si->tail->qnext;
1483b3a8eb9SGleb Smirnoff }
1493b3a8eb9SGleb Smirnoff 
1503b3a8eb9SGleb Smirnoff static int
rr_enqueue(struct dn_sch_inst * _si,struct dn_queue * q,struct mbuf * m)1513b3a8eb9SGleb Smirnoff rr_enqueue(struct dn_sch_inst *_si, struct dn_queue *q, struct mbuf *m)
1523b3a8eb9SGleb Smirnoff {
1533b3a8eb9SGleb Smirnoff 	struct rr_si *si;
1543b3a8eb9SGleb Smirnoff 	struct rr_queue *rrq;
1553b3a8eb9SGleb Smirnoff 
1563b3a8eb9SGleb Smirnoff 	if (m != q->mq.head) {
1573b3a8eb9SGleb Smirnoff 		if (dn_enqueue(q, m, 0)) /* packet was dropped */
1583b3a8eb9SGleb Smirnoff 			return 1;
1593b3a8eb9SGleb Smirnoff 		if (m != q->mq.head)
1603b3a8eb9SGleb Smirnoff 			return 0;
1613b3a8eb9SGleb Smirnoff 	}
1623b3a8eb9SGleb Smirnoff 
1633b3a8eb9SGleb Smirnoff 	/* If reach this point, queue q was idle */
1643b3a8eb9SGleb Smirnoff 	si = (struct rr_si *)(_si + 1);
1653b3a8eb9SGleb Smirnoff 	rrq = (struct rr_queue *)q;
1663b3a8eb9SGleb Smirnoff 
1673b3a8eb9SGleb Smirnoff 	if (rrq->status == 1) /* Queue is already in the queue list */
1683b3a8eb9SGleb Smirnoff 		return 0;
1693b3a8eb9SGleb Smirnoff 
1703b3a8eb9SGleb Smirnoff 	/* Insert the queue in the queue list */
1713b3a8eb9SGleb Smirnoff 	rr_append(rrq, si);
1723b3a8eb9SGleb Smirnoff 
1733b3a8eb9SGleb Smirnoff 	return 0;
1743b3a8eb9SGleb Smirnoff }
1753b3a8eb9SGleb Smirnoff 
1763b3a8eb9SGleb Smirnoff static struct mbuf *
rr_dequeue(struct dn_sch_inst * _si)1773b3a8eb9SGleb Smirnoff rr_dequeue(struct dn_sch_inst *_si)
1783b3a8eb9SGleb Smirnoff {
1793b3a8eb9SGleb Smirnoff 	/* Access scheduler instance private data */
1803b3a8eb9SGleb Smirnoff 	struct rr_si *si = (struct rr_si *)(_si + 1);
1813b3a8eb9SGleb Smirnoff 	struct rr_queue *rrq;
1823b3a8eb9SGleb Smirnoff 	uint64_t len;
1833b3a8eb9SGleb Smirnoff 
1843b3a8eb9SGleb Smirnoff 	while ( (rrq = si->head) ) {
1853b3a8eb9SGleb Smirnoff 		struct mbuf *m = rrq->q.mq.head;
1863b3a8eb9SGleb Smirnoff 		if ( m == NULL) {
1873b3a8eb9SGleb Smirnoff 			/* empty queue, remove from list */
1883b3a8eb9SGleb Smirnoff 			rr_remove_head(si);
1893b3a8eb9SGleb Smirnoff 			continue;
1903b3a8eb9SGleb Smirnoff 		}
1913b3a8eb9SGleb Smirnoff 		len = m->m_pkthdr.len;
1923b3a8eb9SGleb Smirnoff 
1933b3a8eb9SGleb Smirnoff 		if (len > rrq->credit) {
1943b3a8eb9SGleb Smirnoff 			/* Packet too big */
1953b3a8eb9SGleb Smirnoff 			rrq->credit += rrq->quantum;
1963b3a8eb9SGleb Smirnoff 			/* Try next queue */
1973b3a8eb9SGleb Smirnoff 			next_pointer(si);
1983b3a8eb9SGleb Smirnoff 		} else {
1993b3a8eb9SGleb Smirnoff 			rrq->credit -= len;
2003b3a8eb9SGleb Smirnoff 			return dn_dequeue(&rrq->q);
2013b3a8eb9SGleb Smirnoff 		}
2023b3a8eb9SGleb Smirnoff 	}
2033b3a8eb9SGleb Smirnoff 
2043b3a8eb9SGleb Smirnoff 	/* no packet to dequeue*/
2053b3a8eb9SGleb Smirnoff 	return NULL;
2063b3a8eb9SGleb Smirnoff }
2073b3a8eb9SGleb Smirnoff 
2083b3a8eb9SGleb Smirnoff static int
rr_config(struct dn_schk * _schk)2093b3a8eb9SGleb Smirnoff rr_config(struct dn_schk *_schk)
2103b3a8eb9SGleb Smirnoff {
2113b3a8eb9SGleb Smirnoff 	struct rr_schk *schk = (struct rr_schk *)(_schk + 1);
2123b3a8eb9SGleb Smirnoff 	ND("called");
2133b3a8eb9SGleb Smirnoff 
2143b3a8eb9SGleb Smirnoff 	/* use reasonable quantums (64..2k bytes, default 1500) */
2153b3a8eb9SGleb Smirnoff 	schk->min_q = 64;
2163b3a8eb9SGleb Smirnoff 	schk->max_q = 2048;
2173b3a8eb9SGleb Smirnoff 	schk->q_bytes = 1500;	/* quantum */
2183b3a8eb9SGleb Smirnoff 
2193b3a8eb9SGleb Smirnoff 	return 0;
2203b3a8eb9SGleb Smirnoff }
2213b3a8eb9SGleb Smirnoff 
2223b3a8eb9SGleb Smirnoff static int
rr_new_sched(struct dn_sch_inst * _si)2233b3a8eb9SGleb Smirnoff rr_new_sched(struct dn_sch_inst *_si)
2243b3a8eb9SGleb Smirnoff {
2253b3a8eb9SGleb Smirnoff 	struct rr_si *si = (struct rr_si *)(_si + 1);
2263b3a8eb9SGleb Smirnoff 
2273b3a8eb9SGleb Smirnoff 	ND("called");
2283b3a8eb9SGleb Smirnoff 	si->head = si->tail = NULL;
2293b3a8eb9SGleb Smirnoff 
2303b3a8eb9SGleb Smirnoff 	return 0;
2313b3a8eb9SGleb Smirnoff }
2323b3a8eb9SGleb Smirnoff 
2333b3a8eb9SGleb Smirnoff static int
rr_free_sched(struct dn_sch_inst * _si)2343b3a8eb9SGleb Smirnoff rr_free_sched(struct dn_sch_inst *_si)
2353b3a8eb9SGleb Smirnoff {
236f6a5c664SLuigi Rizzo 	(void)_si;
2373b3a8eb9SGleb Smirnoff 	ND("called");
2383b3a8eb9SGleb Smirnoff 	/* Nothing to do? */
2393b3a8eb9SGleb Smirnoff 	return 0;
2403b3a8eb9SGleb Smirnoff }
2413b3a8eb9SGleb Smirnoff 
2423b3a8eb9SGleb Smirnoff static int
rr_new_fsk(struct dn_fsk * fs)2433b3a8eb9SGleb Smirnoff rr_new_fsk(struct dn_fsk *fs)
2443b3a8eb9SGleb Smirnoff {
2453b3a8eb9SGleb Smirnoff 	struct rr_schk *schk = (struct rr_schk *)(fs->sched + 1);
2463b3a8eb9SGleb Smirnoff 	/* par[0] is the weight, par[1] is the quantum step */
247f6a5c664SLuigi Rizzo 	/* make sure the product fits an uint32_t */
2483b3a8eb9SGleb Smirnoff 	ipdn_bound_var(&fs->fs.par[0], 1,
2493b3a8eb9SGleb Smirnoff 		1, 65536, "RR weight");
2503b3a8eb9SGleb Smirnoff 	ipdn_bound_var(&fs->fs.par[1], schk->q_bytes,
2513b3a8eb9SGleb Smirnoff 		schk->min_q, schk->max_q, "RR quantum");
2523b3a8eb9SGleb Smirnoff 	return 0;
2533b3a8eb9SGleb Smirnoff }
2543b3a8eb9SGleb Smirnoff 
2553b3a8eb9SGleb Smirnoff static int
rr_new_queue(struct dn_queue * _q)2563b3a8eb9SGleb Smirnoff rr_new_queue(struct dn_queue *_q)
2573b3a8eb9SGleb Smirnoff {
2583b3a8eb9SGleb Smirnoff 	struct rr_queue *q = (struct rr_queue *)_q;
259f6a5c664SLuigi Rizzo 	uint64_t quantum;
2603b3a8eb9SGleb Smirnoff 
2613b3a8eb9SGleb Smirnoff 	_q->ni.oid.subtype = DN_SCHED_RR;
2623b3a8eb9SGleb Smirnoff 
263f6a5c664SLuigi Rizzo 	quantum = (uint64_t)_q->fs->fs.par[0] * _q->fs->fs.par[1];
264f6a5c664SLuigi Rizzo 	if (quantum >= (1ULL<< 32)) {
265f6a5c664SLuigi Rizzo 		D("quantum too large, truncating to 4G - 1");
266f6a5c664SLuigi Rizzo 		quantum = (1ULL<< 32) - 1;
267f6a5c664SLuigi Rizzo 	}
268f6a5c664SLuigi Rizzo 	q->quantum = quantum;
2693b3a8eb9SGleb Smirnoff 	ND("called, q->quantum %d", q->quantum);
2703b3a8eb9SGleb Smirnoff 	q->credit = q->quantum;
2713b3a8eb9SGleb Smirnoff 	q->status = 0;
2723b3a8eb9SGleb Smirnoff 
2733b3a8eb9SGleb Smirnoff 	if (_q->mq.head != NULL) {
2743b3a8eb9SGleb Smirnoff 		/* Queue NOT empty, insert in the queue list */
2753b3a8eb9SGleb Smirnoff 		rr_append(q, (struct rr_si *)(_q->_si + 1));
2763b3a8eb9SGleb Smirnoff 	}
2773b3a8eb9SGleb Smirnoff 	return 0;
2783b3a8eb9SGleb Smirnoff }
2793b3a8eb9SGleb Smirnoff 
2803b3a8eb9SGleb Smirnoff static int
rr_free_queue(struct dn_queue * _q)2813b3a8eb9SGleb Smirnoff rr_free_queue(struct dn_queue *_q)
2823b3a8eb9SGleb Smirnoff {
2833b3a8eb9SGleb Smirnoff 	struct rr_queue *q = (struct rr_queue *)_q;
2843b3a8eb9SGleb Smirnoff 
2853b3a8eb9SGleb Smirnoff 	ND("called");
2863b3a8eb9SGleb Smirnoff 	if (q->status == 1) {
2873b3a8eb9SGleb Smirnoff 		struct rr_si *si = (struct rr_si *)(_q->_si + 1);
2883b3a8eb9SGleb Smirnoff 		remove_queue_q(q, si);
2893b3a8eb9SGleb Smirnoff 	}
2903b3a8eb9SGleb Smirnoff 	return 0;
2913b3a8eb9SGleb Smirnoff }
2923b3a8eb9SGleb Smirnoff 
2933b3a8eb9SGleb Smirnoff /*
2943b3a8eb9SGleb Smirnoff  * RR scheduler descriptor
2953b3a8eb9SGleb Smirnoff  * contains the type of the scheduler, the name, the size of the
2963b3a8eb9SGleb Smirnoff  * structures and function pointers.
2973b3a8eb9SGleb Smirnoff  */
2983b3a8eb9SGleb Smirnoff static struct dn_alg rr_desc = {
2993b3a8eb9SGleb Smirnoff 	_SI( .type = ) DN_SCHED_RR,
3003b3a8eb9SGleb Smirnoff 	_SI( .name = ) "RR",
3013b3a8eb9SGleb Smirnoff 	_SI( .flags = ) DN_MULTIQUEUE,
3023b3a8eb9SGleb Smirnoff 
303788c0c66SLuigi Rizzo 	_SI( .schk_datalen = ) sizeof(struct rr_schk),
3043b3a8eb9SGleb Smirnoff 	_SI( .si_datalen = ) sizeof(struct rr_si),
3053b3a8eb9SGleb Smirnoff 	_SI( .q_datalen = ) sizeof(struct rr_queue) - sizeof(struct dn_queue),
3063b3a8eb9SGleb Smirnoff 
3073b3a8eb9SGleb Smirnoff 	_SI( .enqueue = ) rr_enqueue,
3083b3a8eb9SGleb Smirnoff 	_SI( .dequeue = ) rr_dequeue,
3093b3a8eb9SGleb Smirnoff 
3103b3a8eb9SGleb Smirnoff 	_SI( .config = ) rr_config,
3113b3a8eb9SGleb Smirnoff 	_SI( .destroy = ) NULL,
3123b3a8eb9SGleb Smirnoff 	_SI( .new_sched = ) rr_new_sched,
3133b3a8eb9SGleb Smirnoff 	_SI( .free_sched = ) rr_free_sched,
3143b3a8eb9SGleb Smirnoff 	_SI( .new_fsk = ) rr_new_fsk,
3153b3a8eb9SGleb Smirnoff 	_SI( .free_fsk = ) NULL,
3163b3a8eb9SGleb Smirnoff 	_SI( .new_queue = ) rr_new_queue,
3173b3a8eb9SGleb Smirnoff 	_SI( .free_queue = ) rr_free_queue,
31891336b40SDon Lewis #ifdef NEW_AQM
31991336b40SDon Lewis 	_SI( .getconfig = )  NULL,
32091336b40SDon Lewis #endif
3213b3a8eb9SGleb Smirnoff };
3223b3a8eb9SGleb Smirnoff 
3233b3a8eb9SGleb Smirnoff DECLARE_DNSCHED_MODULE(dn_rr, &rr_desc);
324