1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2010 Riccardo Panicucci, Luigi Rizzo, Universita` di Pisa 5 * All rights reserved 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 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. 15 * 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 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * The API to write a packet scheduling algorithm for dummynet. 31 * 32 * $FreeBSD$ 33 */ 34 35 #ifndef _DN_SCHED_H 36 #define _DN_SCHED_H 37 38 #include <sys/ck.h> 39 40 #define DN_MULTIQUEUE 0x01 41 /* 42 * Descriptor for a scheduling algorithm. 43 * Contains all function pointers for a given scheduler 44 * This is typically created when a module is loaded, and stored 45 * in a global list of schedulers. 46 */ 47 struct dn_alg { 48 uint32_t type; /* the scheduler type */ 49 const char *name; /* scheduler name */ 50 uint32_t flags; /* DN_MULTIQUEUE if supports multiple queues */ 51 52 /* 53 * The following define the size of 3 optional data structures 54 * that may need to be allocated at runtime, and are appended 55 * to each of the base data structures: scheduler, sched.inst, 56 * and queue. We don't have a per-flowset structure. 57 */ 58 /* + parameters attached to the template, e.g. 59 * default queue sizes, weights, quantum size, and so on; 60 */ 61 size_t schk_datalen; 62 63 /* + per-instance parameters, such as timestamps, 64 * containers for queues, etc; 65 */ 66 size_t si_datalen; 67 68 size_t q_datalen; /* per-queue parameters (e.g. S,F) */ 69 70 /* 71 * Methods implemented by the scheduler: 72 * enqueue enqueue packet 'm' on scheduler 's', queue 'q'. 73 * q is NULL for !MULTIQUEUE. 74 * Return 0 on success, 1 on drop (packet consumed anyways). 75 * Note that q should be interpreted only as a hint 76 * on the flow that the mbuf belongs to: while a 77 * scheduler will normally enqueue m into q, it is ok 78 * to leave q alone and put the mbuf elsewhere. 79 * This function is called in two cases: 80 * - when a new packet arrives to the scheduler; 81 * - when a scheduler is reconfigured. In this case the 82 * call is issued by the new_queue callback, with a 83 * non empty queue (q) and m pointing to the first 84 * mbuf in the queue. For this reason, the function 85 * should internally check for (m != q->mq.head) 86 * before calling dn_enqueue(). 87 * 88 * dequeue Called when scheduler instance 's' can 89 * dequeue a packet. Return NULL if none are available. 90 * XXX what about non work-conserving ? 91 * 92 * config called on 'sched X config ...', normally writes 93 * in the area of size sch_arg 94 * 95 * destroy called on 'sched delete', frees everything 96 * in sch_arg (other parts are handled by more specific 97 * functions) 98 * 99 * new_sched called when a new instance is created, e.g. 100 * to create the local queue for !MULTIQUEUE, set V or 101 * copy parameters for WFQ, and so on. 102 * 103 * free_sched called when deleting an instance, cleans 104 * extra data in the per-instance area. 105 * 106 * new_fsk called when a flowset is linked to a scheduler, 107 * e.g. to validate parameters such as weights etc. 108 * free_fsk when a flowset is unlinked from a scheduler. 109 * (probably unnecessary) 110 * 111 * new_queue called to set the per-queue parameters, 112 * e.g. S and F, adjust sum of weights in the parent, etc. 113 * 114 * The new_queue callback is normally called from when 115 * creating a new queue. In some cases (such as a 116 * scheduler change or reconfiguration) it can be called 117 * with a non empty queue. In this case, the queue 118 * In case of non empty queue, the new_queue callback could 119 * need to call the enqueue function. In this case, 120 * the callback should eventually call enqueue() passing 121 * as m the first element in the queue. 122 * 123 * free_queue actions related to a queue removal, e.g. undo 124 * all the above. If the queue has data in it, also remove 125 * from the scheduler. This can e.g. happen during a reconfigure. 126 */ 127 int (*enqueue)(struct dn_sch_inst *, struct dn_queue *, 128 struct mbuf *); 129 struct mbuf * (*dequeue)(struct dn_sch_inst *); 130 131 int (*config)(struct dn_schk *); 132 int (*destroy)(struct dn_schk*); 133 int (*new_sched)(struct dn_sch_inst *); 134 int (*free_sched)(struct dn_sch_inst *); 135 int (*new_fsk)(struct dn_fsk *f); 136 int (*free_fsk)(struct dn_fsk *f); 137 int (*new_queue)(struct dn_queue *q); 138 int (*free_queue)(struct dn_queue *q); 139 #ifdef NEW_AQM 140 /* Getting scheduler extra parameters */ 141 int (*getconfig)(struct dn_schk *, struct dn_extra_parms *); 142 #endif 143 144 /* run-time fields */ 145 int ref_count; /* XXX number of instances in the system */ 146 CK_LIST_ENTRY(dn_alg) next; /* Next scheduler in the list */ 147 }; 148 149 /* MSVC does not support initializers so we need this ugly macro */ 150 #ifdef _WIN32 151 #define _SI(fld) 152 #else 153 #define _SI(fld) fld 154 #endif 155 156 /* 157 * Additionally, dummynet exports some functions and macros 158 * to be used by schedulers: 159 */ 160 161 void dn_free_pkts(struct mbuf *mnext); 162 int dn_enqueue(struct dn_queue *q, struct mbuf* m, int drop); 163 /* bound a variable between min and max */ 164 int ipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg); 165 166 /* 167 * Extract the head of a queue, update stats. Must be the very last 168 * thing done on a dequeue as the queue itself may go away. 169 */ 170 static __inline struct mbuf* 171 dn_dequeue(struct dn_queue *q) 172 { 173 struct mbuf *m; 174 175 next: 176 m = q->mq.head; 177 if (m == NULL) 178 return NULL; 179 #ifdef NEW_AQM 180 /* Call AQM dequeue function */ 181 if (q->fs->aqmfp && q->fs->aqmfp->dequeue ) 182 return q->fs->aqmfp->dequeue(q); 183 #endif 184 q->mq.head = m->m_nextpkt; 185 q->mq.count--; 186 187 /* Update stats for the queue */ 188 q->ni.length--; 189 q->ni.len_bytes -= m->m_pkthdr.len; 190 if (q->_si) { 191 q->_si->ni.length--; 192 q->_si->ni.len_bytes -= m->m_pkthdr.len; 193 } 194 if (q->ni.length == 0) /* queue is now idle */ 195 q->q_time = V_dn_cfg.curr_time; 196 if (m->m_pkthdr.rcvif != NULL && 197 __predict_false(m_rcvif_restore(m) == NULL)) { 198 m_freem(m); 199 goto next; 200 } 201 return m; 202 } 203 204 int dn_sched_modevent(module_t mod, int cmd, void *arg); 205 206 #define DECLARE_DNSCHED_MODULE(name, dnsched) \ 207 static moduledata_t name##_mod = { \ 208 #name, dn_sched_modevent, dnsched \ 209 }; \ 210 DECLARE_MODULE(name, name##_mod, \ 211 SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY); \ 212 MODULE_DEPEND(name, dummynet, 3, 3, 3) 213 #endif /* _DN_SCHED_H */ 214