altq_jobs.c revision 1.1.2.1 1 1.1.2.1 peter /* $NetBSD: altq_jobs.c,v 1.1.2.1 2006/03/18 12:08:18 peter Exp $ */
2 1.1.2.1 peter /* $KAME: altq_jobs.c,v 1.11 2005/04/13 03:44:25 suz Exp $ */
3 1.1.2.1 peter /*
4 1.1.2.1 peter * Copyright (c) 2001, the Rector and Board of Visitors of the
5 1.1.2.1 peter * University of Virginia.
6 1.1.2.1 peter * All rights reserved.
7 1.1.2.1 peter *
8 1.1.2.1 peter * Redistribution and use in source and binary forms,
9 1.1.2.1 peter * with or without modification, are permitted provided
10 1.1.2.1 peter * that the following conditions are met:
11 1.1.2.1 peter *
12 1.1.2.1 peter * Redistributions of source code must retain the above
13 1.1.2.1 peter * copyright notice, this list of conditions and the following
14 1.1.2.1 peter * disclaimer.
15 1.1.2.1 peter *
16 1.1.2.1 peter * Redistributions in binary form must reproduce the above
17 1.1.2.1 peter * copyright notice, this list of conditions and the following
18 1.1.2.1 peter * disclaimer in the documentation and/or other materials provided
19 1.1.2.1 peter * with the distribution.
20 1.1.2.1 peter *
21 1.1.2.1 peter * Neither the name of the University of Virginia nor the names
22 1.1.2.1 peter * of its contributors may be used to endorse or promote products
23 1.1.2.1 peter * derived from this software without specific prior written
24 1.1.2.1 peter * permission.
25 1.1.2.1 peter *
26 1.1.2.1 peter * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
27 1.1.2.1 peter * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
28 1.1.2.1 peter * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
29 1.1.2.1 peter * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30 1.1.2.1 peter * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
31 1.1.2.1 peter * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
32 1.1.2.1 peter * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 1.1.2.1 peter * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 1.1.2.1 peter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35 1.1.2.1 peter * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 1.1.2.1 peter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
37 1.1.2.1 peter * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
38 1.1.2.1 peter * THE POSSIBILITY OF SUCH DAMAGE.
39 1.1.2.1 peter */
40 1.1.2.1 peter /*
41 1.1.2.1 peter * JoBS - altq prototype implementation
42 1.1.2.1 peter *
43 1.1.2.1 peter * Author: Nicolas Christin <nicolas (at) cs.virginia.edu>
44 1.1.2.1 peter *
45 1.1.2.1 peter * JoBS algorithms originally devised and proposed by
46 1.1.2.1 peter * Nicolas Christin and Jorg Liebeherr.
47 1.1.2.1 peter * Grateful acknowledgments to Tarek Abdelzaher for his help and
48 1.1.2.1 peter * comments, and to Kenjiro Cho for some helpful advice.
49 1.1.2.1 peter * Contributed by the Multimedia Networks Group at the University
50 1.1.2.1 peter * of Virginia.
51 1.1.2.1 peter *
52 1.1.2.1 peter * Papers and additional info can be found at
53 1.1.2.1 peter * http://qosbox.cs.virginia.edu
54 1.1.2.1 peter *
55 1.1.2.1 peter */
56 1.1.2.1 peter
57 1.1.2.1 peter /*
58 1.1.2.1 peter * JoBS queue
59 1.1.2.1 peter */
60 1.1.2.1 peter
61 1.1.2.1 peter #include <sys/cdefs.h>
62 1.1.2.1 peter __KERNEL_RCSID(0, "$NetBSD: altq_jobs.c,v 1.1.2.1 2006/03/18 12:08:18 peter Exp $");
63 1.1.2.1 peter
64 1.1.2.1 peter #ifdef _KERNEL_OPT
65 1.1.2.1 peter #include "opt_altq.h"
66 1.1.2.1 peter #include "opt_inet.h"
67 1.1.2.1 peter #endif
68 1.1.2.1 peter
69 1.1.2.1 peter #ifdef ALTQ_JOBS /* jobs is enabled by ALTQ_JOBS option in opt_altq.h */
70 1.1.2.1 peter
71 1.1.2.1 peter #include <sys/param.h>
72 1.1.2.1 peter #include <sys/malloc.h>
73 1.1.2.1 peter #include <sys/mbuf.h>
74 1.1.2.1 peter #include <sys/socket.h>
75 1.1.2.1 peter #include <sys/sockio.h>
76 1.1.2.1 peter #include <sys/systm.h>
77 1.1.2.1 peter #include <sys/proc.h>
78 1.1.2.1 peter #include <sys/errno.h>
79 1.1.2.1 peter #include <sys/kernel.h>
80 1.1.2.1 peter #include <sys/queue.h>
81 1.1.2.1 peter
82 1.1.2.1 peter #ifdef __FreeBSD__
83 1.1.2.1 peter #include <sys/limits.h>
84 1.1.2.1 peter #endif
85 1.1.2.1 peter
86 1.1.2.1 peter #include <net/if.h>
87 1.1.2.1 peter #include <net/if_types.h>
88 1.1.2.1 peter
89 1.1.2.1 peter #include <altq/altq.h>
90 1.1.2.1 peter #include <altq/altq_conf.h>
91 1.1.2.1 peter #include <altq/altq_jobs.h>
92 1.1.2.1 peter
93 1.1.2.1 peter #ifdef ALTQ3_COMPAT
94 1.1.2.1 peter /*
95 1.1.2.1 peter * function prototypes
96 1.1.2.1 peter */
97 1.1.2.1 peter static struct jobs_if *jobs_attach(struct ifaltq *, u_int, u_int, u_int);
98 1.1.2.1 peter static int jobs_detach(struct jobs_if *);
99 1.1.2.1 peter static int jobs_clear_interface(struct jobs_if *);
100 1.1.2.1 peter static int jobs_request(struct ifaltq *, int, void *);
101 1.1.2.1 peter static void jobs_purge(struct jobs_if *);
102 1.1.2.1 peter static struct jobs_class *jobs_class_create(struct jobs_if *,
103 1.1.2.1 peter int, int64_t, int64_t, int64_t, int64_t, int64_t, int);
104 1.1.2.1 peter static int jobs_class_destroy(struct jobs_class *);
105 1.1.2.1 peter static int jobs_enqueue(struct ifaltq *, struct mbuf *, struct altq_pktattr *);
106 1.1.2.1 peter static struct mbuf *jobs_dequeue(struct ifaltq *, int);
107 1.1.2.1 peter
108 1.1.2.1 peter static int jobs_addq(struct jobs_class *, struct mbuf *, struct jobs_if*);
109 1.1.2.1 peter static struct mbuf *jobs_getq(struct jobs_class *);
110 1.1.2.1 peter static struct mbuf *jobs_pollq(struct jobs_class *);
111 1.1.2.1 peter static void jobs_purgeq(struct jobs_class *);
112 1.1.2.1 peter
113 1.1.2.1 peter static int jobscmd_if_attach(struct jobs_attach *);
114 1.1.2.1 peter static int jobscmd_if_detach(struct jobs_interface *);
115 1.1.2.1 peter static int jobscmd_add_class(struct jobs_add_class *);
116 1.1.2.1 peter static int jobscmd_delete_class(struct jobs_delete_class *);
117 1.1.2.1 peter static int jobscmd_modify_class(struct jobs_modify_class *);
118 1.1.2.1 peter static int jobscmd_add_filter(struct jobs_add_filter *);
119 1.1.2.1 peter static int jobscmd_delete_filter(struct jobs_delete_filter *);
120 1.1.2.1 peter static int jobscmd_class_stats(struct jobs_class_stats *);
121 1.1.2.1 peter static void get_class_stats(struct class_stats *, struct jobs_class *);
122 1.1.2.1 peter static struct jobs_class *clh_to_clp(struct jobs_if *, u_long);
123 1.1.2.1 peter static u_long clp_to_clh(struct jobs_class *);
124 1.1.2.1 peter
125 1.1.2.1 peter static TSLIST *tslist_alloc(void);
126 1.1.2.1 peter static void tslist_destroy(struct jobs_class *);
127 1.1.2.1 peter static int tslist_enqueue(struct jobs_class *, u_int64_t);
128 1.1.2.1 peter static void tslist_dequeue(struct jobs_class *);
129 1.1.2.1 peter static void tslist_drop(struct jobs_class *);
130 1.1.2.1 peter
131 1.1.2.1 peter static int enforce_wc(struct jobs_if *);
132 1.1.2.1 peter static int64_t* adjust_rates_rdc(struct jobs_if *);
133 1.1.2.1 peter static int64_t* assign_rate_drops_adc(struct jobs_if *);
134 1.1.2.1 peter static int64_t* update_error(struct jobs_if *);
135 1.1.2.1 peter static int min_rates_adc(struct jobs_if *);
136 1.1.2.1 peter static int64_t proj_delay(struct jobs_if *, int);
137 1.1.2.1 peter static int pick_dropped_rlc(struct jobs_if *);
138 1.1.2.1 peter
139 1.1.2.1 peter altqdev_decl(jobs);
140 1.1.2.1 peter
141 1.1.2.1 peter /* jif_list keeps all jobs_if's allocated. */
142 1.1.2.1 peter static struct jobs_if *jif_list = NULL;
143 1.1.2.1 peter
144 1.1.2.1 peter typedef unsigned long long ull;
145 1.1.2.1 peter
146 1.1.2.1 peter /* setup functions */
147 1.1.2.1 peter
148 1.1.2.1 peter static struct jobs_if *
149 1.1.2.1 peter jobs_attach(ifq, bandwidth, qlimit, separate)
150 1.1.2.1 peter struct ifaltq *ifq;
151 1.1.2.1 peter u_int bandwidth;
152 1.1.2.1 peter u_int qlimit;
153 1.1.2.1 peter u_int separate;
154 1.1.2.1 peter {
155 1.1.2.1 peter struct jobs_if *jif;
156 1.1.2.1 peter
157 1.1.2.1 peter MALLOC(jif, struct jobs_if *, sizeof(struct jobs_if),
158 1.1.2.1 peter M_DEVBUF, M_WAITOK);
159 1.1.2.1 peter
160 1.1.2.1 peter if (jif == NULL)
161 1.1.2.1 peter return (NULL);
162 1.1.2.1 peter
163 1.1.2.1 peter (void)memset(jif, 0, sizeof(struct jobs_if));
164 1.1.2.1 peter jif->jif_bandwidth = bandwidth;
165 1.1.2.1 peter jif->jif_qlimit = qlimit;
166 1.1.2.1 peter jif->jif_separate = separate;
167 1.1.2.1 peter #ifdef ALTQ_DEBUG
168 1.1.2.1 peter printf("JoBS bandwidth = %d bps\n", (int)bandwidth);
169 1.1.2.1 peter printf("JoBS buffer size = %d pkts [%s]\n",
170 1.1.2.1 peter (int)qlimit, separate?"separate buffers":"shared buffer");
171 1.1.2.1 peter #endif
172 1.1.2.1 peter jif->jif_maxpri = -1;
173 1.1.2.1 peter jif->jif_ifq = ifq;
174 1.1.2.1 peter
175 1.1.2.1 peter jif->wc_cycles_enqueue = 0;
176 1.1.2.1 peter jif->avg_cycles_enqueue = 0;
177 1.1.2.1 peter jif->avg_cycles2_enqueue = 0;
178 1.1.2.1 peter jif->bc_cycles_enqueue = INFINITY;
179 1.1.2.1 peter jif->wc_cycles_dequeue = 0;
180 1.1.2.1 peter jif->avg_cycles_dequeue = 0;
181 1.1.2.1 peter jif->avg_cycles2_dequeue = 0;
182 1.1.2.1 peter jif->bc_cycles_dequeue = INFINITY;
183 1.1.2.1 peter jif->total_enqueued = 0;
184 1.1.2.1 peter jif->total_dequeued = 0;
185 1.1.2.1 peter
186 1.1.2.1 peter /* add this state to the jobs list */
187 1.1.2.1 peter jif->jif_next = jif_list;
188 1.1.2.1 peter jif_list = jif;
189 1.1.2.1 peter
190 1.1.2.1 peter return (jif);
191 1.1.2.1 peter }
192 1.1.2.1 peter
193 1.1.2.1 peter static int
194 1.1.2.1 peter jobs_detach(jif)
195 1.1.2.1 peter struct jobs_if *jif;
196 1.1.2.1 peter {
197 1.1.2.1 peter (void)jobs_clear_interface(jif);
198 1.1.2.1 peter
199 1.1.2.1 peter /* remove this interface from the jif list */
200 1.1.2.1 peter if (jif_list == jif)
201 1.1.2.1 peter jif_list = jif->jif_next;
202 1.1.2.1 peter else {
203 1.1.2.1 peter struct jobs_if *p;
204 1.1.2.1 peter
205 1.1.2.1 peter for (p = jif_list; p != NULL; p = p->jif_next)
206 1.1.2.1 peter if (p->jif_next == jif) {
207 1.1.2.1 peter p->jif_next = jif->jif_next;
208 1.1.2.1 peter break;
209 1.1.2.1 peter }
210 1.1.2.1 peter ASSERT(p != NULL);
211 1.1.2.1 peter }
212 1.1.2.1 peter FREE(jif, M_DEVBUF);
213 1.1.2.1 peter return (0);
214 1.1.2.1 peter }
215 1.1.2.1 peter
216 1.1.2.1 peter /*
217 1.1.2.1 peter * bring the interface back to the initial state by discarding
218 1.1.2.1 peter * all the filters and classes.
219 1.1.2.1 peter */
220 1.1.2.1 peter static int
221 1.1.2.1 peter jobs_clear_interface(jif)
222 1.1.2.1 peter struct jobs_if *jif;
223 1.1.2.1 peter {
224 1.1.2.1 peter struct jobs_class *cl;
225 1.1.2.1 peter int pri;
226 1.1.2.1 peter
227 1.1.2.1 peter /* free the filters for this interface */
228 1.1.2.1 peter acc_discard_filters(&jif->jif_classifier, NULL, 1);
229 1.1.2.1 peter
230 1.1.2.1 peter /* clear out the classes */
231 1.1.2.1 peter for (pri = 0; pri <= jif->jif_maxpri; pri++)
232 1.1.2.1 peter if ((cl = jif->jif_classes[pri]) != NULL)
233 1.1.2.1 peter jobs_class_destroy(cl);
234 1.1.2.1 peter
235 1.1.2.1 peter return (0);
236 1.1.2.1 peter }
237 1.1.2.1 peter
238 1.1.2.1 peter static int
239 1.1.2.1 peter jobs_request(ifq, req, arg)
240 1.1.2.1 peter struct ifaltq *ifq;
241 1.1.2.1 peter int req;
242 1.1.2.1 peter void *arg;
243 1.1.2.1 peter {
244 1.1.2.1 peter struct jobs_if *jif = (struct jobs_if *)ifq->altq_disc;
245 1.1.2.1 peter
246 1.1.2.1 peter switch (req) {
247 1.1.2.1 peter case ALTRQ_PURGE:
248 1.1.2.1 peter jobs_purge(jif);
249 1.1.2.1 peter break;
250 1.1.2.1 peter }
251 1.1.2.1 peter return (0);
252 1.1.2.1 peter }
253 1.1.2.1 peter
254 1.1.2.1 peter /* discard all the queued packets on the interface */
255 1.1.2.1 peter static void
256 1.1.2.1 peter jobs_purge(jif)
257 1.1.2.1 peter struct jobs_if *jif;
258 1.1.2.1 peter {
259 1.1.2.1 peter struct jobs_class *cl;
260 1.1.2.1 peter int pri;
261 1.1.2.1 peter
262 1.1.2.1 peter for (pri = 0; pri <= jif->jif_maxpri; pri++) {
263 1.1.2.1 peter if ((cl = jif->jif_classes[pri]) != NULL && !qempty(cl->cl_q))
264 1.1.2.1 peter jobs_purgeq(cl);
265 1.1.2.1 peter }
266 1.1.2.1 peter if (ALTQ_IS_ENABLED(jif->jif_ifq))
267 1.1.2.1 peter jif->jif_ifq->ifq_len = 0;
268 1.1.2.1 peter }
269 1.1.2.1 peter
270 1.1.2.1 peter static struct jobs_class *
271 1.1.2.1 peter jobs_class_create(jif, pri, adc, rdc, alc, rlc, arc, flags)
272 1.1.2.1 peter struct jobs_if *jif;
273 1.1.2.1 peter int pri;
274 1.1.2.1 peter int64_t adc, rdc, alc, rlc, arc;
275 1.1.2.1 peter int flags;
276 1.1.2.1 peter {
277 1.1.2.1 peter struct jobs_class *cl, *scan1, *scan2;
278 1.1.2.1 peter int s;
279 1.1.2.1 peter int class_exists1, class_exists2;
280 1.1.2.1 peter int i, j;
281 1.1.2.1 peter int64_t tmp[JOBS_MAXPRI];
282 1.1.2.1 peter u_int64_t now;
283 1.1.2.1 peter
284 1.1.2.1 peter if ((cl = jif->jif_classes[pri]) != NULL) {
285 1.1.2.1 peter /* modify the class instead of creating a new one */
286 1.1.2.1 peter s = splnet();
287 1.1.2.1 peter if (!qempty(cl->cl_q))
288 1.1.2.1 peter jobs_purgeq(cl);
289 1.1.2.1 peter splx(s);
290 1.1.2.1 peter } else {
291 1.1.2.1 peter MALLOC(cl, struct jobs_class *, sizeof(struct jobs_class),
292 1.1.2.1 peter M_DEVBUF, M_WAITOK);
293 1.1.2.1 peter if (cl == NULL)
294 1.1.2.1 peter return (NULL);
295 1.1.2.1 peter (void)memset(cl, 0, sizeof(struct jobs_class));
296 1.1.2.1 peter
297 1.1.2.1 peter MALLOC(cl->cl_q, class_queue_t *, sizeof(class_queue_t),
298 1.1.2.1 peter M_DEVBUF, M_WAITOK);
299 1.1.2.1 peter if (cl->cl_q == NULL)
300 1.1.2.1 peter goto err_ret;
301 1.1.2.1 peter (void)memset(cl->cl_q, 0, sizeof(class_queue_t));
302 1.1.2.1 peter
303 1.1.2.1 peter cl->arv_tm = tslist_alloc();
304 1.1.2.1 peter if (cl->arv_tm == NULL)
305 1.1.2.1 peter goto err_ret;
306 1.1.2.1 peter }
307 1.1.2.1 peter
308 1.1.2.1 peter jif->jif_classes[pri] = cl;
309 1.1.2.1 peter
310 1.1.2.1 peter if (flags & JOCF_DEFAULTCLASS)
311 1.1.2.1 peter jif->jif_default = cl;
312 1.1.2.1 peter
313 1.1.2.1 peter qtype(cl->cl_q) = Q_DROPTAIL;
314 1.1.2.1 peter qlen(cl->cl_q) = 0;
315 1.1.2.1 peter cl->service_rate = 0;
316 1.1.2.1 peter cl->min_rate_adc = 0;
317 1.1.2.1 peter cl->current_loss = 0;
318 1.1.2.1 peter cl->cl_period = 0;
319 1.1.2.1 peter PKTCNTR_RESET(&cl->cl_arrival);
320 1.1.2.1 peter PKTCNTR_RESET(&cl->cl_rin);
321 1.1.2.1 peter PKTCNTR_RESET(&cl->cl_rout);
322 1.1.2.1 peter PKTCNTR_RESET(&cl->cl_rout_th);
323 1.1.2.1 peter PKTCNTR_RESET(&cl->cl_dropcnt);
324 1.1.2.1 peter PKTCNTR_RESET(&cl->st_arrival);
325 1.1.2.1 peter PKTCNTR_RESET(&cl->st_rin);
326 1.1.2.1 peter PKTCNTR_RESET(&cl->st_rout);
327 1.1.2.1 peter PKTCNTR_RESET(&cl->st_dropcnt);
328 1.1.2.1 peter cl->st_service_rate = 0;
329 1.1.2.1 peter cl->cl_lastdel = 0;
330 1.1.2.1 peter cl->cl_avgdel = 0;
331 1.1.2.1 peter cl->adc_violations = 0;
332 1.1.2.1 peter
333 1.1.2.1 peter if (adc == -1) {
334 1.1.2.1 peter cl->concerned_adc = 0;
335 1.1.2.1 peter adc = INFINITY;
336 1.1.2.1 peter } else
337 1.1.2.1 peter cl->concerned_adc = 1;
338 1.1.2.1 peter
339 1.1.2.1 peter if (alc == -1) {
340 1.1.2.1 peter cl->concerned_alc = 0;
341 1.1.2.1 peter alc = INFINITY;
342 1.1.2.1 peter } else
343 1.1.2.1 peter cl->concerned_alc = 1;
344 1.1.2.1 peter
345 1.1.2.1 peter if (rdc == -1) {
346 1.1.2.1 peter rdc = 0;
347 1.1.2.1 peter cl->concerned_rdc = 0;
348 1.1.2.1 peter } else
349 1.1.2.1 peter cl->concerned_rdc = 1;
350 1.1.2.1 peter
351 1.1.2.1 peter if (rlc == -1) {
352 1.1.2.1 peter rlc = 0;
353 1.1.2.1 peter cl->concerned_rlc = 0;
354 1.1.2.1 peter } else
355 1.1.2.1 peter cl->concerned_rlc = 1;
356 1.1.2.1 peter
357 1.1.2.1 peter if (arc == -1) {
358 1.1.2.1 peter arc = 0;
359 1.1.2.1 peter cl->concerned_arc = 0;
360 1.1.2.1 peter } else
361 1.1.2.1 peter cl->concerned_arc = 1;
362 1.1.2.1 peter
363 1.1.2.1 peter cl->cl_rdc=rdc;
364 1.1.2.1 peter
365 1.1.2.1 peter if (cl->concerned_adc) {
366 1.1.2.1 peter /* adc is given in us, convert it to clock ticks */
367 1.1.2.1 peter cl->cl_adc = (u_int64_t)(adc*machclk_freq/GRANULARITY);
368 1.1.2.1 peter } else
369 1.1.2.1 peter cl->cl_adc = adc;
370 1.1.2.1 peter
371 1.1.2.1 peter if (cl->concerned_arc) {
372 1.1.2.1 peter /* arc is given in bps, convert it to internal unit */
373 1.1.2.1 peter cl->cl_arc = (u_int64_t)(bps_to_internal(arc));
374 1.1.2.1 peter } else
375 1.1.2.1 peter cl->cl_arc = arc;
376 1.1.2.1 peter
377 1.1.2.1 peter cl->cl_rlc=rlc;
378 1.1.2.1 peter cl->cl_alc=alc;
379 1.1.2.1 peter cl->delay_prod_others = 0;
380 1.1.2.1 peter cl->loss_prod_others = 0;
381 1.1.2.1 peter cl->cl_flags = flags;
382 1.1.2.1 peter cl->cl_pri = pri;
383 1.1.2.1 peter if (pri > jif->jif_maxpri)
384 1.1.2.1 peter jif->jif_maxpri = pri;
385 1.1.2.1 peter cl->cl_jif = jif;
386 1.1.2.1 peter cl->cl_handle = (u_long)cl; /* just a pointer to this class */
387 1.1.2.1 peter
388 1.1.2.1 peter /*
389 1.1.2.1 peter * update delay_prod_others and loss_prod_others
390 1.1.2.1 peter * in all classes if needed
391 1.1.2.1 peter */
392 1.1.2.1 peter
393 1.1.2.1 peter if (cl->concerned_rdc) {
394 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
395 1.1.2.1 peter scan1 = jif->jif_classes[i];
396 1.1.2.1 peter class_exists1 = (scan1 != NULL);
397 1.1.2.1 peter if (class_exists1) {
398 1.1.2.1 peter tmp[i] = 1;
399 1.1.2.1 peter for (j = 0; j <= i-1; j++) {
400 1.1.2.1 peter scan2 = jif->jif_classes[j];
401 1.1.2.1 peter class_exists2 = (scan2 != NULL);
402 1.1.2.1 peter if (class_exists2
403 1.1.2.1 peter && scan2->concerned_rdc)
404 1.1.2.1 peter tmp[i] *= scan2->cl_rdc;
405 1.1.2.1 peter }
406 1.1.2.1 peter } else
407 1.1.2.1 peter tmp[i] = 0;
408 1.1.2.1 peter }
409 1.1.2.1 peter
410 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
411 1.1.2.1 peter scan1 = jif->jif_classes[i];
412 1.1.2.1 peter class_exists1 = (scan1 != NULL);
413 1.1.2.1 peter if (class_exists1) {
414 1.1.2.1 peter scan1->delay_prod_others = 1;
415 1.1.2.1 peter for (j = 0; j <= jif->jif_maxpri; j++) {
416 1.1.2.1 peter scan2 = jif->jif_classes[j];
417 1.1.2.1 peter class_exists2 = (scan2 != NULL);
418 1.1.2.1 peter if (class_exists2 && j != i
419 1.1.2.1 peter && scan2->concerned_rdc)
420 1.1.2.1 peter scan1->delay_prod_others *= tmp[j];
421 1.1.2.1 peter }
422 1.1.2.1 peter }
423 1.1.2.1 peter }
424 1.1.2.1 peter }
425 1.1.2.1 peter
426 1.1.2.1 peter if (cl->concerned_rlc) {
427 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
428 1.1.2.1 peter scan1 = jif->jif_classes[i];
429 1.1.2.1 peter class_exists1 = (scan1 != NULL);
430 1.1.2.1 peter if (class_exists1) {
431 1.1.2.1 peter tmp[i] = 1;
432 1.1.2.1 peter for (j = 0; j <= i-1; j++) {
433 1.1.2.1 peter scan2 = jif->jif_classes[j];
434 1.1.2.1 peter class_exists2 = (scan2 != NULL);
435 1.1.2.1 peter if (class_exists2
436 1.1.2.1 peter && scan2->concerned_rlc)
437 1.1.2.1 peter tmp[i] *= scan2->cl_rlc;
438 1.1.2.1 peter }
439 1.1.2.1 peter } else
440 1.1.2.1 peter tmp[i] = 0;
441 1.1.2.1 peter }
442 1.1.2.1 peter
443 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
444 1.1.2.1 peter scan1 = jif->jif_classes[i];
445 1.1.2.1 peter class_exists1 = (scan1 != NULL);
446 1.1.2.1 peter if (class_exists1) {
447 1.1.2.1 peter scan1->loss_prod_others = 1;
448 1.1.2.1 peter for (j = 0; j <= jif->jif_maxpri; j++) {
449 1.1.2.1 peter scan2 = jif->jif_classes[j];
450 1.1.2.1 peter class_exists2 = (scan2 != NULL);
451 1.1.2.1 peter if (class_exists2 && j != i
452 1.1.2.1 peter && scan2->concerned_rlc)
453 1.1.2.1 peter scan1->loss_prod_others *= tmp[j];
454 1.1.2.1 peter }
455 1.1.2.1 peter }
456 1.1.2.1 peter }
457 1.1.2.1 peter }
458 1.1.2.1 peter
459 1.1.2.1 peter now = read_machclk();
460 1.1.2.1 peter cl->idletime = now;
461 1.1.2.1 peter return (cl);
462 1.1.2.1 peter
463 1.1.2.1 peter err_ret:
464 1.1.2.1 peter if (cl->cl_q != NULL)
465 1.1.2.1 peter FREE(cl->cl_q, M_DEVBUF);
466 1.1.2.1 peter if (cl->arv_tm != NULL)
467 1.1.2.1 peter FREE(cl->arv_tm, M_DEVBUF);
468 1.1.2.1 peter
469 1.1.2.1 peter FREE(cl, M_DEVBUF);
470 1.1.2.1 peter return (NULL);
471 1.1.2.1 peter }
472 1.1.2.1 peter
473 1.1.2.1 peter static int
474 1.1.2.1 peter jobs_class_destroy(cl)
475 1.1.2.1 peter struct jobs_class *cl;
476 1.1.2.1 peter {
477 1.1.2.1 peter struct jobs_if *jif;
478 1.1.2.1 peter int s, pri;
479 1.1.2.1 peter
480 1.1.2.1 peter s = splnet();
481 1.1.2.1 peter
482 1.1.2.1 peter /* delete filters referencing to this class */
483 1.1.2.1 peter acc_discard_filters(&cl->cl_jif->jif_classifier, cl, 0);
484 1.1.2.1 peter
485 1.1.2.1 peter if (!qempty(cl->cl_q))
486 1.1.2.1 peter jobs_purgeq(cl);
487 1.1.2.1 peter
488 1.1.2.1 peter jif = cl->cl_jif;
489 1.1.2.1 peter jif->jif_classes[cl->cl_pri] = NULL;
490 1.1.2.1 peter if (jif->jif_maxpri == cl->cl_pri) {
491 1.1.2.1 peter for (pri = cl->cl_pri; pri >= 0; pri--)
492 1.1.2.1 peter if (jif->jif_classes[pri] != NULL) {
493 1.1.2.1 peter jif->jif_maxpri = pri;
494 1.1.2.1 peter break;
495 1.1.2.1 peter }
496 1.1.2.1 peter if (pri < 0)
497 1.1.2.1 peter jif->jif_maxpri = -1;
498 1.1.2.1 peter }
499 1.1.2.1 peter splx(s);
500 1.1.2.1 peter
501 1.1.2.1 peter tslist_destroy(cl);
502 1.1.2.1 peter FREE(cl->cl_q, M_DEVBUF);
503 1.1.2.1 peter FREE(cl, M_DEVBUF);
504 1.1.2.1 peter return (0);
505 1.1.2.1 peter }
506 1.1.2.1 peter
507 1.1.2.1 peter /*
508 1.1.2.1 peter * jobs_enqueue is an enqueue function to be registered to
509 1.1.2.1 peter * (*altq_enqueue) in struct ifaltq.
510 1.1.2.1 peter */
511 1.1.2.1 peter static int
512 1.1.2.1 peter jobs_enqueue(ifq, m, pktattr)
513 1.1.2.1 peter struct ifaltq *ifq;
514 1.1.2.1 peter struct mbuf *m;
515 1.1.2.1 peter struct altq_pktattr *pktattr;
516 1.1.2.1 peter {
517 1.1.2.1 peter struct jobs_if *jif = (struct jobs_if *)ifq->altq_disc;
518 1.1.2.1 peter struct jobs_class *cl, *scan;
519 1.1.2.1 peter int len;
520 1.1.2.1 peter int return_flag;
521 1.1.2.1 peter int pri;
522 1.1.2.1 peter u_int64_t now;
523 1.1.2.1 peter u_int64_t old_arv;
524 1.1.2.1 peter int64_t* delta_rate;
525 1.1.2.1 peter u_int64_t tstamp1, tstamp2, cycles; /* used for benchmarking only */
526 1.1.2.1 peter
527 1.1.2.1 peter jif->total_enqueued++;
528 1.1.2.1 peter now = read_machclk();
529 1.1.2.1 peter tstamp1 = now;
530 1.1.2.1 peter
531 1.1.2.1 peter return_flag = 0;
532 1.1.2.1 peter
533 1.1.2.1 peter /* proceed with packet enqueuing */
534 1.1.2.1 peter
535 1.1.2.1 peter if (IFQ_IS_EMPTY(ifq)) {
536 1.1.2.1 peter for (pri=0; pri <= jif->jif_maxpri; pri++) {
537 1.1.2.1 peter scan = jif->jif_classes[pri];
538 1.1.2.1 peter if (scan != NULL) {
539 1.1.2.1 peter /*
540 1.1.2.1 peter * reset all quantities, except:
541 1.1.2.1 peter * average delay, number of violations
542 1.1.2.1 peter */
543 1.1.2.1 peter PKTCNTR_RESET(&scan->cl_rin);
544 1.1.2.1 peter PKTCNTR_RESET(&scan->cl_rout);
545 1.1.2.1 peter PKTCNTR_RESET(&scan->cl_rout_th);
546 1.1.2.1 peter PKTCNTR_RESET(&scan->cl_arrival);
547 1.1.2.1 peter PKTCNTR_RESET(&scan->cl_dropcnt);
548 1.1.2.1 peter scan->cl_lastdel = 0;
549 1.1.2.1 peter scan->current_loss = 0;
550 1.1.2.1 peter scan->service_rate = 0;
551 1.1.2.1 peter scan->idletime = now;
552 1.1.2.1 peter scan->cl_last_rate_update = now;
553 1.1.2.1 peter }
554 1.1.2.1 peter }
555 1.1.2.1 peter }
556 1.1.2.1 peter
557 1.1.2.1 peter /* grab class set by classifier */
558 1.1.2.1 peter if (pktattr == NULL || (cl = pktattr->pattr_class) == NULL)
559 1.1.2.1 peter cl = jif->jif_default;
560 1.1.2.1 peter
561 1.1.2.1 peter len = m_pktlen(m);
562 1.1.2.1 peter old_arv = cl->cl_arrival.bytes;
563 1.1.2.1 peter PKTCNTR_ADD(&cl->cl_arrival, (int)len);
564 1.1.2.1 peter PKTCNTR_ADD(&cl->cl_rin, (int)len);
565 1.1.2.1 peter PKTCNTR_ADD(&cl->st_arrival, (int)len);
566 1.1.2.1 peter PKTCNTR_ADD(&cl->st_rin, (int)len);
567 1.1.2.1 peter
568 1.1.2.1 peter if (cl->cl_arrival.bytes < old_arv) {
569 1.1.2.1 peter /* deals w/ overflow */
570 1.1.2.1 peter for (pri=0; pri <= jif->jif_maxpri; pri++) {
571 1.1.2.1 peter scan = jif->jif_classes[pri];
572 1.1.2.1 peter if (scan != NULL) {
573 1.1.2.1 peter /*
574 1.1.2.1 peter * reset all quantities, except:
575 1.1.2.1 peter * average delay, number of violations
576 1.1.2.1 peter */
577 1.1.2.1 peter PKTCNTR_RESET(&scan->cl_rin);
578 1.1.2.1 peter PKTCNTR_RESET(&scan->cl_rout);
579 1.1.2.1 peter PKTCNTR_RESET(&scan->cl_rout_th);
580 1.1.2.1 peter PKTCNTR_RESET(&scan->cl_arrival);
581 1.1.2.1 peter PKTCNTR_RESET(&scan->cl_dropcnt);
582 1.1.2.1 peter scan->current_loss = 0;
583 1.1.2.1 peter scan->service_rate = 0;
584 1.1.2.1 peter scan->idletime = now;
585 1.1.2.1 peter scan->cl_last_rate_update = now;
586 1.1.2.1 peter }
587 1.1.2.1 peter }
588 1.1.2.1 peter PKTCNTR_ADD(&cl->cl_arrival, (int)len);
589 1.1.2.1 peter PKTCNTR_ADD(&cl->cl_rin, (int)len);
590 1.1.2.1 peter }
591 1.1.2.1 peter
592 1.1.2.1 peter if (cl->cl_arrival.bytes > cl->cl_rin.bytes)
593 1.1.2.1 peter cl->current_loss =
594 1.1.2.1 peter ((cl->cl_arrival.bytes - cl->cl_rin.bytes) << SCALE_LOSS)
595 1.1.2.1 peter / cl->cl_arrival.bytes;
596 1.1.2.1 peter else
597 1.1.2.1 peter cl->current_loss = 0;
598 1.1.2.1 peter
599 1.1.2.1 peter /* for MDRR: update theoretical value of the output curve */
600 1.1.2.1 peter
601 1.1.2.1 peter for (pri=0; pri <= jif->jif_maxpri; pri++) {
602 1.1.2.1 peter scan = jif->jif_classes[pri];
603 1.1.2.1 peter if (scan != NULL) {
604 1.1.2.1 peter if (scan->cl_last_rate_update == scan->idletime
605 1.1.2.1 peter || scan->cl_last_rate_update == 0)
606 1.1.2.1 peter scan->cl_last_rate_update = now; /* initial case */
607 1.1.2.1 peter else
608 1.1.2.1 peter scan->cl_rout_th.bytes +=
609 1.1.2.1 peter delay_diff(now, scan->cl_last_rate_update)
610 1.1.2.1 peter * scan->service_rate;
611 1.1.2.1 peter
612 1.1.2.1 peter /*
613 1.1.2.1 peter * we don't really care about packets here
614 1.1.2.1 peter * WARNING: rout_th is SCALED
615 1.1.2.1 peter * (b/c of the service rate)
616 1.1.2.1 peter * for precision, as opposed to rout.
617 1.1.2.1 peter */
618 1.1.2.1 peter
619 1.1.2.1 peter scan->cl_last_rate_update = now;
620 1.1.2.1 peter }
621 1.1.2.1 peter }
622 1.1.2.1 peter
623 1.1.2.1 peter if (jobs_addq(cl, m, jif) != 0)
624 1.1.2.1 peter return_flag = ENOBUFS; /* signals there's a buffer overflow */
625 1.1.2.1 peter else
626 1.1.2.1 peter IFQ_INC_LEN(ifq);
627 1.1.2.1 peter
628 1.1.2.1 peter /* successfully queued. */
629 1.1.2.1 peter
630 1.1.2.1 peter enforce_wc(jif);
631 1.1.2.1 peter
632 1.1.2.1 peter if (!min_rates_adc(jif)) {
633 1.1.2.1 peter delta_rate = assign_rate_drops_adc(jif);
634 1.1.2.1 peter if (delta_rate != NULL) {
635 1.1.2.1 peter for (pri = 0; pri <= jif->jif_maxpri; pri++)
636 1.1.2.1 peter if ((cl = jif->jif_classes[pri]) != NULL &&
637 1.1.2.1 peter !qempty(cl->cl_q))
638 1.1.2.1 peter cl->service_rate += delta_rate[pri];
639 1.1.2.1 peter FREE(delta_rate, M_DEVBUF);
640 1.1.2.1 peter }
641 1.1.2.1 peter }
642 1.1.2.1 peter
643 1.1.2.1 peter delta_rate = adjust_rates_rdc(jif);
644 1.1.2.1 peter
645 1.1.2.1 peter if (delta_rate != NULL) {
646 1.1.2.1 peter for (pri = 0; pri <= jif->jif_maxpri; pri++)
647 1.1.2.1 peter if ((cl = jif->jif_classes[pri]) != NULL &&
648 1.1.2.1 peter !qempty(cl->cl_q))
649 1.1.2.1 peter cl->service_rate += delta_rate[pri];
650 1.1.2.1 peter FREE(delta_rate, M_DEVBUF);
651 1.1.2.1 peter }
652 1.1.2.1 peter
653 1.1.2.1 peter tstamp2 = read_machclk();
654 1.1.2.1 peter cycles = delay_diff(tstamp2, tstamp1);
655 1.1.2.1 peter if (cycles > jif->wc_cycles_enqueue)
656 1.1.2.1 peter jif->wc_cycles_enqueue=cycles;
657 1.1.2.1 peter if (cycles < jif->bc_cycles_enqueue)
658 1.1.2.1 peter jif->bc_cycles_enqueue=cycles;
659 1.1.2.1 peter
660 1.1.2.1 peter jif->avg_cycles_enqueue += cycles;
661 1.1.2.1 peter jif->avg_cycles2_enqueue += cycles * cycles;
662 1.1.2.1 peter
663 1.1.2.1 peter return (return_flag);
664 1.1.2.1 peter }
665 1.1.2.1 peter
666 1.1.2.1 peter /*
667 1.1.2.1 peter * jobs_dequeue is a dequeue function to be registered to
668 1.1.2.1 peter * (*altq_dequeue) in struct ifaltq.
669 1.1.2.1 peter *
670 1.1.2.1 peter * note: ALTDQ_POLL returns the next packet without removing the packet
671 1.1.2.1 peter * from the queue. ALTDQ_REMOVE is a normal dequeue operation.
672 1.1.2.1 peter * ALTDQ_REMOVE must return the same packet if called immediately
673 1.1.2.1 peter * after ALTDQ_POLL.
674 1.1.2.1 peter */
675 1.1.2.1 peter
676 1.1.2.1 peter static struct mbuf *
677 1.1.2.1 peter jobs_dequeue(ifq, op)
678 1.1.2.1 peter struct ifaltq *ifq;
679 1.1.2.1 peter int op;
680 1.1.2.1 peter {
681 1.1.2.1 peter struct jobs_if *jif = (struct jobs_if *)ifq->altq_disc;
682 1.1.2.1 peter struct jobs_class *cl;
683 1.1.2.1 peter struct mbuf *m;
684 1.1.2.1 peter int pri;
685 1.1.2.1 peter int svc_class;
686 1.1.2.1 peter int64_t max_error;
687 1.1.2.1 peter int64_t error;
688 1.1.2.1 peter u_int64_t now;
689 1.1.2.1 peter u_int64_t tstamp1, tstamp2, cycles;
690 1.1.2.1 peter
691 1.1.2.1 peter jif->total_dequeued++;
692 1.1.2.1 peter
693 1.1.2.1 peter now = read_machclk();
694 1.1.2.1 peter tstamp1 = now;
695 1.1.2.1 peter
696 1.1.2.1 peter if (IFQ_IS_EMPTY(ifq)) {
697 1.1.2.1 peter /* no packet in the queue */
698 1.1.2.1 peter for (pri=0; pri <= jif->jif_maxpri; pri++) {
699 1.1.2.1 peter cl = jif->jif_classes[pri];
700 1.1.2.1 peter if (cl != NULL)
701 1.1.2.1 peter cl->idletime = now;
702 1.1.2.1 peter }
703 1.1.2.1 peter
704 1.1.2.1 peter tstamp2 = read_machclk();
705 1.1.2.1 peter cycles = delay_diff(tstamp2, tstamp1);
706 1.1.2.1 peter if (cycles > jif->wc_cycles_dequeue)
707 1.1.2.1 peter jif->wc_cycles_dequeue = cycles;
708 1.1.2.1 peter if (cycles < jif->bc_cycles_dequeue)
709 1.1.2.1 peter jif->bc_cycles_dequeue = cycles;
710 1.1.2.1 peter
711 1.1.2.1 peter jif->avg_cycles_dequeue += cycles;
712 1.1.2.1 peter jif->avg_cycles2_dequeue += cycles * cycles;
713 1.1.2.1 peter
714 1.1.2.1 peter return (NULL);
715 1.1.2.1 peter }
716 1.1.2.1 peter
717 1.1.2.1 peter /*
718 1.1.2.1 peter * select the class whose actual tranmissions are the furthest
719 1.1.2.1 peter * from the promised transmissions
720 1.1.2.1 peter */
721 1.1.2.1 peter
722 1.1.2.1 peter max_error = -1;
723 1.1.2.1 peter svc_class = -1;
724 1.1.2.1 peter
725 1.1.2.1 peter for (pri=0; pri <= jif->jif_maxpri; pri++) {
726 1.1.2.1 peter if (((cl = jif->jif_classes[pri]) != NULL)
727 1.1.2.1 peter && !qempty(cl->cl_q)) {
728 1.1.2.1 peter error = (int64_t)cl->cl_rout_th.bytes
729 1.1.2.1 peter -(int64_t)scale_rate(cl->cl_rout.bytes);
730 1.1.2.1 peter if (max_error == -1) {
731 1.1.2.1 peter max_error = error;
732 1.1.2.1 peter svc_class = pri;
733 1.1.2.1 peter } else if (error > max_error) {
734 1.1.2.1 peter max_error = error;
735 1.1.2.1 peter svc_class = pri;
736 1.1.2.1 peter }
737 1.1.2.1 peter }
738 1.1.2.1 peter }
739 1.1.2.1 peter
740 1.1.2.1 peter if (svc_class != -1)
741 1.1.2.1 peter cl = jif->jif_classes[svc_class];
742 1.1.2.1 peter else
743 1.1.2.1 peter cl = NULL;
744 1.1.2.1 peter
745 1.1.2.1 peter if (op == ALTDQ_POLL) {
746 1.1.2.1 peter tstamp2 = read_machclk();
747 1.1.2.1 peter cycles = delay_diff(tstamp2, tstamp1);
748 1.1.2.1 peter if (cycles > jif->wc_cycles_dequeue)
749 1.1.2.1 peter jif->wc_cycles_dequeue = cycles;
750 1.1.2.1 peter if (cycles < jif->bc_cycles_dequeue)
751 1.1.2.1 peter jif->bc_cycles_dequeue = cycles;
752 1.1.2.1 peter
753 1.1.2.1 peter jif->avg_cycles_dequeue += cycles;
754 1.1.2.1 peter jif->avg_cycles2_dequeue += cycles * cycles;
755 1.1.2.1 peter
756 1.1.2.1 peter return (jobs_pollq(cl));
757 1.1.2.1 peter }
758 1.1.2.1 peter
759 1.1.2.1 peter if (cl != NULL)
760 1.1.2.1 peter m = jobs_getq(cl);
761 1.1.2.1 peter else
762 1.1.2.1 peter m = NULL;
763 1.1.2.1 peter
764 1.1.2.1 peter if (m != NULL) {
765 1.1.2.1 peter IFQ_DEC_LEN(ifq);
766 1.1.2.1 peter if (qempty(cl->cl_q))
767 1.1.2.1 peter cl->cl_period++;
768 1.1.2.1 peter
769 1.1.2.1 peter cl->cl_lastdel = (u_int64_t)delay_diff(now,
770 1.1.2.1 peter tslist_first(cl->arv_tm)->timestamp);
771 1.1.2.1 peter if (cl->concerned_adc
772 1.1.2.1 peter && (int64_t)cl->cl_lastdel > cl->cl_adc)
773 1.1.2.1 peter cl->adc_violations++;
774 1.1.2.1 peter cl->cl_avgdel += ticks_to_secs(GRANULARITY*cl->cl_lastdel);
775 1.1.2.1 peter
776 1.1.2.1 peter PKTCNTR_ADD(&cl->cl_rout, m_pktlen(m));
777 1.1.2.1 peter PKTCNTR_ADD(&cl->st_rout, m_pktlen(m));
778 1.1.2.1 peter }
779 1.1.2.1 peter if (cl != NULL)
780 1.1.2.1 peter tslist_dequeue(cl); /* dequeue the timestamp */
781 1.1.2.1 peter
782 1.1.2.1 peter tstamp2 = read_machclk();
783 1.1.2.1 peter cycles = delay_diff(tstamp2, tstamp1);
784 1.1.2.1 peter if (cycles > jif->wc_cycles_dequeue)
785 1.1.2.1 peter jif->wc_cycles_dequeue = cycles;
786 1.1.2.1 peter if (cycles < jif->bc_cycles_dequeue)
787 1.1.2.1 peter jif->bc_cycles_dequeue = cycles;
788 1.1.2.1 peter
789 1.1.2.1 peter jif->avg_cycles_dequeue += cycles;
790 1.1.2.1 peter jif->avg_cycles2_dequeue += cycles * cycles;
791 1.1.2.1 peter
792 1.1.2.1 peter return (m);
793 1.1.2.1 peter }
794 1.1.2.1 peter
795 1.1.2.1 peter static int
796 1.1.2.1 peter jobs_addq(cl, m, jif)
797 1.1.2.1 peter struct jobs_class *cl;
798 1.1.2.1 peter struct mbuf *m;
799 1.1.2.1 peter struct jobs_if *jif;
800 1.1.2.1 peter {
801 1.1.2.1 peter int victim;
802 1.1.2.1 peter u_int64_t len;
803 1.1.2.1 peter u_int64_t now;
804 1.1.2.1 peter struct jobs_class* victim_class;
805 1.1.2.1 peter
806 1.1.2.1 peter victim = -1;
807 1.1.2.1 peter victim_class = NULL;
808 1.1.2.1 peter len = 0;
809 1.1.2.1 peter
810 1.1.2.1 peter now = read_machclk();
811 1.1.2.1 peter
812 1.1.2.1 peter if (jif->jif_separate && qlen(cl->cl_q) >= jif->jif_qlimit) {
813 1.1.2.1 peter /*
814 1.1.2.1 peter * separate buffers: no guarantees on packet drops
815 1.1.2.1 peter * can be offered
816 1.1.2.1 peter * thus we drop the incoming packet
817 1.1.2.1 peter */
818 1.1.2.1 peter len = (u_int64_t)m_pktlen(m);
819 1.1.2.1 peter PKTCNTR_ADD(&cl->cl_dropcnt, (int)len);
820 1.1.2.1 peter PKTCNTR_SUB(&cl->cl_rin, (int)len);
821 1.1.2.1 peter PKTCNTR_ADD(&cl->st_dropcnt, (int)len);
822 1.1.2.1 peter PKTCNTR_SUB(&cl->st_rin, (int)len);
823 1.1.2.1 peter cl->current_loss += (len << SCALE_LOSS)
824 1.1.2.1 peter /cl->cl_arrival.bytes;
825 1.1.2.1 peter m_freem(m);
826 1.1.2.1 peter return (-1);
827 1.1.2.1 peter
828 1.1.2.1 peter } else if (!jif->jif_separate
829 1.1.2.1 peter && jif->jif_ifq->ifq_len >= jif->jif_qlimit) {
830 1.1.2.1 peter /* shared buffer: supports guarantees on losses */
831 1.1.2.1 peter if (!cl->concerned_rlc) {
832 1.1.2.1 peter if (!cl->concerned_alc) {
833 1.1.2.1 peter /*
834 1.1.2.1 peter * no ALC, no RLC on this class:
835 1.1.2.1 peter * drop the incoming packet
836 1.1.2.1 peter */
837 1.1.2.1 peter len = (u_int64_t)m_pktlen(m);
838 1.1.2.1 peter PKTCNTR_ADD(&cl->cl_dropcnt, (int)len);
839 1.1.2.1 peter PKTCNTR_SUB(&cl->cl_rin, (int)len);
840 1.1.2.1 peter PKTCNTR_ADD(&cl->st_dropcnt, (int)len);
841 1.1.2.1 peter PKTCNTR_SUB(&cl->st_rin, (int)len);
842 1.1.2.1 peter cl->current_loss += (len << SCALE_LOSS)/cl->cl_arrival.bytes;
843 1.1.2.1 peter m_freem(m);
844 1.1.2.1 peter return (-1);
845 1.1.2.1 peter } else {
846 1.1.2.1 peter /*
847 1.1.2.1 peter * no RLC, but an ALC:
848 1.1.2.1 peter * drop the incoming packet if possible
849 1.1.2.1 peter */
850 1.1.2.1 peter len = (u_int64_t)m_pktlen(m);
851 1.1.2.1 peter if (cl->current_loss + (len << SCALE_LOSS)
852 1.1.2.1 peter / cl->cl_arrival.bytes <= cl->cl_alc) {
853 1.1.2.1 peter PKTCNTR_ADD(&cl->cl_dropcnt, (int)len);
854 1.1.2.1 peter PKTCNTR_SUB(&cl->cl_rin, (int)len);
855 1.1.2.1 peter PKTCNTR_ADD(&cl->st_dropcnt, (int)len);
856 1.1.2.1 peter PKTCNTR_SUB(&cl->st_rin, (int)len);
857 1.1.2.1 peter cl->current_loss += (len << SCALE_LOSS)/cl->cl_arrival.bytes;
858 1.1.2.1 peter m_freem(m);
859 1.1.2.1 peter return (-1);
860 1.1.2.1 peter } else {
861 1.1.2.1 peter /*
862 1.1.2.1 peter * the ALC would be violated:
863 1.1.2.1 peter * pick another class
864 1.1.2.1 peter */
865 1.1.2.1 peter _addq(cl->cl_q, m);
866 1.1.2.1 peter tslist_enqueue(cl, now);
867 1.1.2.1 peter
868 1.1.2.1 peter victim = pick_dropped_rlc(jif);
869 1.1.2.1 peter
870 1.1.2.1 peter if (victim == -1) {
871 1.1.2.1 peter /*
872 1.1.2.1 peter * something went wrong
873 1.1.2.1 peter * let us discard
874 1.1.2.1 peter * the incoming packet,
875 1.1.2.1 peter * regardless of what
876 1.1.2.1 peter * may happen...
877 1.1.2.1 peter */
878 1.1.2.1 peter victim_class = cl;
879 1.1.2.1 peter } else
880 1.1.2.1 peter victim_class = jif->jif_classes[victim];
881 1.1.2.1 peter
882 1.1.2.1 peter if (victim_class != NULL) {
883 1.1.2.1 peter /*
884 1.1.2.1 peter * test for safety
885 1.1.2.1 peter * purposes...
886 1.1.2.1 peter * it must be true
887 1.1.2.1 peter */
888 1.1.2.1 peter m = _getq_tail(victim_class->cl_q);
889 1.1.2.1 peter len = (u_int64_t)m_pktlen(m);
890 1.1.2.1 peter PKTCNTR_ADD(&victim_class->cl_dropcnt, (int)len);
891 1.1.2.1 peter PKTCNTR_SUB(&victim_class->cl_rin, (int)len);
892 1.1.2.1 peter PKTCNTR_ADD(&victim_class->st_dropcnt, (int)len);
893 1.1.2.1 peter PKTCNTR_SUB(&victim_class->st_rin, (int)len);
894 1.1.2.1 peter victim_class->current_loss += (len << SCALE_LOSS)/victim_class->cl_arrival.bytes;
895 1.1.2.1 peter m_freem(m); /* the packet is trashed here */
896 1.1.2.1 peter tslist_drop(victim_class); /* and its timestamp as well */
897 1.1.2.1 peter }
898 1.1.2.1 peter return (-1);
899 1.1.2.1 peter }
900 1.1.2.1 peter }
901 1.1.2.1 peter } else {
902 1.1.2.1 peter /*
903 1.1.2.1 peter * RLC on that class:
904 1.1.2.1 peter * pick class according to RLCs
905 1.1.2.1 peter */
906 1.1.2.1 peter _addq(cl->cl_q, m);
907 1.1.2.1 peter tslist_enqueue(cl, now);
908 1.1.2.1 peter
909 1.1.2.1 peter victim = pick_dropped_rlc(jif);
910 1.1.2.1 peter if (victim == -1) {
911 1.1.2.1 peter /*
912 1.1.2.1 peter * something went wrong
913 1.1.2.1 peter * let us discard the incoming packet,
914 1.1.2.1 peter * regardless of what may happen...
915 1.1.2.1 peter */
916 1.1.2.1 peter victim_class = cl;
917 1.1.2.1 peter } else
918 1.1.2.1 peter victim_class = jif->jif_classes[victim];
919 1.1.2.1 peter
920 1.1.2.1 peter if (victim_class != NULL) {
921 1.1.2.1 peter /*
922 1.1.2.1 peter * test for safety purposes...
923 1.1.2.1 peter * it must be true
924 1.1.2.1 peter */
925 1.1.2.1 peter m = _getq_tail(victim_class->cl_q);
926 1.1.2.1 peter len = (u_int64_t)m_pktlen(m);
927 1.1.2.1 peter PKTCNTR_ADD(&victim_class->cl_dropcnt, (int)len);
928 1.1.2.1 peter PKTCNTR_SUB(&victim_class->cl_rin, (int)len);
929 1.1.2.1 peter PKTCNTR_ADD(&victim_class->st_dropcnt, (int)len);
930 1.1.2.1 peter PKTCNTR_SUB(&victim_class->st_rin, (int)len);
931 1.1.2.1 peter victim_class->current_loss += (len << SCALE_LOSS)/victim_class->cl_arrival.bytes;
932 1.1.2.1 peter m_freem(m); /* the packet is trashed here */
933 1.1.2.1 peter tslist_drop(victim_class); /* and its timestamp as well */
934 1.1.2.1 peter }
935 1.1.2.1 peter return (-1);
936 1.1.2.1 peter }
937 1.1.2.1 peter }
938 1.1.2.1 peter /* else: no drop */
939 1.1.2.1 peter
940 1.1.2.1 peter _addq(cl->cl_q, m);
941 1.1.2.1 peter tslist_enqueue(cl, now);
942 1.1.2.1 peter
943 1.1.2.1 peter return (0);
944 1.1.2.1 peter }
945 1.1.2.1 peter
946 1.1.2.1 peter static struct mbuf *
947 1.1.2.1 peter jobs_getq(cl)
948 1.1.2.1 peter struct jobs_class *cl;
949 1.1.2.1 peter {
950 1.1.2.1 peter return _getq(cl->cl_q);
951 1.1.2.1 peter }
952 1.1.2.1 peter
953 1.1.2.1 peter static struct mbuf *
954 1.1.2.1 peter jobs_pollq(cl)
955 1.1.2.1 peter struct jobs_class *cl;
956 1.1.2.1 peter {
957 1.1.2.1 peter return qhead(cl->cl_q);
958 1.1.2.1 peter }
959 1.1.2.1 peter
960 1.1.2.1 peter static void
961 1.1.2.1 peter jobs_purgeq(cl)
962 1.1.2.1 peter struct jobs_class *cl;
963 1.1.2.1 peter {
964 1.1.2.1 peter struct mbuf *m;
965 1.1.2.1 peter
966 1.1.2.1 peter if (qempty(cl->cl_q))
967 1.1.2.1 peter return;
968 1.1.2.1 peter
969 1.1.2.1 peter while ((m = _getq(cl->cl_q)) != NULL) {
970 1.1.2.1 peter PKTCNTR_ADD(&cl->cl_dropcnt, m_pktlen(m));
971 1.1.2.1 peter PKTCNTR_ADD(&cl->st_dropcnt, m_pktlen(m));
972 1.1.2.1 peter m_freem(m);
973 1.1.2.1 peter tslist_drop(cl);
974 1.1.2.1 peter }
975 1.1.2.1 peter ASSERT(qlen(cl->cl_q) == 0);
976 1.1.2.1 peter }
977 1.1.2.1 peter
978 1.1.2.1 peter /*
979 1.1.2.1 peter * timestamp list support routines
980 1.1.2.1 peter *
981 1.1.2.1 peter * this implementation has been revamped and
982 1.1.2.1 peter * now uses a TAILQ structure.
983 1.1.2.1 peter * timestamp list holds class timestamps
984 1.1.2.1 peter * there is one timestamp list per class.
985 1.1.2.1 peter */
986 1.1.2.1 peter static TSLIST *
987 1.1.2.1 peter tslist_alloc()
988 1.1.2.1 peter {
989 1.1.2.1 peter TSLIST *list_init;
990 1.1.2.1 peter
991 1.1.2.1 peter MALLOC(list_init, TSLIST *, sizeof(TSLIST), M_DEVBUF, M_WAITOK);
992 1.1.2.1 peter TAILQ_INIT(list_init);
993 1.1.2.1 peter return (list_init);
994 1.1.2.1 peter }
995 1.1.2.1 peter
996 1.1.2.1 peter static void
997 1.1.2.1 peter tslist_destroy(cl)
998 1.1.2.1 peter struct jobs_class *cl;
999 1.1.2.1 peter {
1000 1.1.2.1 peter while (tslist_first(cl->arv_tm) != NULL)
1001 1.1.2.1 peter tslist_dequeue(cl);
1002 1.1.2.1 peter
1003 1.1.2.1 peter FREE(cl->arv_tm, M_DEVBUF);
1004 1.1.2.1 peter }
1005 1.1.2.1 peter
1006 1.1.2.1 peter static int
1007 1.1.2.1 peter tslist_enqueue(cl, arv)
1008 1.1.2.1 peter struct jobs_class *cl;
1009 1.1.2.1 peter u_int64_t arv;
1010 1.1.2.1 peter {
1011 1.1.2.1 peter TSENTRY *pushed;
1012 1.1.2.1 peter MALLOC(pushed, TSENTRY*, sizeof(TSENTRY), M_DEVBUF, M_WAITOK);
1013 1.1.2.1 peter if (pushed == NULL)
1014 1.1.2.1 peter return (0);
1015 1.1.2.1 peter
1016 1.1.2.1 peter pushed->timestamp = arv;
1017 1.1.2.1 peter TAILQ_INSERT_TAIL(cl->arv_tm, pushed, ts_list);
1018 1.1.2.1 peter return (1);
1019 1.1.2.1 peter }
1020 1.1.2.1 peter
1021 1.1.2.1 peter static void
1022 1.1.2.1 peter tslist_dequeue(cl)
1023 1.1.2.1 peter struct jobs_class *cl;
1024 1.1.2.1 peter {
1025 1.1.2.1 peter TSENTRY *popped;
1026 1.1.2.1 peter popped = tslist_first(cl->arv_tm);
1027 1.1.2.1 peter if (popped != NULL) {
1028 1.1.2.1 peter TAILQ_REMOVE(cl->arv_tm, popped, ts_list);
1029 1.1.2.1 peter FREE(popped, M_DEVBUF);
1030 1.1.2.1 peter }
1031 1.1.2.1 peter return;
1032 1.1.2.1 peter }
1033 1.1.2.1 peter
1034 1.1.2.1 peter static void
1035 1.1.2.1 peter tslist_drop(cl)
1036 1.1.2.1 peter struct jobs_class *cl;
1037 1.1.2.1 peter {
1038 1.1.2.1 peter TSENTRY *popped;
1039 1.1.2.1 peter popped = tslist_last(cl->arv_tm);
1040 1.1.2.1 peter if (popped != NULL) {
1041 1.1.2.1 peter TAILQ_REMOVE(cl->arv_tm, popped, ts_list);
1042 1.1.2.1 peter FREE(popped, M_DEVBUF);
1043 1.1.2.1 peter }
1044 1.1.2.1 peter return;
1045 1.1.2.1 peter }
1046 1.1.2.1 peter
1047 1.1.2.1 peter /*
1048 1.1.2.1 peter * rate allocation support routines
1049 1.1.2.1 peter */
1050 1.1.2.1 peter /*
1051 1.1.2.1 peter * enforce_wc: enforce that backlogged classes have non-zero
1052 1.1.2.1 peter * service rate, and that non-backlogged classes have zero
1053 1.1.2.1 peter * service rate.
1054 1.1.2.1 peter */
1055 1.1.2.1 peter
1056 1.1.2.1 peter static int
1057 1.1.2.1 peter enforce_wc(jif)
1058 1.1.2.1 peter struct jobs_if *jif;
1059 1.1.2.1 peter {
1060 1.1.2.1 peter struct jobs_class *cl;
1061 1.1.2.1 peter
1062 1.1.2.1 peter int64_t active_classes;
1063 1.1.2.1 peter int pri;
1064 1.1.2.1 peter int is_backlogged, class_exists, updated;
1065 1.1.2.1 peter
1066 1.1.2.1 peter updated = 0;
1067 1.1.2.1 peter active_classes = 0;
1068 1.1.2.1 peter
1069 1.1.2.1 peter for (pri = 0; pri <= jif->jif_maxpri; pri++) {
1070 1.1.2.1 peter cl = jif->jif_classes[pri];
1071 1.1.2.1 peter class_exists = (cl != NULL);
1072 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1073 1.1.2.1 peter
1074 1.1.2.1 peter if (is_backlogged)
1075 1.1.2.1 peter active_classes++;
1076 1.1.2.1 peter if ((is_backlogged && cl->service_rate <= 0)
1077 1.1.2.1 peter ||(class_exists
1078 1.1.2.1 peter && !is_backlogged && cl->service_rate > 0))
1079 1.1.2.1 peter updated = 1;
1080 1.1.2.1 peter }
1081 1.1.2.1 peter
1082 1.1.2.1 peter if (updated) {
1083 1.1.2.1 peter for (pri = 0; pri <= jif->jif_maxpri; pri++) {
1084 1.1.2.1 peter cl = jif->jif_classes[pri];
1085 1.1.2.1 peter class_exists = (cl != NULL);
1086 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1087 1.1.2.1 peter
1088 1.1.2.1 peter if (class_exists && !is_backlogged)
1089 1.1.2.1 peter cl->service_rate = 0;
1090 1.1.2.1 peter else if (is_backlogged)
1091 1.1.2.1 peter cl->service_rate = (int64_t)(bps_to_internal((u_int64_t)jif->jif_bandwidth)/active_classes);
1092 1.1.2.1 peter }
1093 1.1.2.1 peter }
1094 1.1.2.1 peter
1095 1.1.2.1 peter return (updated);
1096 1.1.2.1 peter }
1097 1.1.2.1 peter
1098 1.1.2.1 peter /*
1099 1.1.2.1 peter * adjust_rates_rdc: compute the service rates adjustments
1100 1.1.2.1 peter * needed to realize the desired proportional delay differentiation.
1101 1.1.2.1 peter * essentially, the rate adjustement delta_rate = prop_control*error,
1102 1.1.2.1 peter * where error is the difference between the measured "weighted"
1103 1.1.2.1 peter * delay and the mean of the weighted delays. see paper for more
1104 1.1.2.1 peter * information.
1105 1.1.2.1 peter * prop_control has slightly changed since the INFOCOM paper,
1106 1.1.2.1 peter * this condition seems to provide better results.
1107 1.1.2.1 peter */
1108 1.1.2.1 peter
1109 1.1.2.1 peter static int64_t *
1110 1.1.2.1 peter adjust_rates_rdc(jif)
1111 1.1.2.1 peter struct jobs_if *jif;
1112 1.1.2.1 peter {
1113 1.1.2.1 peter int64_t* result;
1114 1.1.2.1 peter int64_t credit, available, lower_bound, upper_bound;
1115 1.1.2.1 peter int64_t bk;
1116 1.1.2.1 peter int i, j;
1117 1.1.2.1 peter int rdc_classes, active_classes;
1118 1.1.2.1 peter int class_exists, is_backlogged;
1119 1.1.2.1 peter struct jobs_class *cl;
1120 1.1.2.1 peter int64_t* error;
1121 1.1.2.1 peter int64_t prop_control;
1122 1.1.2.1 peter u_int64_t max_prod;
1123 1.1.2.1 peter u_int64_t min_share;
1124 1.1.2.1 peter u_int64_t max_avg_pkt_size;
1125 1.1.2.1 peter
1126 1.1.2.1 peter /*
1127 1.1.2.1 peter * min_share is scaled
1128 1.1.2.1 peter * to avoid dealing with doubles
1129 1.1.2.1 peter */
1130 1.1.2.1 peter active_classes = 0;
1131 1.1.2.1 peter rdc_classes = 0;
1132 1.1.2.1 peter max_prod = 0;
1133 1.1.2.1 peter max_avg_pkt_size = 0;
1134 1.1.2.1 peter
1135 1.1.2.1 peter upper_bound = (int64_t)jif->jif_bandwidth;
1136 1.1.2.1 peter
1137 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1138 1.1.2.1 peter cl = jif->jif_classes[i];
1139 1.1.2.1 peter class_exists = (cl != NULL);
1140 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1141 1.1.2.1 peter if (is_backlogged) {
1142 1.1.2.1 peter active_classes++;
1143 1.1.2.1 peter if (cl->concerned_rdc)
1144 1.1.2.1 peter rdc_classes++;
1145 1.1.2.1 peter else
1146 1.1.2.1 peter upper_bound -=
1147 1.1.2.1 peter internal_to_bps(cl->service_rate);
1148 1.1.2.1 peter }
1149 1.1.2.1 peter }
1150 1.1.2.1 peter
1151 1.1.2.1 peter MALLOC(result, int64_t*, (jif->jif_maxpri+1)*sizeof(int64_t),
1152 1.1.2.1 peter M_DEVBUF, M_WAITOK);
1153 1.1.2.1 peter
1154 1.1.2.1 peter if (result == NULL)
1155 1.1.2.1 peter return NULL;
1156 1.1.2.1 peter
1157 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++)
1158 1.1.2.1 peter result[i] = 0;
1159 1.1.2.1 peter
1160 1.1.2.1 peter if (upper_bound <= 0 || rdc_classes == 0)
1161 1.1.2.1 peter return result;
1162 1.1.2.1 peter
1163 1.1.2.1 peter credit = 0;
1164 1.1.2.1 peter lower_bound = 0;
1165 1.1.2.1 peter min_share = ((u_int64_t)1 << SCALE_SHARE);
1166 1.1.2.1 peter bk = 0;
1167 1.1.2.1 peter
1168 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1169 1.1.2.1 peter cl = jif->jif_classes[i];
1170 1.1.2.1 peter class_exists = (cl != NULL);
1171 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1172 1.1.2.1 peter if (is_backlogged && cl->concerned_rdc)
1173 1.1.2.1 peter bk += cl->cl_rin.bytes;
1174 1.1.2.1 peter }
1175 1.1.2.1 peter
1176 1.1.2.1 peter if (bk == 0)
1177 1.1.2.1 peter return (result);
1178 1.1.2.1 peter
1179 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1180 1.1.2.1 peter cl = jif->jif_classes[i];
1181 1.1.2.1 peter class_exists = (cl != NULL);
1182 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1183 1.1.2.1 peter if (is_backlogged
1184 1.1.2.1 peter && (cl->cl_rin.bytes << SCALE_SHARE)/bk < min_share)
1185 1.1.2.1 peter min_share = (cl->cl_rin.bytes << SCALE_SHARE)/bk;
1186 1.1.2.1 peter if (is_backlogged && cl->concerned_rdc
1187 1.1.2.1 peter && cl->delay_prod_others > max_prod)
1188 1.1.2.1 peter max_prod = cl->delay_prod_others;
1189 1.1.2.1 peter
1190 1.1.2.1 peter if (is_backlogged && cl->concerned_rdc
1191 1.1.2.1 peter && cl->cl_rin.bytes > max_avg_pkt_size*cl->cl_rin.packets)
1192 1.1.2.1 peter max_avg_pkt_size = (u_int64_t)((u_int)cl->cl_rin.bytes/(u_int)cl->cl_rin.packets);
1193 1.1.2.1 peter }
1194 1.1.2.1 peter
1195 1.1.2.1 peter error = update_error(jif);
1196 1.1.2.1 peter if (!error)
1197 1.1.2.1 peter return (NULL);
1198 1.1.2.1 peter
1199 1.1.2.1 peter prop_control = (upper_bound*upper_bound*min_share)
1200 1.1.2.1 peter /(max_prod*(max_avg_pkt_size << 2));
1201 1.1.2.1 peter
1202 1.1.2.1 peter prop_control = bps_to_internal(ticks_to_secs(prop_control)); /* in BT-1 */
1203 1.1.2.1 peter
1204 1.1.2.1 peter credit = 0;
1205 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1206 1.1.2.1 peter cl = jif->jif_classes[i];
1207 1.1.2.1 peter class_exists = (cl != NULL);
1208 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1209 1.1.2.1 peter if (is_backlogged && cl->concerned_rdc) {
1210 1.1.2.1 peter result[i] = -prop_control*error[i]; /* in BT-1 */
1211 1.1.2.1 peter result[i] >>= (SCALE_SHARE);
1212 1.1.2.1 peter }
1213 1.1.2.1 peter }
1214 1.1.2.1 peter
1215 1.1.2.1 peter FREE(error, M_DEVBUF); /* we don't need these anymore */
1216 1.1.2.1 peter
1217 1.1.2.1 peter /* saturation */
1218 1.1.2.1 peter
1219 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1220 1.1.2.1 peter cl = jif->jif_classes[i];
1221 1.1.2.1 peter class_exists = (cl != NULL);
1222 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1223 1.1.2.1 peter
1224 1.1.2.1 peter if (is_backlogged && cl->concerned_rdc)
1225 1.1.2.1 peter lower_bound += cl->min_rate_adc;
1226 1.1.2.1 peter /*
1227 1.1.2.1 peter * note: if there's no ADC or ARC on cl,
1228 1.1.2.1 peter * this is equal to zero, which is fine
1229 1.1.2.1 peter */
1230 1.1.2.1 peter }
1231 1.1.2.1 peter
1232 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1233 1.1.2.1 peter cl = jif->jif_classes[i];
1234 1.1.2.1 peter class_exists = (cl != NULL);
1235 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1236 1.1.2.1 peter
1237 1.1.2.1 peter if (is_backlogged && cl->concerned_rdc
1238 1.1.2.1 peter && result[i] + cl->service_rate > upper_bound) {
1239 1.1.2.1 peter for (j = 0; j <= jif->jif_maxpri; j++) {
1240 1.1.2.1 peter cl = jif->jif_classes[j];
1241 1.1.2.1 peter class_exists = (cl != NULL);
1242 1.1.2.1 peter is_backlogged = (class_exists
1243 1.1.2.1 peter && !qempty(cl->cl_q));
1244 1.1.2.1 peter if (is_backlogged && cl->concerned_rdc) {
1245 1.1.2.1 peter if (j == i)
1246 1.1.2.1 peter result[j] = upper_bound
1247 1.1.2.1 peter -cl->service_rate
1248 1.1.2.1 peter + cl->min_rate_adc
1249 1.1.2.1 peter - lower_bound;
1250 1.1.2.1 peter else
1251 1.1.2.1 peter result[j] =
1252 1.1.2.1 peter -cl->service_rate
1253 1.1.2.1 peter +cl->min_rate_adc;
1254 1.1.2.1 peter }
1255 1.1.2.1 peter }
1256 1.1.2.1 peter return result;
1257 1.1.2.1 peter }
1258 1.1.2.1 peter
1259 1.1.2.1 peter cl = jif->jif_classes[i];
1260 1.1.2.1 peter /* do this again since it may have been modified */
1261 1.1.2.1 peter class_exists = (cl != NULL);
1262 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1263 1.1.2.1 peter
1264 1.1.2.1 peter if (is_backlogged && cl->concerned_rdc
1265 1.1.2.1 peter && result[i] + cl->service_rate < cl->min_rate_adc) {
1266 1.1.2.1 peter credit += cl->service_rate+result[i]
1267 1.1.2.1 peter -cl->min_rate_adc;
1268 1.1.2.1 peter /* "credit" is in fact a negative number */
1269 1.1.2.1 peter result[i] = -cl->service_rate+cl->min_rate_adc;
1270 1.1.2.1 peter }
1271 1.1.2.1 peter }
1272 1.1.2.1 peter
1273 1.1.2.1 peter for (i = jif->jif_maxpri; (i >= 0 && credit < 0); i--) {
1274 1.1.2.1 peter cl = jif->jif_classes[i];
1275 1.1.2.1 peter class_exists = (cl != NULL);
1276 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1277 1.1.2.1 peter
1278 1.1.2.1 peter if (is_backlogged && cl->concerned_rdc) {
1279 1.1.2.1 peter available = result[i]
1280 1.1.2.1 peter + cl->service_rate-cl->min_rate_adc;
1281 1.1.2.1 peter if (available >= -credit) {
1282 1.1.2.1 peter result[i] += credit;
1283 1.1.2.1 peter credit = 0;
1284 1.1.2.1 peter } else {
1285 1.1.2.1 peter result[i] -= available;
1286 1.1.2.1 peter credit += available;
1287 1.1.2.1 peter }
1288 1.1.2.1 peter }
1289 1.1.2.1 peter }
1290 1.1.2.1 peter return result;
1291 1.1.2.1 peter }
1292 1.1.2.1 peter
1293 1.1.2.1 peter /*
1294 1.1.2.1 peter * assign_rate_drops_adc: returns the adjustment needed to
1295 1.1.2.1 peter * the service rates to meet the absolute delay/rate constraints
1296 1.1.2.1 peter * (delay/throughput bounds) and drops traffic if need be.
1297 1.1.2.1 peter * see tech. report UVA/T.R. CS-2000-24/CS-2001-21 for more info.
1298 1.1.2.1 peter */
1299 1.1.2.1 peter
1300 1.1.2.1 peter static int64_t *
1301 1.1.2.1 peter assign_rate_drops_adc(jif)
1302 1.1.2.1 peter struct jobs_if* jif;
1303 1.1.2.1 peter {
1304 1.1.2.1 peter int64_t* result;
1305 1.1.2.1 peter int class_exists, is_backlogged;
1306 1.1.2.1 peter struct jobs_class *cl;
1307 1.1.2.1 peter
1308 1.1.2.1 peter int64_t *c, *n, *k;
1309 1.1.2.1 peter int64_t *available;
1310 1.1.2.1 peter
1311 1.1.2.1 peter int lowest, highest;
1312 1.1.2.1 peter int keep_going;
1313 1.1.2.1 peter int i;
1314 1.1.2.1 peter u_int64_t now, oldest_arv;
1315 1.1.2.1 peter int64_t remaining_time;
1316 1.1.2.1 peter struct mbuf* pkt;
1317 1.1.2.1 peter u_int64_t len;
1318 1.1.2.1 peter
1319 1.1.2.1 peter now = read_machclk();
1320 1.1.2.1 peter oldest_arv = now;
1321 1.1.2.1 peter
1322 1.1.2.1 peter MALLOC(result, int64_t*, (jif->jif_maxpri+1)*sizeof(int64_t), M_DEVBUF, M_WAITOK);
1323 1.1.2.1 peter if (result == NULL)
1324 1.1.2.1 peter return NULL;
1325 1.1.2.1 peter MALLOC(c, int64_t*, (jif->jif_maxpri+1)*sizeof(u_int64_t), M_DEVBUF, M_WAITOK);
1326 1.1.2.1 peter if (c == NULL)
1327 1.1.2.1 peter return NULL;
1328 1.1.2.1 peter MALLOC(n, int64_t*, (jif->jif_maxpri+1)*sizeof(u_int64_t), M_DEVBUF, M_WAITOK);
1329 1.1.2.1 peter if (n == NULL)
1330 1.1.2.1 peter return NULL;
1331 1.1.2.1 peter MALLOC(k, int64_t*, (jif->jif_maxpri+1)*sizeof(u_int64_t), M_DEVBUF, M_WAITOK);
1332 1.1.2.1 peter if (k == NULL)
1333 1.1.2.1 peter return NULL;
1334 1.1.2.1 peter MALLOC(available, int64_t*, (jif->jif_maxpri+1)*sizeof(int64_t), M_DEVBUF, M_WAITOK);
1335 1.1.2.1 peter if (available == NULL)
1336 1.1.2.1 peter return NULL;
1337 1.1.2.1 peter
1338 1.1.2.1 peter for (i = 0;i <= jif->jif_maxpri; i++)
1339 1.1.2.1 peter result[i] = 0;
1340 1.1.2.1 peter
1341 1.1.2.1 peter keep_going = 1;
1342 1.1.2.1 peter
1343 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1344 1.1.2.1 peter cl = jif->jif_classes[i];
1345 1.1.2.1 peter class_exists = (cl != NULL);
1346 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1347 1.1.2.1 peter
1348 1.1.2.1 peter if (is_backlogged) {
1349 1.1.2.1 peter if (cl->concerned_adc) {
1350 1.1.2.1 peter /*
1351 1.1.2.1 peter * get the arrival time of the oldest
1352 1.1.2.1 peter * class-i packet
1353 1.1.2.1 peter */
1354 1.1.2.1 peter if (tslist_first(cl->arv_tm) == NULL)
1355 1.1.2.1 peter oldest_arv = now; /* NOTREACHED */
1356 1.1.2.1 peter else
1357 1.1.2.1 peter oldest_arv = (tslist_first(cl->arv_tm))->timestamp;
1358 1.1.2.1 peter
1359 1.1.2.1 peter n[i] = cl->service_rate;
1360 1.1.2.1 peter k[i] = scale_rate((int64_t)(cl->cl_rin.bytes - cl->cl_rout.bytes));
1361 1.1.2.1 peter
1362 1.1.2.1 peter remaining_time = cl->cl_adc
1363 1.1.2.1 peter - (int64_t)delay_diff(now, oldest_arv);
1364 1.1.2.1 peter if (remaining_time > 0) {
1365 1.1.2.1 peter c[i] = remaining_time;
1366 1.1.2.1 peter /*
1367 1.1.2.1 peter * c is the remaining time before
1368 1.1.2.1 peter * the deadline is violated
1369 1.1.2.1 peter * (in ticks)
1370 1.1.2.1 peter */
1371 1.1.2.1 peter available[i] = n[i]-k[i]/c[i];
1372 1.1.2.1 peter } else {
1373 1.1.2.1 peter /*
1374 1.1.2.1 peter * deadline has passed...
1375 1.1.2.1 peter * we allocate the whole link
1376 1.1.2.1 peter * capacity to hopefully
1377 1.1.2.1 peter * solve the problem
1378 1.1.2.1 peter */
1379 1.1.2.1 peter c[i] = 0;
1380 1.1.2.1 peter available[i] = -((int64_t)bps_to_internal((u_int64_t)jif->jif_bandwidth));
1381 1.1.2.1 peter }
1382 1.1.2.1 peter if (cl->concerned_arc) {
1383 1.1.2.1 peter /*
1384 1.1.2.1 peter * there's an ARC in addition
1385 1.1.2.1 peter * to the ADC
1386 1.1.2.1 peter */
1387 1.1.2.1 peter if (n[i] - cl->cl_arc < available[i])
1388 1.1.2.1 peter available[i] = n[i]
1389 1.1.2.1 peter - cl->cl_arc;
1390 1.1.2.1 peter }
1391 1.1.2.1 peter } else if (cl->concerned_arc) {
1392 1.1.2.1 peter /*
1393 1.1.2.1 peter * backlogged, concerned by ARC
1394 1.1.2.1 peter * but not by ADC
1395 1.1.2.1 peter */
1396 1.1.2.1 peter n[i] = cl->service_rate;
1397 1.1.2.1 peter available[i] = n[i] - cl->cl_arc;
1398 1.1.2.1 peter } else {
1399 1.1.2.1 peter /*
1400 1.1.2.1 peter * backlogged but not concerned by ADC
1401 1.1.2.1 peter * or ARC -> can give everything
1402 1.1.2.1 peter */
1403 1.1.2.1 peter n[i] = cl->service_rate;
1404 1.1.2.1 peter available[i] = n[i];
1405 1.1.2.1 peter }
1406 1.1.2.1 peter } else {
1407 1.1.2.1 peter /* not backlogged */
1408 1.1.2.1 peter n[i] = 0;
1409 1.1.2.1 peter k[i] = 0;
1410 1.1.2.1 peter c[i] = 0;
1411 1.1.2.1 peter if (class_exists)
1412 1.1.2.1 peter available[i] = cl->service_rate;
1413 1.1.2.1 peter else
1414 1.1.2.1 peter available[i] = 0;
1415 1.1.2.1 peter }
1416 1.1.2.1 peter }
1417 1.1.2.1 peter
1418 1.1.2.1 peter /* step 1: adjust rates (greedy algorithm) */
1419 1.1.2.1 peter
1420 1.1.2.1 peter highest = 0;
1421 1.1.2.1 peter lowest = jif->jif_maxpri;
1422 1.1.2.1 peter
1423 1.1.2.1 peter while (highest < jif->jif_maxpri+1 && available[highest] >= 0)
1424 1.1.2.1 peter highest++; /* which is the highest class that needs more service? */
1425 1.1.2.1 peter while (lowest > 0 && available[lowest] <= 0)
1426 1.1.2.1 peter lowest--; /* which is the lowest class that needs less service? */
1427 1.1.2.1 peter
1428 1.1.2.1 peter while (highest != jif->jif_maxpri+1 && lowest != -1) {
1429 1.1.2.1 peter /* give the excess service from lowest to highest */
1430 1.1.2.1 peter if (available[lowest]+available[highest] > 0) {
1431 1.1.2.1 peter /*
1432 1.1.2.1 peter * still some "credit" left
1433 1.1.2.1 peter * give all that is needed by "highest"
1434 1.1.2.1 peter */
1435 1.1.2.1 peter n[lowest] += available[highest];
1436 1.1.2.1 peter n[highest] -= available[highest];
1437 1.1.2.1 peter available[lowest] += available[highest];
1438 1.1.2.1 peter available[highest] = 0;
1439 1.1.2.1 peter
1440 1.1.2.1 peter while (highest < jif->jif_maxpri+1
1441 1.1.2.1 peter && available[highest] >= 0)
1442 1.1.2.1 peter highest++; /* which is the highest class that needs more service now? */
1443 1.1.2.1 peter
1444 1.1.2.1 peter } else if (available[lowest]+available[highest] == 0) {
1445 1.1.2.1 peter /* no more credit left but it's fine */
1446 1.1.2.1 peter n[lowest] += available[highest];
1447 1.1.2.1 peter n[highest] -= available[highest];
1448 1.1.2.1 peter available[highest] = 0;
1449 1.1.2.1 peter available[lowest] = 0;
1450 1.1.2.1 peter
1451 1.1.2.1 peter while (highest < jif->jif_maxpri+1
1452 1.1.2.1 peter && available[highest] >= 0)
1453 1.1.2.1 peter highest++; /* which is the highest class that needs more service? */
1454 1.1.2.1 peter while (lowest >= 0 && available[lowest] <= 0)
1455 1.1.2.1 peter lowest--; /* which is the lowest class that needs less service? */
1456 1.1.2.1 peter
1457 1.1.2.1 peter } else if (available[lowest]+available[highest] < 0) {
1458 1.1.2.1 peter /*
1459 1.1.2.1 peter * no more credit left and we need to switch
1460 1.1.2.1 peter * to another class
1461 1.1.2.1 peter */
1462 1.1.2.1 peter n[lowest] -= available[lowest];
1463 1.1.2.1 peter n[highest] += available[lowest];
1464 1.1.2.1 peter available[highest] += available[lowest];
1465 1.1.2.1 peter available[lowest] = 0;
1466 1.1.2.1 peter
1467 1.1.2.1 peter while ((lowest >= 0)&&(available[lowest] <= 0))
1468 1.1.2.1 peter lowest--; /* which is the lowest class that needs less service? */
1469 1.1.2.1 peter }
1470 1.1.2.1 peter }
1471 1.1.2.1 peter
1472 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1473 1.1.2.1 peter cl = jif->jif_classes[i];
1474 1.1.2.1 peter class_exists = (cl != NULL);
1475 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1476 1.1.2.1 peter if (is_backlogged) {
1477 1.1.2.1 peter result[i] = n[i] - cl->service_rate;
1478 1.1.2.1 peter } else {
1479 1.1.2.1 peter if (class_exists)
1480 1.1.2.1 peter result[i] = - cl->service_rate;
1481 1.1.2.1 peter else
1482 1.1.2.1 peter result[i] = 0;
1483 1.1.2.1 peter }
1484 1.1.2.1 peter }
1485 1.1.2.1 peter
1486 1.1.2.1 peter /* step 2: adjust drops (for ADC) */
1487 1.1.2.1 peter
1488 1.1.2.1 peter if (highest != jif->jif_maxpri+1) {
1489 1.1.2.1 peter /* some class(es) still need(s) additional service */
1490 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1491 1.1.2.1 peter cl = jif->jif_classes[i];
1492 1.1.2.1 peter class_exists = (cl != NULL);
1493 1.1.2.1 peter is_backlogged = (class_exists
1494 1.1.2.1 peter && !qempty(cl->cl_q));
1495 1.1.2.1 peter if (is_backlogged && available[i] < 0) {
1496 1.1.2.1 peter if (cl->concerned_adc) {
1497 1.1.2.1 peter k[i] = c[i]*n[i];
1498 1.1.2.1 peter while (keep_going && scale_rate((int64_t)(cl->cl_rin.bytes-cl->cl_rout.bytes)) > k[i]) {
1499 1.1.2.1 peter pkt = qtail(cl->cl_q);
1500 1.1.2.1 peter if (pkt != NULL) {
1501 1.1.2.1 peter /* "safeguard" test (a packet SHOULD be in there) */
1502 1.1.2.1 peter len = (u_int64_t)m_pktlen(pkt);
1503 1.1.2.1 peter /* access packet at the tail */
1504 1.1.2.1 peter if (cl->concerned_alc
1505 1.1.2.1 peter && cl->current_loss+(len << SCALE_LOSS)/cl->cl_arrival.bytes > cl->cl_alc) {
1506 1.1.2.1 peter keep_going = 0; /* relax ADC in favor of ALC */
1507 1.1.2.1 peter } else {
1508 1.1.2.1 peter /* drop packet at the tail of the class-i queue, update values */
1509 1.1.2.1 peter pkt = _getq_tail(cl->cl_q);
1510 1.1.2.1 peter len = (u_int64_t)m_pktlen(pkt);
1511 1.1.2.1 peter PKTCNTR_ADD(&cl->cl_dropcnt, (int)len);
1512 1.1.2.1 peter PKTCNTR_SUB(&cl->cl_rin, (int)len);
1513 1.1.2.1 peter PKTCNTR_ADD(&cl->st_dropcnt, (int)len);
1514 1.1.2.1 peter PKTCNTR_SUB(&cl->st_rin, (int)len);
1515 1.1.2.1 peter cl->current_loss += (len << SCALE_LOSS)/cl->cl_arrival.bytes;
1516 1.1.2.1 peter m_freem(pkt); /* the packet is trashed here */
1517 1.1.2.1 peter tslist_drop(cl);
1518 1.1.2.1 peter IFQ_DEC_LEN(cl->cl_jif->jif_ifq);
1519 1.1.2.1 peter }
1520 1.1.2.1 peter } else
1521 1.1.2.1 peter keep_going = 0; /* NOTREACHED */
1522 1.1.2.1 peter }
1523 1.1.2.1 peter k[i] = scale_rate((int64_t)(cl->cl_rin.bytes-cl->cl_rout.bytes));
1524 1.1.2.1 peter }
1525 1.1.2.1 peter /*
1526 1.1.2.1 peter * n[i] is the max rate we can give.
1527 1.1.2.1 peter * the above drops as much as possible
1528 1.1.2.1 peter * to respect a delay bound.
1529 1.1.2.1 peter * for throughput bounds,
1530 1.1.2.1 peter * there's nothing that can be done
1531 1.1.2.1 peter * after the greedy reallocation.
1532 1.1.2.1 peter */
1533 1.1.2.1 peter }
1534 1.1.2.1 peter }
1535 1.1.2.1 peter }
1536 1.1.2.1 peter
1537 1.1.2.1 peter /* update the values of min_rate_adc */
1538 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1539 1.1.2.1 peter cl = jif->jif_classes[i];
1540 1.1.2.1 peter class_exists = (cl != NULL);
1541 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1542 1.1.2.1 peter if (is_backlogged && cl->concerned_adc) {
1543 1.1.2.1 peter if (c[i] != 0) {
1544 1.1.2.1 peter if (cl->concerned_adc
1545 1.1.2.1 peter && !cl->concerned_arc)
1546 1.1.2.1 peter cl->min_rate_adc = k[i]/c[i];
1547 1.1.2.1 peter else
1548 1.1.2.1 peter cl->min_rate_adc = n[i];
1549 1.1.2.1 peter } else
1550 1.1.2.1 peter cl->min_rate_adc = (int64_t)bps_to_internal((u_int64_t)jif->jif_bandwidth);
1551 1.1.2.1 peter } else if (is_backlogged && cl->concerned_arc)
1552 1.1.2.1 peter cl->min_rate_adc = n[i]; /* the best we can give */
1553 1.1.2.1 peter else {
1554 1.1.2.1 peter if (class_exists)
1555 1.1.2.1 peter cl->min_rate_adc = 0;
1556 1.1.2.1 peter }
1557 1.1.2.1 peter }
1558 1.1.2.1 peter
1559 1.1.2.1 peter FREE(c, M_DEVBUF);
1560 1.1.2.1 peter FREE(n, M_DEVBUF);
1561 1.1.2.1 peter FREE(k, M_DEVBUF);
1562 1.1.2.1 peter FREE(available, M_DEVBUF);
1563 1.1.2.1 peter
1564 1.1.2.1 peter return (result);
1565 1.1.2.1 peter }
1566 1.1.2.1 peter
1567 1.1.2.1 peter /*
1568 1.1.2.1 peter * update_error: returns the difference between the mean weighted
1569 1.1.2.1 peter * delay and the weighted delay for each class. if proportional
1570 1.1.2.1 peter * delay differentiation is perfectly achieved, it should return
1571 1.1.2.1 peter * zero for each class.
1572 1.1.2.1 peter */
1573 1.1.2.1 peter static int64_t *
1574 1.1.2.1 peter update_error(jif)
1575 1.1.2.1 peter struct jobs_if *jif;
1576 1.1.2.1 peter {
1577 1.1.2.1 peter int i;
1578 1.1.2.1 peter int active_classes, backlogged_classes;
1579 1.1.2.1 peter u_int64_t mean_weighted_delay;
1580 1.1.2.1 peter u_int64_t delays[JOBS_MAXPRI];
1581 1.1.2.1 peter int64_t* error;
1582 1.1.2.1 peter int class_exists, is_backlogged;
1583 1.1.2.1 peter struct jobs_class *cl;
1584 1.1.2.1 peter
1585 1.1.2.1 peter MALLOC(error, int64_t*, sizeof(int64_t)*(jif->jif_maxpri+1), M_DEVBUF, M_WAITOK);
1586 1.1.2.1 peter
1587 1.1.2.1 peter if (error == NULL)
1588 1.1.2.1 peter return NULL;
1589 1.1.2.1 peter
1590 1.1.2.1 peter (void)memset(error, 0, sizeof(int64_t)*(jif->jif_maxpri+1));
1591 1.1.2.1 peter
1592 1.1.2.1 peter mean_weighted_delay = 0;
1593 1.1.2.1 peter active_classes = 0;
1594 1.1.2.1 peter backlogged_classes = 0;
1595 1.1.2.1 peter
1596 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1597 1.1.2.1 peter cl = jif->jif_classes[i];
1598 1.1.2.1 peter class_exists = (cl != NULL);
1599 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1600 1.1.2.1 peter
1601 1.1.2.1 peter if (is_backlogged) {
1602 1.1.2.1 peter backlogged_classes++;
1603 1.1.2.1 peter if (cl->concerned_rdc) {
1604 1.1.2.1 peter delays[i] = proj_delay(jif, i);
1605 1.1.2.1 peter mean_weighted_delay += cl->delay_prod_others*delays[i];
1606 1.1.2.1 peter active_classes ++;
1607 1.1.2.1 peter }
1608 1.1.2.1 peter }
1609 1.1.2.1 peter }
1610 1.1.2.1 peter
1611 1.1.2.1 peter if (active_classes == 0)
1612 1.1.2.1 peter return error;
1613 1.1.2.1 peter else
1614 1.1.2.1 peter mean_weighted_delay /= active_classes;
1615 1.1.2.1 peter
1616 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1617 1.1.2.1 peter cl = jif->jif_classes[i];
1618 1.1.2.1 peter class_exists = (cl != NULL);
1619 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1620 1.1.2.1 peter
1621 1.1.2.1 peter if (is_backlogged && cl->concerned_rdc)
1622 1.1.2.1 peter error[i] = ((int64_t)mean_weighted_delay)-((int64_t)cl->delay_prod_others*delays[i]);
1623 1.1.2.1 peter else
1624 1.1.2.1 peter error[i] = 0; /*
1625 1.1.2.1 peter * either the class isn't concerned,
1626 1.1.2.1 peter * or it's not backlogged.
1627 1.1.2.1 peter * in any case, the rate shouldn't
1628 1.1.2.1 peter * be adjusted.
1629 1.1.2.1 peter */
1630 1.1.2.1 peter }
1631 1.1.2.1 peter return error;
1632 1.1.2.1 peter }
1633 1.1.2.1 peter
1634 1.1.2.1 peter /*
1635 1.1.2.1 peter * min_rates_adc: computes the minimum service rates needed in
1636 1.1.2.1 peter * each class to meet the absolute delay bounds. if, for any
1637 1.1.2.1 peter * class i, the current service rate of class i is less than
1638 1.1.2.1 peter * the computed minimum service rate, this function returns
1639 1.1.2.1 peter * false, true otherwise.
1640 1.1.2.1 peter */
1641 1.1.2.1 peter static int
1642 1.1.2.1 peter min_rates_adc(jif)
1643 1.1.2.1 peter struct jobs_if *jif;
1644 1.1.2.1 peter {
1645 1.1.2.1 peter int result;
1646 1.1.2.1 peter int i;
1647 1.1.2.1 peter int class_exists, is_backlogged;
1648 1.1.2.1 peter int64_t remaining_time;
1649 1.1.2.1 peter struct jobs_class *cl;
1650 1.1.2.1 peter result = 1;
1651 1.1.2.1 peter
1652 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1653 1.1.2.1 peter cl = jif->jif_classes[i];
1654 1.1.2.1 peter class_exists = (cl != NULL);
1655 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1656 1.1.2.1 peter if (is_backlogged && cl->concerned_adc) {
1657 1.1.2.1 peter remaining_time = cl->cl_adc - proj_delay(jif, i);
1658 1.1.2.1 peter if (remaining_time > 0 ) {
1659 1.1.2.1 peter /* min rate needed for ADC */
1660 1.1.2.1 peter cl->min_rate_adc = scale_rate((int64_t)(cl->cl_rin.bytes-cl->cl_rout.bytes))/remaining_time;
1661 1.1.2.1 peter if (cl->concerned_arc
1662 1.1.2.1 peter && cl->cl_arc > cl->min_rate_adc) {
1663 1.1.2.1 peter /* min rate needed for ADC + ARC */
1664 1.1.2.1 peter cl->min_rate_adc = cl->cl_arc;
1665 1.1.2.1 peter }
1666 1.1.2.1 peter } else {
1667 1.1.2.1 peter /* the deadline has been exceeded: give the whole link capacity to hopefully fix the situation */
1668 1.1.2.1 peter cl->min_rate_adc = (int64_t)bps_to_internal((u_int64_t)jif->jif_bandwidth);
1669 1.1.2.1 peter }
1670 1.1.2.1 peter } else if (is_backlogged && cl->concerned_arc)
1671 1.1.2.1 peter cl->min_rate_adc = cl->cl_arc; /* no ADC, an ARC */
1672 1.1.2.1 peter else if (class_exists)
1673 1.1.2.1 peter cl->min_rate_adc = 0; /*
1674 1.1.2.1 peter * either the class is not
1675 1.1.2.1 peter * backlogged
1676 1.1.2.1 peter * or there is no ADC and
1677 1.1.2.1 peter * no ARC
1678 1.1.2.1 peter */
1679 1.1.2.1 peter if (is_backlogged && cl->min_rate_adc > cl->service_rate)
1680 1.1.2.1 peter result = 0;
1681 1.1.2.1 peter }
1682 1.1.2.1 peter
1683 1.1.2.1 peter return result;
1684 1.1.2.1 peter }
1685 1.1.2.1 peter
1686 1.1.2.1 peter /*
1687 1.1.2.1 peter * proj_delay: computes the difference between the current time
1688 1.1.2.1 peter * and the time the oldest class-i packet still in the class-i
1689 1.1.2.1 peter * queue i arrived in the system.
1690 1.1.2.1 peter */
1691 1.1.2.1 peter static int64_t
1692 1.1.2.1 peter proj_delay(jif, i)
1693 1.1.2.1 peter struct jobs_if *jif;
1694 1.1.2.1 peter int i;
1695 1.1.2.1 peter {
1696 1.1.2.1 peter u_int64_t now;
1697 1.1.2.1 peter int class_exists, is_backlogged;
1698 1.1.2.1 peter struct jobs_class *cl;
1699 1.1.2.1 peter
1700 1.1.2.1 peter now = read_machclk();
1701 1.1.2.1 peter cl = jif->jif_classes[i];
1702 1.1.2.1 peter class_exists = (cl != NULL);
1703 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1704 1.1.2.1 peter
1705 1.1.2.1 peter if (is_backlogged)
1706 1.1.2.1 peter return ((int64_t)delay_diff(now, tslist_first(cl->arv_tm)->timestamp));
1707 1.1.2.1 peter
1708 1.1.2.1 peter return (0); /* NOTREACHED */
1709 1.1.2.1 peter }
1710 1.1.2.1 peter
1711 1.1.2.1 peter /*
1712 1.1.2.1 peter * pick_dropped_rlc: returns the class index of the class to be
1713 1.1.2.1 peter * dropped for meeting the relative loss constraints.
1714 1.1.2.1 peter */
1715 1.1.2.1 peter static int
1716 1.1.2.1 peter pick_dropped_rlc(jif)
1717 1.1.2.1 peter struct jobs_if *jif;
1718 1.1.2.1 peter {
1719 1.1.2.1 peter int64_t mean;
1720 1.1.2.1 peter int64_t* loss_error;
1721 1.1.2.1 peter int i, active_classes, backlogged_classes;
1722 1.1.2.1 peter int class_exists, is_backlogged;
1723 1.1.2.1 peter int class_dropped;
1724 1.1.2.1 peter int64_t max_error;
1725 1.1.2.1 peter int64_t max_alc;
1726 1.1.2.1 peter struct mbuf* pkt;
1727 1.1.2.1 peter struct jobs_class *cl;
1728 1.1.2.1 peter u_int64_t len;
1729 1.1.2.1 peter
1730 1.1.2.1 peter MALLOC(loss_error, int64_t *, sizeof(int64_t)*(jif->jif_maxpri+1), M_DEVBUF, M_WAITOK);
1731 1.1.2.1 peter
1732 1.1.2.1 peter if (loss_error == NULL)
1733 1.1.2.1 peter return -1;
1734 1.1.2.1 peter
1735 1.1.2.1 peter class_dropped = -1;
1736 1.1.2.1 peter max_error = 0;
1737 1.1.2.1 peter mean = 0;
1738 1.1.2.1 peter active_classes = 0;
1739 1.1.2.1 peter backlogged_classes = 0;
1740 1.1.2.1 peter
1741 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1742 1.1.2.1 peter cl = jif->jif_classes[i];
1743 1.1.2.1 peter class_exists = (cl != NULL);
1744 1.1.2.1 peter is_backlogged = (class_exists && !qempty(cl->cl_q));
1745 1.1.2.1 peter if (is_backlogged) {
1746 1.1.2.1 peter backlogged_classes ++;
1747 1.1.2.1 peter if (cl->concerned_rlc) {
1748 1.1.2.1 peter mean += cl->loss_prod_others
1749 1.1.2.1 peter * cl->current_loss;
1750 1.1.2.1 peter active_classes++;
1751 1.1.2.1 peter }
1752 1.1.2.1 peter }
1753 1.1.2.1 peter }
1754 1.1.2.1 peter
1755 1.1.2.1 peter if (active_classes > 0)
1756 1.1.2.1 peter mean /= active_classes;
1757 1.1.2.1 peter
1758 1.1.2.1 peter if (active_classes == 0)
1759 1.1.2.1 peter class_dropped = JOBS_MAXPRI+1; /*
1760 1.1.2.1 peter * no classes are concerned
1761 1.1.2.1 peter * by RLCs (JOBS_MAXPRI+1
1762 1.1.2.1 peter * means "ignore RLC" here)
1763 1.1.2.1 peter */
1764 1.1.2.1 peter else {
1765 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1766 1.1.2.1 peter cl = jif->jif_classes[i];
1767 1.1.2.1 peter class_exists = (cl != NULL);
1768 1.1.2.1 peter is_backlogged = (class_exists
1769 1.1.2.1 peter && !qempty(cl->cl_q));
1770 1.1.2.1 peter
1771 1.1.2.1 peter if ((is_backlogged)&&(cl->cl_rlc))
1772 1.1.2.1 peter loss_error[i]=cl->loss_prod_others
1773 1.1.2.1 peter *cl->current_loss-mean;
1774 1.1.2.1 peter else
1775 1.1.2.1 peter loss_error[i] = INFINITY;
1776 1.1.2.1 peter }
1777 1.1.2.1 peter
1778 1.1.2.1 peter for (i = 0; i <= jif->jif_maxpri; i++) {
1779 1.1.2.1 peter cl = jif->jif_classes[i];
1780 1.1.2.1 peter class_exists = (cl != NULL);
1781 1.1.2.1 peter is_backlogged = (class_exists
1782 1.1.2.1 peter && !qempty(cl->cl_q));
1783 1.1.2.1 peter if (is_backlogged && loss_error[i] <= max_error) {
1784 1.1.2.1 peter /*
1785 1.1.2.1 peter * find out which class is the most
1786 1.1.2.1 peter * below the mean.
1787 1.1.2.1 peter * it's the one that needs to be dropped
1788 1.1.2.1 peter * ties are broken in favor of the higher
1789 1.1.2.1 peter * priority classes (i.e., if two classes
1790 1.1.2.1 peter * present the same deviation, the lower
1791 1.1.2.1 peter * priority class will get dropped).
1792 1.1.2.1 peter */
1793 1.1.2.1 peter max_error = loss_error[i];
1794 1.1.2.1 peter class_dropped = i;
1795 1.1.2.1 peter }
1796 1.1.2.1 peter }
1797 1.1.2.1 peter
1798 1.1.2.1 peter if (class_dropped != -1) {
1799 1.1.2.1 peter cl = jif->jif_classes[class_dropped];
1800 1.1.2.1 peter pkt = qtail(cl->cl_q);
1801 1.1.2.1 peter if (pkt != NULL) {
1802 1.1.2.1 peter /*
1803 1.1.2.1 peter * "safeguard" test (a packet SHOULD be
1804 1.1.2.1 peter * in there)
1805 1.1.2.1 peter */
1806 1.1.2.1 peter len = (u_int64_t)m_pktlen(pkt);
1807 1.1.2.1 peter /* access packet at the tail */
1808 1.1.2.1 peter if (cl->current_loss+(len << SCALE_LOSS)/cl->cl_arrival.bytes > cl->cl_alc) {
1809 1.1.2.1 peter /*
1810 1.1.2.1 peter * the class to drop for meeting
1811 1.1.2.1 peter * the RLC will defeat the ALC:
1812 1.1.2.1 peter * ignore RLC.
1813 1.1.2.1 peter */
1814 1.1.2.1 peter class_dropped = JOBS_MAXPRI+1;
1815 1.1.2.1 peter }
1816 1.1.2.1 peter } else
1817 1.1.2.1 peter class_dropped = JOBS_MAXPRI+1; /* NOTREACHED */
1818 1.1.2.1 peter } else
1819 1.1.2.1 peter class_dropped = JOBS_MAXPRI+1;
1820 1.1.2.1 peter }
1821 1.1.2.1 peter
1822 1.1.2.1 peter if (class_dropped == JOBS_MAXPRI+1) {
1823 1.1.2.1 peter max_alc = -((int64_t)1 << SCALE_LOSS);
1824 1.1.2.1 peter for (i = jif->jif_maxpri; i >= 0; i--) {
1825 1.1.2.1 peter cl = jif->jif_classes[i];
1826 1.1.2.1 peter class_exists = (cl != NULL);
1827 1.1.2.1 peter is_backlogged = (class_exists
1828 1.1.2.1 peter && !qempty(cl->cl_q));
1829 1.1.2.1 peter if (is_backlogged) {
1830 1.1.2.1 peter if (cl->concerned_alc && cl->cl_alc - cl->current_loss > max_alc) {
1831 1.1.2.1 peter max_alc = cl->cl_alc-cl->current_loss; /* pick the class which is the furthest from its ALC */
1832 1.1.2.1 peter class_dropped = i;
1833 1.1.2.1 peter } else if (!cl->concerned_alc && ((int64_t) 1 << SCALE_LOSS)-cl->current_loss > max_alc) {
1834 1.1.2.1 peter max_alc = ((int64_t) 1 << SCALE_LOSS)-cl->current_loss;
1835 1.1.2.1 peter class_dropped = i;
1836 1.1.2.1 peter }
1837 1.1.2.1 peter }
1838 1.1.2.1 peter }
1839 1.1.2.1 peter }
1840 1.1.2.1 peter
1841 1.1.2.1 peter FREE(loss_error, M_DEVBUF);
1842 1.1.2.1 peter return (class_dropped);
1843 1.1.2.1 peter }
1844 1.1.2.1 peter
1845 1.1.2.1 peter /*
1846 1.1.2.1 peter * ALTQ binding/setup functions
1847 1.1.2.1 peter */
1848 1.1.2.1 peter /*
1849 1.1.2.1 peter * jobs device interface
1850 1.1.2.1 peter */
1851 1.1.2.1 peter int
1852 1.1.2.1 peter jobsopen(dev, flag, fmt, l)
1853 1.1.2.1 peter dev_t dev;
1854 1.1.2.1 peter int flag, fmt;
1855 1.1.2.1 peter struct lwp *l;
1856 1.1.2.1 peter {
1857 1.1.2.1 peter if (machclk_freq == 0)
1858 1.1.2.1 peter init_machclk();
1859 1.1.2.1 peter
1860 1.1.2.1 peter if (machclk_freq == 0) {
1861 1.1.2.1 peter printf("jobs: no CPU clock available!\n");
1862 1.1.2.1 peter return (ENXIO);
1863 1.1.2.1 peter }
1864 1.1.2.1 peter /* everything will be done when the queueing scheme is attached. */
1865 1.1.2.1 peter return 0;
1866 1.1.2.1 peter }
1867 1.1.2.1 peter
1868 1.1.2.1 peter int
1869 1.1.2.1 peter jobsclose(dev, flag, fmt, l)
1870 1.1.2.1 peter dev_t dev;
1871 1.1.2.1 peter int flag, fmt;
1872 1.1.2.1 peter struct lwp *l;
1873 1.1.2.1 peter {
1874 1.1.2.1 peter struct jobs_if *jif;
1875 1.1.2.1 peter int err, error = 0;
1876 1.1.2.1 peter
1877 1.1.2.1 peter while ((jif = jif_list) != NULL) {
1878 1.1.2.1 peter /* destroy all */
1879 1.1.2.1 peter if (ALTQ_IS_ENABLED(jif->jif_ifq))
1880 1.1.2.1 peter altq_disable(jif->jif_ifq);
1881 1.1.2.1 peter
1882 1.1.2.1 peter err = altq_detach(jif->jif_ifq);
1883 1.1.2.1 peter if (err == 0)
1884 1.1.2.1 peter err = jobs_detach(jif);
1885 1.1.2.1 peter if (err != 0 && error == 0)
1886 1.1.2.1 peter error = err;
1887 1.1.2.1 peter }
1888 1.1.2.1 peter
1889 1.1.2.1 peter return error;
1890 1.1.2.1 peter }
1891 1.1.2.1 peter
1892 1.1.2.1 peter int
1893 1.1.2.1 peter jobsioctl(dev, cmd, addr, flag, l)
1894 1.1.2.1 peter dev_t dev;
1895 1.1.2.1 peter ioctlcmd_t cmd;
1896 1.1.2.1 peter caddr_t addr;
1897 1.1.2.1 peter int flag;
1898 1.1.2.1 peter struct lwp *l;
1899 1.1.2.1 peter {
1900 1.1.2.1 peter struct jobs_if *jif;
1901 1.1.2.1 peter struct jobs_interface *ifacep;
1902 1.1.2.1 peter struct proc *p = l->l_proc;
1903 1.1.2.1 peter int error = 0;
1904 1.1.2.1 peter
1905 1.1.2.1 peter /* check super-user privilege */
1906 1.1.2.1 peter switch (cmd) {
1907 1.1.2.1 peter case JOBS_GETSTATS:
1908 1.1.2.1 peter break;
1909 1.1.2.1 peter default:
1910 1.1.2.1 peter #if (__FreeBSD_version > 400000)
1911 1.1.2.1 peter if ((error = suser(p)) != 0)
1912 1.1.2.1 peter return (error);
1913 1.1.2.1 peter #else
1914 1.1.2.1 peter if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1915 1.1.2.1 peter return (error);
1916 1.1.2.1 peter #endif
1917 1.1.2.1 peter break;
1918 1.1.2.1 peter }
1919 1.1.2.1 peter
1920 1.1.2.1 peter switch (cmd) {
1921 1.1.2.1 peter
1922 1.1.2.1 peter case JOBS_IF_ATTACH:
1923 1.1.2.1 peter error = jobscmd_if_attach((struct jobs_attach *)addr);
1924 1.1.2.1 peter break;
1925 1.1.2.1 peter
1926 1.1.2.1 peter case JOBS_IF_DETACH:
1927 1.1.2.1 peter error = jobscmd_if_detach((struct jobs_interface *)addr);
1928 1.1.2.1 peter break;
1929 1.1.2.1 peter
1930 1.1.2.1 peter case JOBS_ENABLE:
1931 1.1.2.1 peter case JOBS_DISABLE:
1932 1.1.2.1 peter case JOBS_CLEAR:
1933 1.1.2.1 peter ifacep = (struct jobs_interface *)addr;
1934 1.1.2.1 peter if ((jif = altq_lookup(ifacep->jobs_ifname,
1935 1.1.2.1 peter ALTQT_JOBS)) == NULL) {
1936 1.1.2.1 peter error = EBADF;
1937 1.1.2.1 peter break;
1938 1.1.2.1 peter }
1939 1.1.2.1 peter
1940 1.1.2.1 peter switch (cmd) {
1941 1.1.2.1 peter case JOBS_ENABLE:
1942 1.1.2.1 peter if (jif->jif_default == NULL) {
1943 1.1.2.1 peter #if 1
1944 1.1.2.1 peter printf("jobs: no default class\n");
1945 1.1.2.1 peter #endif
1946 1.1.2.1 peter error = EINVAL;
1947 1.1.2.1 peter break;
1948 1.1.2.1 peter }
1949 1.1.2.1 peter error = altq_enable(jif->jif_ifq);
1950 1.1.2.1 peter break;
1951 1.1.2.1 peter
1952 1.1.2.1 peter case JOBS_DISABLE:
1953 1.1.2.1 peter error = altq_disable(jif->jif_ifq);
1954 1.1.2.1 peter break;
1955 1.1.2.1 peter
1956 1.1.2.1 peter case JOBS_CLEAR:
1957 1.1.2.1 peter jobs_clear_interface(jif);
1958 1.1.2.1 peter break;
1959 1.1.2.1 peter }
1960 1.1.2.1 peter break;
1961 1.1.2.1 peter
1962 1.1.2.1 peter case JOBS_ADD_CLASS:
1963 1.1.2.1 peter error = jobscmd_add_class((struct jobs_add_class *)addr);
1964 1.1.2.1 peter break;
1965 1.1.2.1 peter
1966 1.1.2.1 peter case JOBS_DEL_CLASS:
1967 1.1.2.1 peter error = jobscmd_delete_class((struct jobs_delete_class *)addr);
1968 1.1.2.1 peter break;
1969 1.1.2.1 peter
1970 1.1.2.1 peter case JOBS_MOD_CLASS:
1971 1.1.2.1 peter error = jobscmd_modify_class((struct jobs_modify_class *)addr);
1972 1.1.2.1 peter break;
1973 1.1.2.1 peter
1974 1.1.2.1 peter case JOBS_ADD_FILTER:
1975 1.1.2.1 peter error = jobscmd_add_filter((struct jobs_add_filter *)addr);
1976 1.1.2.1 peter break;
1977 1.1.2.1 peter
1978 1.1.2.1 peter case JOBS_DEL_FILTER:
1979 1.1.2.1 peter error = jobscmd_delete_filter((struct jobs_delete_filter *)addr);
1980 1.1.2.1 peter break;
1981 1.1.2.1 peter
1982 1.1.2.1 peter case JOBS_GETSTATS:
1983 1.1.2.1 peter error = jobscmd_class_stats((struct jobs_class_stats *)addr);
1984 1.1.2.1 peter break;
1985 1.1.2.1 peter
1986 1.1.2.1 peter default:
1987 1.1.2.1 peter error = EINVAL;
1988 1.1.2.1 peter break;
1989 1.1.2.1 peter }
1990 1.1.2.1 peter return error;
1991 1.1.2.1 peter }
1992 1.1.2.1 peter
1993 1.1.2.1 peter static int
1994 1.1.2.1 peter jobscmd_if_attach(ap)
1995 1.1.2.1 peter struct jobs_attach *ap;
1996 1.1.2.1 peter {
1997 1.1.2.1 peter struct jobs_if *jif;
1998 1.1.2.1 peter struct ifnet *ifp;
1999 1.1.2.1 peter int error;
2000 1.1.2.1 peter
2001 1.1.2.1 peter if ((ifp = ifunit(ap->iface.jobs_ifname)) == NULL)
2002 1.1.2.1 peter return (ENXIO);
2003 1.1.2.1 peter if ((jif = jobs_attach(&ifp->if_snd, ap->bandwidth, ap->qlimit, ap->separate)) == NULL)
2004 1.1.2.1 peter return (ENOMEM);
2005 1.1.2.1 peter
2006 1.1.2.1 peter /*
2007 1.1.2.1 peter * set JOBS to this ifnet structure.
2008 1.1.2.1 peter */
2009 1.1.2.1 peter if ((error = altq_attach(&ifp->if_snd, ALTQT_JOBS, jif,
2010 1.1.2.1 peter jobs_enqueue, jobs_dequeue, jobs_request,
2011 1.1.2.1 peter &jif->jif_classifier, acc_classify)) != 0)
2012 1.1.2.1 peter (void)jobs_detach(jif);
2013 1.1.2.1 peter
2014 1.1.2.1 peter return (error);
2015 1.1.2.1 peter }
2016 1.1.2.1 peter
2017 1.1.2.1 peter static int
2018 1.1.2.1 peter jobscmd_if_detach(ap)
2019 1.1.2.1 peter struct jobs_interface *ap;
2020 1.1.2.1 peter {
2021 1.1.2.1 peter struct jobs_if *jif;
2022 1.1.2.1 peter int error;
2023 1.1.2.1 peter
2024 1.1.2.1 peter if ((jif = altq_lookup(ap->jobs_ifname, ALTQT_JOBS)) == NULL)
2025 1.1.2.1 peter return (EBADF);
2026 1.1.2.1 peter
2027 1.1.2.1 peter if (ALTQ_IS_ENABLED(jif->jif_ifq))
2028 1.1.2.1 peter altq_disable(jif->jif_ifq);
2029 1.1.2.1 peter
2030 1.1.2.1 peter if ((error = altq_detach(jif->jif_ifq)))
2031 1.1.2.1 peter return (error);
2032 1.1.2.1 peter
2033 1.1.2.1 peter return jobs_detach(jif);
2034 1.1.2.1 peter }
2035 1.1.2.1 peter
2036 1.1.2.1 peter static int
2037 1.1.2.1 peter jobscmd_add_class(ap)
2038 1.1.2.1 peter struct jobs_add_class *ap;
2039 1.1.2.1 peter {
2040 1.1.2.1 peter struct jobs_if *jif;
2041 1.1.2.1 peter struct jobs_class *cl;
2042 1.1.2.1 peter
2043 1.1.2.1 peter if ((jif = altq_lookup(ap->iface.jobs_ifname, ALTQT_JOBS)) == NULL)
2044 1.1.2.1 peter return (EBADF);
2045 1.1.2.1 peter
2046 1.1.2.1 peter if (ap->pri < 0 || ap->pri >= JOBS_MAXPRI)
2047 1.1.2.1 peter return (EINVAL);
2048 1.1.2.1 peter
2049 1.1.2.1 peter if ((cl = jobs_class_create(jif, ap->pri,
2050 1.1.2.1 peter ap->cl_adc, ap->cl_rdc,
2051 1.1.2.1 peter ap->cl_alc, ap->cl_rlc, ap-> cl_arc,
2052 1.1.2.1 peter ap->flags)) == NULL)
2053 1.1.2.1 peter return (ENOMEM);
2054 1.1.2.1 peter
2055 1.1.2.1 peter /* return a class handle to the user */
2056 1.1.2.1 peter ap->class_handle = clp_to_clh(cl);
2057 1.1.2.1 peter return (0);
2058 1.1.2.1 peter }
2059 1.1.2.1 peter
2060 1.1.2.1 peter static int
2061 1.1.2.1 peter jobscmd_delete_class(ap)
2062 1.1.2.1 peter struct jobs_delete_class *ap;
2063 1.1.2.1 peter {
2064 1.1.2.1 peter struct jobs_if *jif;
2065 1.1.2.1 peter struct jobs_class *cl;
2066 1.1.2.1 peter
2067 1.1.2.1 peter if ((jif = altq_lookup(ap->iface.jobs_ifname, ALTQT_JOBS)) == NULL)
2068 1.1.2.1 peter return (EBADF);
2069 1.1.2.1 peter
2070 1.1.2.1 peter if ((cl = clh_to_clp(jif, ap->class_handle)) == NULL)
2071 1.1.2.1 peter return (EINVAL);
2072 1.1.2.1 peter
2073 1.1.2.1 peter return jobs_class_destroy(cl);
2074 1.1.2.1 peter }
2075 1.1.2.1 peter
2076 1.1.2.1 peter static int
2077 1.1.2.1 peter jobscmd_modify_class(ap)
2078 1.1.2.1 peter struct jobs_modify_class *ap;
2079 1.1.2.1 peter {
2080 1.1.2.1 peter struct jobs_if *jif;
2081 1.1.2.1 peter struct jobs_class *cl;
2082 1.1.2.1 peter
2083 1.1.2.1 peter if ((jif = altq_lookup(ap->iface.jobs_ifname, ALTQT_JOBS)) == NULL)
2084 1.1.2.1 peter return (EBADF);
2085 1.1.2.1 peter
2086 1.1.2.1 peter if (ap->pri < 0 || ap->pri >= JOBS_MAXPRI)
2087 1.1.2.1 peter return (EINVAL);
2088 1.1.2.1 peter
2089 1.1.2.1 peter if ((cl = clh_to_clp(jif, ap->class_handle)) == NULL)
2090 1.1.2.1 peter return (EINVAL);
2091 1.1.2.1 peter
2092 1.1.2.1 peter /*
2093 1.1.2.1 peter * if priority is changed, move the class to the new priority
2094 1.1.2.1 peter */
2095 1.1.2.1 peter if (jif->jif_classes[ap->pri] != cl) {
2096 1.1.2.1 peter if (jif->jif_classes[ap->pri] != NULL)
2097 1.1.2.1 peter return (EEXIST);
2098 1.1.2.1 peter jif->jif_classes[cl->cl_pri] = NULL;
2099 1.1.2.1 peter jif->jif_classes[ap->pri] = cl;
2100 1.1.2.1 peter cl->cl_pri = ap->pri;
2101 1.1.2.1 peter }
2102 1.1.2.1 peter
2103 1.1.2.1 peter /* call jobs_class_create to change class parameters */
2104 1.1.2.1 peter if ((cl = jobs_class_create(jif, ap->pri,
2105 1.1.2.1 peter ap->cl_adc, ap->cl_rdc,
2106 1.1.2.1 peter ap->cl_alc, ap->cl_rlc, ap->cl_arc,
2107 1.1.2.1 peter ap->flags)) == NULL)
2108 1.1.2.1 peter return (ENOMEM);
2109 1.1.2.1 peter return 0;
2110 1.1.2.1 peter }
2111 1.1.2.1 peter
2112 1.1.2.1 peter static int
2113 1.1.2.1 peter jobscmd_add_filter(ap)
2114 1.1.2.1 peter struct jobs_add_filter *ap;
2115 1.1.2.1 peter {
2116 1.1.2.1 peter struct jobs_if *jif;
2117 1.1.2.1 peter struct jobs_class *cl;
2118 1.1.2.1 peter
2119 1.1.2.1 peter if ((jif = altq_lookup(ap->iface.jobs_ifname, ALTQT_JOBS)) == NULL)
2120 1.1.2.1 peter return (EBADF);
2121 1.1.2.1 peter
2122 1.1.2.1 peter if ((cl = clh_to_clp(jif, ap->class_handle)) == NULL)
2123 1.1.2.1 peter return (EINVAL);
2124 1.1.2.1 peter
2125 1.1.2.1 peter return acc_add_filter(&jif->jif_classifier, &ap->filter,
2126 1.1.2.1 peter cl, &ap->filter_handle);
2127 1.1.2.1 peter }
2128 1.1.2.1 peter
2129 1.1.2.1 peter static int
2130 1.1.2.1 peter jobscmd_delete_filter(ap)
2131 1.1.2.1 peter struct jobs_delete_filter *ap;
2132 1.1.2.1 peter {
2133 1.1.2.1 peter struct jobs_if *jif;
2134 1.1.2.1 peter
2135 1.1.2.1 peter if ((jif = altq_lookup(ap->iface.jobs_ifname, ALTQT_JOBS)) == NULL)
2136 1.1.2.1 peter return (EBADF);
2137 1.1.2.1 peter
2138 1.1.2.1 peter return acc_delete_filter(&jif->jif_classifier,
2139 1.1.2.1 peter ap->filter_handle);
2140 1.1.2.1 peter }
2141 1.1.2.1 peter
2142 1.1.2.1 peter static int
2143 1.1.2.1 peter jobscmd_class_stats(ap)
2144 1.1.2.1 peter struct jobs_class_stats *ap;
2145 1.1.2.1 peter {
2146 1.1.2.1 peter struct jobs_if *jif;
2147 1.1.2.1 peter struct jobs_class *cl;
2148 1.1.2.1 peter struct class_stats stats, *usp;
2149 1.1.2.1 peter int pri, error;
2150 1.1.2.1 peter
2151 1.1.2.1 peter if ((jif = altq_lookup(ap->iface.jobs_ifname, ALTQT_JOBS)) == NULL)
2152 1.1.2.1 peter return (EBADF);
2153 1.1.2.1 peter
2154 1.1.2.1 peter ap->maxpri = jif->jif_maxpri;
2155 1.1.2.1 peter
2156 1.1.2.1 peter /* then, read the next N classes */
2157 1.1.2.1 peter usp = ap->stats;
2158 1.1.2.1 peter for (pri = 0; pri <= jif->jif_maxpri; pri++) {
2159 1.1.2.1 peter cl = jif->jif_classes[pri];
2160 1.1.2.1 peter if (cl != NULL)
2161 1.1.2.1 peter get_class_stats(&stats, cl);
2162 1.1.2.1 peter else
2163 1.1.2.1 peter (void)memset(&stats, 0, sizeof(stats));
2164 1.1.2.1 peter if ((error = copyout((caddr_t)&stats, (caddr_t)usp++,
2165 1.1.2.1 peter sizeof(stats))) != 0)
2166 1.1.2.1 peter return (error);
2167 1.1.2.1 peter }
2168 1.1.2.1 peter return (0);
2169 1.1.2.1 peter }
2170 1.1.2.1 peter
2171 1.1.2.1 peter static void get_class_stats(sp, cl)
2172 1.1.2.1 peter struct class_stats *sp;
2173 1.1.2.1 peter struct jobs_class *cl;
2174 1.1.2.1 peter {
2175 1.1.2.1 peter u_int64_t now;
2176 1.1.2.1 peter now = read_machclk();
2177 1.1.2.1 peter
2178 1.1.2.1 peter sp->class_handle = clp_to_clh(cl);
2179 1.1.2.1 peter sp->qlength = qlen(cl->cl_q);
2180 1.1.2.1 peter
2181 1.1.2.1 peter sp->period = cl->cl_period;
2182 1.1.2.1 peter sp->rin = cl->st_rin;
2183 1.1.2.1 peter sp->arrival = cl->st_arrival;
2184 1.1.2.1 peter sp->arrivalbusy = cl->cl_arrival;
2185 1.1.2.1 peter sp->rout = cl->st_rout;
2186 1.1.2.1 peter sp->dropcnt = cl->cl_dropcnt;
2187 1.1.2.1 peter
2188 1.1.2.1 peter /* PKTCNTR_RESET(&cl->st_arrival);*/
2189 1.1.2.1 peter PKTCNTR_RESET(&cl->st_rin);
2190 1.1.2.1 peter PKTCNTR_RESET(&cl->st_rout);
2191 1.1.2.1 peter
2192 1.1.2.1 peter sp->totallength = cl->cl_jif->jif_ifq->ifq_len;
2193 1.1.2.1 peter sp->lastdel = ticks_to_secs(GRANULARITY*cl->cl_lastdel);
2194 1.1.2.1 peter sp->avgdel = cl->cl_avgdel;
2195 1.1.2.1 peter
2196 1.1.2.1 peter cl->cl_avgdel = 0;
2197 1.1.2.1 peter
2198 1.1.2.1 peter sp->busylength = ticks_to_secs(1000*delay_diff(now, cl->idletime));
2199 1.1.2.1 peter sp->adc_violations = cl->adc_violations;
2200 1.1.2.1 peter
2201 1.1.2.1 peter sp->wc_cycles_enqueue = cl->cl_jif->wc_cycles_enqueue;
2202 1.1.2.1 peter sp->wc_cycles_dequeue = cl->cl_jif->wc_cycles_dequeue;
2203 1.1.2.1 peter sp->bc_cycles_enqueue = cl->cl_jif->bc_cycles_enqueue;
2204 1.1.2.1 peter sp->bc_cycles_dequeue = cl->cl_jif->bc_cycles_dequeue;
2205 1.1.2.1 peter sp->avg_cycles_enqueue = cl->cl_jif->avg_cycles_enqueue;
2206 1.1.2.1 peter sp->avg_cycles_dequeue = cl->cl_jif->avg_cycles_dequeue;
2207 1.1.2.1 peter sp->avg_cycles2_enqueue = cl->cl_jif->avg_cycles2_enqueue;
2208 1.1.2.1 peter sp->avg_cycles2_dequeue = cl->cl_jif->avg_cycles2_dequeue;
2209 1.1.2.1 peter sp->total_enqueued = cl->cl_jif->total_enqueued;
2210 1.1.2.1 peter sp->total_dequeued = cl->cl_jif->total_dequeued;
2211 1.1.2.1 peter }
2212 1.1.2.1 peter
2213 1.1.2.1 peter /* convert a class handle to the corresponding class pointer */
2214 1.1.2.1 peter static struct jobs_class *
2215 1.1.2.1 peter clh_to_clp(jif, chandle)
2216 1.1.2.1 peter struct jobs_if *jif;
2217 1.1.2.1 peter u_long chandle;
2218 1.1.2.1 peter {
2219 1.1.2.1 peter struct jobs_class *cl;
2220 1.1.2.1 peter
2221 1.1.2.1 peter cl = (struct jobs_class *)chandle;
2222 1.1.2.1 peter if (chandle != ALIGN(cl)) {
2223 1.1.2.1 peter #if 1
2224 1.1.2.1 peter printf("clh_to_cl: unaligned pointer %p\n", cl);
2225 1.1.2.1 peter #endif
2226 1.1.2.1 peter return (NULL);
2227 1.1.2.1 peter }
2228 1.1.2.1 peter
2229 1.1.2.1 peter if (cl == NULL || cl->cl_handle != chandle || cl->cl_jif != jif)
2230 1.1.2.1 peter return (NULL);
2231 1.1.2.1 peter return (cl);
2232 1.1.2.1 peter }
2233 1.1.2.1 peter
2234 1.1.2.1 peter /* convert a class pointer to the corresponding class handle */
2235 1.1.2.1 peter static u_long
2236 1.1.2.1 peter clp_to_clh(cl)
2237 1.1.2.1 peter struct jobs_class *cl;
2238 1.1.2.1 peter {
2239 1.1.2.1 peter return (cl->cl_handle);
2240 1.1.2.1 peter }
2241 1.1.2.1 peter
2242 1.1.2.1 peter #ifdef KLD_MODULE
2243 1.1.2.1 peter
2244 1.1.2.1 peter static struct altqsw jobs_sw =
2245 1.1.2.1 peter {"jobs", jobsopen, jobsclose, jobsioctl};
2246 1.1.2.1 peter
2247 1.1.2.1 peter ALTQ_MODULE(altq_jobs, ALTQT_JOBS, &jobs_sw);
2248 1.1.2.1 peter
2249 1.1.2.1 peter #endif /* KLD_MODULE */
2250 1.1.2.1 peter
2251 1.1.2.1 peter #endif /* ALTQ3_COMPAT */
2252 1.1.2.1 peter #endif /* ALTQ_JOBS */
2253