2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2010 Riccardo Panicucci, Luigi Rizzo, Universita` di Pisa
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * The API to write a packet scheduling algorithm for dummynet.
38 #define DN_MULTIQUEUE 0x01
40 * Descriptor for a scheduling algorithm.
41 * Contains all function pointers for a given scheduler
42 * This is typically created when a module is loaded, and stored
43 * in a global list of schedulers.
46 uint32_t type; /* the scheduler type */
47 const char *name; /* scheduler name */
48 uint32_t flags; /* DN_MULTIQUEUE if supports multiple queues */
51 * The following define the size of 3 optional data structures
52 * that may need to be allocated at runtime, and are appended
53 * to each of the base data structures: scheduler, sched.inst,
54 * and queue. We don't have a per-flowset structure.
56 /* + parameters attached to the template, e.g.
57 * default queue sizes, weights, quantum size, and so on;
61 /* + per-instance parameters, such as timestamps,
62 * containers for queues, etc;
66 size_t q_datalen; /* per-queue parameters (e.g. S,F) */
69 * Methods implemented by the scheduler:
70 * enqueue enqueue packet 'm' on scheduler 's', queue 'q'.
71 * q is NULL for !MULTIQUEUE.
72 * Return 0 on success, 1 on drop (packet consumed anyways).
73 * Note that q should be interpreted only as a hint
74 * on the flow that the mbuf belongs to: while a
75 * scheduler will normally enqueue m into q, it is ok
76 * to leave q alone and put the mbuf elsewhere.
77 * This function is called in two cases:
78 * - when a new packet arrives to the scheduler;
79 * - when a scheduler is reconfigured. In this case the
80 * call is issued by the new_queue callback, with a
81 * non empty queue (q) and m pointing to the first
82 * mbuf in the queue. For this reason, the function
83 * should internally check for (m != q->mq.head)
84 * before calling dn_enqueue().
86 * dequeue Called when scheduler instance 's' can
87 * dequeue a packet. Return NULL if none are available.
88 * XXX what about non work-conserving ?
90 * config called on 'sched X config ...', normally writes
91 * in the area of size sch_arg
93 * destroy called on 'sched delete', frees everything
94 * in sch_arg (other parts are handled by more specific
97 * new_sched called when a new instance is created, e.g.
98 * to create the local queue for !MULTIQUEUE, set V or
99 * copy parameters for WFQ, and so on.
101 * free_sched called when deleting an instance, cleans
102 * extra data in the per-instance area.
104 * new_fsk called when a flowset is linked to a scheduler,
105 * e.g. to validate parameters such as weights etc.
106 * free_fsk when a flowset is unlinked from a scheduler.
107 * (probably unnecessary)
109 * new_queue called to set the per-queue parameters,
110 * e.g. S and F, adjust sum of weights in the parent, etc.
112 * The new_queue callback is normally called from when
113 * creating a new queue. In some cases (such as a
114 * scheduler change or reconfiguration) it can be called
115 * with a non empty queue. In this case, the queue
116 * In case of non empty queue, the new_queue callback could
117 * need to call the enqueue function. In this case,
118 * the callback should eventually call enqueue() passing
119 * as m the first element in the queue.
121 * free_queue actions related to a queue removal, e.g. undo
122 * all the above. If the queue has data in it, also remove
123 * from the scheduler. This can e.g. happen during a reconfigure.
125 int (*enqueue)(struct dn_sch_inst *, struct dn_queue *,
127 struct mbuf * (*dequeue)(struct dn_sch_inst *);
129 int (*config)(struct dn_schk *);
130 int (*destroy)(struct dn_schk*);
131 int (*new_sched)(struct dn_sch_inst *);
132 int (*free_sched)(struct dn_sch_inst *);
133 int (*new_fsk)(struct dn_fsk *f);
134 int (*free_fsk)(struct dn_fsk *f);
135 int (*new_queue)(struct dn_queue *q);
136 int (*free_queue)(struct dn_queue *q);
138 /* Getting scheduler extra parameters */
139 int (*getconfig)(struct dn_schk *, struct dn_extra_parms *);
142 /* run-time fields */
143 int ref_count; /* XXX number of instances in the system */
144 SLIST_ENTRY(dn_alg) next; /* Next scheduler in the list */
147 /* MSVC does not support initializers so we need this ugly macro */
155 * Additionally, dummynet exports some functions and macros
156 * to be used by schedulers:
159 void dn_free_pkts(struct mbuf *mnext);
160 int dn_enqueue(struct dn_queue *q, struct mbuf* m, int drop);
161 /* bound a variable between min and max */
162 int ipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg);
165 * Extract the head of a queue, update stats. Must be the very last
166 * thing done on a dequeue as the queue itself may go away.
168 static __inline struct mbuf*
169 dn_dequeue(struct dn_queue *q)
171 struct mbuf *m = q->mq.head;
175 /* Call AQM dequeue function */
176 if (q->fs->aqmfp && q->fs->aqmfp->dequeue )
177 return q->fs->aqmfp->dequeue(q);
179 q->mq.head = m->m_nextpkt;
182 /* Update stats for the queue */
184 q->ni.len_bytes -= m->m_pkthdr.len;
187 q->_si->ni.len_bytes -= m->m_pkthdr.len;
189 if (q->ni.length == 0) /* queue is now idle */
190 q->q_time = dn_cfg.curr_time;
194 int dn_sched_modevent(module_t mod, int cmd, void *arg);
196 #define DECLARE_DNSCHED_MODULE(name, dnsched) \
197 static moduledata_t name##_mod = { \
198 #name, dn_sched_modevent, dnsched \
200 DECLARE_MODULE(name, name##_mod, \
201 SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY); \
202 MODULE_DEPEND(name, dummynet, 3, 3, 3)
203 #endif /* _DN_SCHED_H */