1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /* $FreeBSD$ */ |
---|
4 | /* $KAME: altq_cbq.c,v 1.19 2003/09/17 14:23:25 kjc Exp $ */ |
---|
5 | |
---|
6 | /* |
---|
7 | * Copyright (c) Sun Microsystems, Inc. 1993-1998 All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions |
---|
11 | * are met: |
---|
12 | * |
---|
13 | * 1. Redistributions of source code must retain the above copyright |
---|
14 | * notice, this list of conditions and the following disclaimer. |
---|
15 | * |
---|
16 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
17 | * notice, this list of conditions and the following disclaimer in the |
---|
18 | * documentation and/or other materials provided with the distribution. |
---|
19 | * |
---|
20 | * 3. All advertising materials mentioning features or use of this software |
---|
21 | * must display the following acknowledgement: |
---|
22 | * This product includes software developed by the SMCC Technology |
---|
23 | * Development Group at Sun Microsystems, Inc. |
---|
24 | * |
---|
25 | * 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or |
---|
26 | * promote products derived from this software without specific prior |
---|
27 | * written permission. |
---|
28 | * |
---|
29 | * SUN MICROSYSTEMS DOES NOT CLAIM MERCHANTABILITY OF THIS SOFTWARE OR THE |
---|
30 | * SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE. The software is |
---|
31 | * provided "as is" without express or implied warranty of any kind. |
---|
32 | * |
---|
33 | * These notices must be retained in any copies of any part of this software. |
---|
34 | */ |
---|
35 | |
---|
36 | #if defined(__FreeBSD__) || defined(__NetBSD__) |
---|
37 | #include <rtems/bsd/local/opt_altq.h> |
---|
38 | #include <rtems/bsd/local/opt_inet.h> |
---|
39 | #ifdef __FreeBSD__ |
---|
40 | #include <rtems/bsd/local/opt_inet6.h> |
---|
41 | #endif |
---|
42 | #endif /* __FreeBSD__ || __NetBSD__ */ |
---|
43 | #ifdef ALTQ_CBQ /* cbq is enabled by ALTQ_CBQ option in opt_altq.h */ |
---|
44 | |
---|
45 | #include <rtems/bsd/sys/param.h> |
---|
46 | #include <sys/malloc.h> |
---|
47 | #include <sys/mbuf.h> |
---|
48 | #include <sys/socket.h> |
---|
49 | #include <sys/systm.h> |
---|
50 | #include <sys/proc.h> |
---|
51 | #include <rtems/bsd/sys/errno.h> |
---|
52 | #include <sys/time.h> |
---|
53 | #ifdef ALTQ3_COMPAT |
---|
54 | #include <sys/uio.h> |
---|
55 | #include <sys/kernel.h> |
---|
56 | #endif |
---|
57 | |
---|
58 | #include <net/if.h> |
---|
59 | #include <netinet/in.h> |
---|
60 | |
---|
61 | #include <net/pfvar.h> |
---|
62 | #include <altq/altq.h> |
---|
63 | #include <altq/altq_cbq.h> |
---|
64 | #ifdef ALTQ3_COMPAT |
---|
65 | #include <altq/altq_conf.h> |
---|
66 | #endif |
---|
67 | |
---|
68 | #ifdef ALTQ3_COMPAT |
---|
69 | /* |
---|
70 | * Local Data structures. |
---|
71 | */ |
---|
72 | static cbq_state_t *cbq_list = NULL; |
---|
73 | #endif |
---|
74 | |
---|
75 | /* |
---|
76 | * Forward Declarations. |
---|
77 | */ |
---|
78 | static int cbq_class_destroy(cbq_state_t *, struct rm_class *); |
---|
79 | static struct rm_class *clh_to_clp(cbq_state_t *, u_int32_t); |
---|
80 | static int cbq_clear_interface(cbq_state_t *); |
---|
81 | static int cbq_request(struct ifaltq *, int, void *); |
---|
82 | static int cbq_enqueue(struct ifaltq *, struct mbuf *, |
---|
83 | struct altq_pktattr *); |
---|
84 | static struct mbuf *cbq_dequeue(struct ifaltq *, int); |
---|
85 | static void cbqrestart(struct ifaltq *); |
---|
86 | static void get_class_stats(class_stats_t *, struct rm_class *); |
---|
87 | static void cbq_purge(cbq_state_t *); |
---|
88 | #ifdef ALTQ3_COMPAT |
---|
89 | static int cbq_add_class(struct cbq_add_class *); |
---|
90 | static int cbq_delete_class(struct cbq_delete_class *); |
---|
91 | static int cbq_modify_class(struct cbq_modify_class *); |
---|
92 | static int cbq_class_create(cbq_state_t *, struct cbq_add_class *, |
---|
93 | struct rm_class *, struct rm_class *); |
---|
94 | static int cbq_clear_hierarchy(struct cbq_interface *); |
---|
95 | static int cbq_set_enable(struct cbq_interface *, int); |
---|
96 | static int cbq_ifattach(struct cbq_interface *); |
---|
97 | static int cbq_ifdetach(struct cbq_interface *); |
---|
98 | static int cbq_getstats(struct cbq_getstats *); |
---|
99 | |
---|
100 | static int cbq_add_filter(struct cbq_add_filter *); |
---|
101 | static int cbq_delete_filter(struct cbq_delete_filter *); |
---|
102 | #endif /* ALTQ3_COMPAT */ |
---|
103 | |
---|
104 | /* |
---|
105 | * int |
---|
106 | * cbq_class_destroy(cbq_mod_state_t *, struct rm_class *) - This |
---|
107 | * function destroys a given traffic class. Before destroying |
---|
108 | * the class, all traffic for that class is released. |
---|
109 | */ |
---|
110 | static int |
---|
111 | cbq_class_destroy(cbq_state_t *cbqp, struct rm_class *cl) |
---|
112 | { |
---|
113 | int i; |
---|
114 | |
---|
115 | /* delete the class */ |
---|
116 | rmc_delete_class(&cbqp->ifnp, cl); |
---|
117 | |
---|
118 | /* |
---|
119 | * free the class handle |
---|
120 | */ |
---|
121 | for (i = 0; i < CBQ_MAX_CLASSES; i++) |
---|
122 | if (cbqp->cbq_class_tbl[i] == cl) |
---|
123 | cbqp->cbq_class_tbl[i] = NULL; |
---|
124 | |
---|
125 | if (cl == cbqp->ifnp.root_) |
---|
126 | cbqp->ifnp.root_ = NULL; |
---|
127 | if (cl == cbqp->ifnp.default_) |
---|
128 | cbqp->ifnp.default_ = NULL; |
---|
129 | #ifdef ALTQ3_COMPAT |
---|
130 | if (cl == cbqp->ifnp.ctl_) |
---|
131 | cbqp->ifnp.ctl_ = NULL; |
---|
132 | #endif |
---|
133 | return (0); |
---|
134 | } |
---|
135 | |
---|
136 | /* convert class handle to class pointer */ |
---|
137 | static struct rm_class * |
---|
138 | clh_to_clp(cbq_state_t *cbqp, u_int32_t chandle) |
---|
139 | { |
---|
140 | int i; |
---|
141 | struct rm_class *cl; |
---|
142 | |
---|
143 | if (chandle == 0) |
---|
144 | return (NULL); |
---|
145 | /* |
---|
146 | * first, try optimistically the slot matching the lower bits of |
---|
147 | * the handle. if it fails, do the linear table search. |
---|
148 | */ |
---|
149 | i = chandle % CBQ_MAX_CLASSES; |
---|
150 | if ((cl = cbqp->cbq_class_tbl[i]) != NULL && |
---|
151 | cl->stats_.handle == chandle) |
---|
152 | return (cl); |
---|
153 | for (i = 0; i < CBQ_MAX_CLASSES; i++) |
---|
154 | if ((cl = cbqp->cbq_class_tbl[i]) != NULL && |
---|
155 | cl->stats_.handle == chandle) |
---|
156 | return (cl); |
---|
157 | return (NULL); |
---|
158 | } |
---|
159 | |
---|
160 | static int |
---|
161 | cbq_clear_interface(cbq_state_t *cbqp) |
---|
162 | { |
---|
163 | int again, i; |
---|
164 | struct rm_class *cl; |
---|
165 | |
---|
166 | #ifdef ALTQ3_CLFIER_COMPAT |
---|
167 | /* free the filters for this interface */ |
---|
168 | acc_discard_filters(&cbqp->cbq_classifier, NULL, 1); |
---|
169 | #endif |
---|
170 | |
---|
171 | /* clear out the classes now */ |
---|
172 | do { |
---|
173 | again = 0; |
---|
174 | for (i = 0; i < CBQ_MAX_CLASSES; i++) { |
---|
175 | if ((cl = cbqp->cbq_class_tbl[i]) != NULL) { |
---|
176 | if (is_a_parent_class(cl)) |
---|
177 | again++; |
---|
178 | else { |
---|
179 | cbq_class_destroy(cbqp, cl); |
---|
180 | cbqp->cbq_class_tbl[i] = NULL; |
---|
181 | if (cl == cbqp->ifnp.root_) |
---|
182 | cbqp->ifnp.root_ = NULL; |
---|
183 | if (cl == cbqp->ifnp.default_) |
---|
184 | cbqp->ifnp.default_ = NULL; |
---|
185 | #ifdef ALTQ3_COMPAT |
---|
186 | if (cl == cbqp->ifnp.ctl_) |
---|
187 | cbqp->ifnp.ctl_ = NULL; |
---|
188 | #endif |
---|
189 | } |
---|
190 | } |
---|
191 | } |
---|
192 | } while (again); |
---|
193 | |
---|
194 | return (0); |
---|
195 | } |
---|
196 | |
---|
197 | static int |
---|
198 | cbq_request(struct ifaltq *ifq, int req, void *arg) |
---|
199 | { |
---|
200 | cbq_state_t *cbqp = (cbq_state_t *)ifq->altq_disc; |
---|
201 | |
---|
202 | IFQ_LOCK_ASSERT(ifq); |
---|
203 | |
---|
204 | switch (req) { |
---|
205 | case ALTRQ_PURGE: |
---|
206 | cbq_purge(cbqp); |
---|
207 | break; |
---|
208 | } |
---|
209 | return (0); |
---|
210 | } |
---|
211 | |
---|
212 | /* copy the stats info in rm_class to class_states_t */ |
---|
213 | static void |
---|
214 | get_class_stats(class_stats_t *statsp, struct rm_class *cl) |
---|
215 | { |
---|
216 | statsp->xmit_cnt = cl->stats_.xmit_cnt; |
---|
217 | statsp->drop_cnt = cl->stats_.drop_cnt; |
---|
218 | statsp->over = cl->stats_.over; |
---|
219 | statsp->borrows = cl->stats_.borrows; |
---|
220 | statsp->overactions = cl->stats_.overactions; |
---|
221 | statsp->delays = cl->stats_.delays; |
---|
222 | |
---|
223 | statsp->depth = cl->depth_; |
---|
224 | statsp->priority = cl->pri_; |
---|
225 | statsp->maxidle = cl->maxidle_; |
---|
226 | statsp->minidle = cl->minidle_; |
---|
227 | statsp->offtime = cl->offtime_; |
---|
228 | statsp->qmax = qlimit(cl->q_); |
---|
229 | statsp->ns_per_byte = cl->ns_per_byte_; |
---|
230 | statsp->wrr_allot = cl->w_allotment_; |
---|
231 | statsp->qcnt = qlen(cl->q_); |
---|
232 | statsp->avgidle = cl->avgidle_; |
---|
233 | |
---|
234 | statsp->qtype = qtype(cl->q_); |
---|
235 | #ifdef ALTQ_RED |
---|
236 | if (q_is_red(cl->q_)) |
---|
237 | red_getstats(cl->red_, &statsp->red[0]); |
---|
238 | #endif |
---|
239 | #ifdef ALTQ_RIO |
---|
240 | if (q_is_rio(cl->q_)) |
---|
241 | rio_getstats((rio_t *)cl->red_, &statsp->red[0]); |
---|
242 | #endif |
---|
243 | } |
---|
244 | |
---|
245 | int |
---|
246 | cbq_pfattach(struct pf_altq *a) |
---|
247 | { |
---|
248 | struct ifnet *ifp; |
---|
249 | int s, error; |
---|
250 | |
---|
251 | if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL) |
---|
252 | return (EINVAL); |
---|
253 | #ifdef __NetBSD__ |
---|
254 | s = splnet(); |
---|
255 | #else |
---|
256 | s = splimp(); |
---|
257 | #endif |
---|
258 | error = altq_attach(&ifp->if_snd, ALTQT_CBQ, a->altq_disc, |
---|
259 | cbq_enqueue, cbq_dequeue, cbq_request, NULL, NULL); |
---|
260 | splx(s); |
---|
261 | return (error); |
---|
262 | } |
---|
263 | |
---|
264 | int |
---|
265 | cbq_add_altq(struct pf_altq *a) |
---|
266 | { |
---|
267 | cbq_state_t *cbqp; |
---|
268 | struct ifnet *ifp; |
---|
269 | |
---|
270 | if ((ifp = ifunit(a->ifname)) == NULL) |
---|
271 | return (EINVAL); |
---|
272 | if (!ALTQ_IS_READY(&ifp->if_snd)) |
---|
273 | return (ENODEV); |
---|
274 | |
---|
275 | /* allocate and initialize cbq_state_t */ |
---|
276 | cbqp = malloc(sizeof(cbq_state_t), M_DEVBUF, M_WAITOK); |
---|
277 | if (cbqp == NULL) |
---|
278 | return (ENOMEM); |
---|
279 | bzero(cbqp, sizeof(cbq_state_t)); |
---|
280 | CALLOUT_INIT(&cbqp->cbq_callout); |
---|
281 | cbqp->cbq_qlen = 0; |
---|
282 | cbqp->ifnp.ifq_ = &ifp->if_snd; /* keep the ifq */ |
---|
283 | |
---|
284 | /* keep the state in pf_altq */ |
---|
285 | a->altq_disc = cbqp; |
---|
286 | |
---|
287 | return (0); |
---|
288 | } |
---|
289 | |
---|
290 | int |
---|
291 | cbq_remove_altq(struct pf_altq *a) |
---|
292 | { |
---|
293 | cbq_state_t *cbqp; |
---|
294 | |
---|
295 | if ((cbqp = a->altq_disc) == NULL) |
---|
296 | return (EINVAL); |
---|
297 | a->altq_disc = NULL; |
---|
298 | |
---|
299 | cbq_clear_interface(cbqp); |
---|
300 | |
---|
301 | if (cbqp->ifnp.default_) |
---|
302 | cbq_class_destroy(cbqp, cbqp->ifnp.default_); |
---|
303 | if (cbqp->ifnp.root_) |
---|
304 | cbq_class_destroy(cbqp, cbqp->ifnp.root_); |
---|
305 | |
---|
306 | /* deallocate cbq_state_t */ |
---|
307 | free(cbqp, M_DEVBUF); |
---|
308 | |
---|
309 | return (0); |
---|
310 | } |
---|
311 | |
---|
312 | int |
---|
313 | cbq_add_queue(struct pf_altq *a) |
---|
314 | { |
---|
315 | struct rm_class *borrow, *parent; |
---|
316 | cbq_state_t *cbqp; |
---|
317 | struct rm_class *cl; |
---|
318 | struct cbq_opts *opts; |
---|
319 | int i; |
---|
320 | |
---|
321 | if ((cbqp = a->altq_disc) == NULL) |
---|
322 | return (EINVAL); |
---|
323 | if (a->qid == 0) |
---|
324 | return (EINVAL); |
---|
325 | |
---|
326 | /* |
---|
327 | * find a free slot in the class table. if the slot matching |
---|
328 | * the lower bits of qid is free, use this slot. otherwise, |
---|
329 | * use the first free slot. |
---|
330 | */ |
---|
331 | i = a->qid % CBQ_MAX_CLASSES; |
---|
332 | if (cbqp->cbq_class_tbl[i] != NULL) { |
---|
333 | for (i = 0; i < CBQ_MAX_CLASSES; i++) |
---|
334 | if (cbqp->cbq_class_tbl[i] == NULL) |
---|
335 | break; |
---|
336 | if (i == CBQ_MAX_CLASSES) |
---|
337 | return (EINVAL); |
---|
338 | } |
---|
339 | |
---|
340 | opts = &a->pq_u.cbq_opts; |
---|
341 | /* check parameters */ |
---|
342 | if (a->priority >= CBQ_MAXPRI) |
---|
343 | return (EINVAL); |
---|
344 | |
---|
345 | /* Get pointers to parent and borrow classes. */ |
---|
346 | parent = clh_to_clp(cbqp, a->parent_qid); |
---|
347 | if (opts->flags & CBQCLF_BORROW) |
---|
348 | borrow = parent; |
---|
349 | else |
---|
350 | borrow = NULL; |
---|
351 | |
---|
352 | /* |
---|
353 | * A class must borrow from it's parent or it can not |
---|
354 | * borrow at all. Hence, borrow can be null. |
---|
355 | */ |
---|
356 | if (parent == NULL && (opts->flags & CBQCLF_ROOTCLASS) == 0) { |
---|
357 | printf("cbq_add_queue: no parent class!\n"); |
---|
358 | return (EINVAL); |
---|
359 | } |
---|
360 | |
---|
361 | if ((borrow != parent) && (borrow != NULL)) { |
---|
362 | printf("cbq_add_class: borrow class != parent\n"); |
---|
363 | return (EINVAL); |
---|
364 | } |
---|
365 | |
---|
366 | /* |
---|
367 | * check parameters |
---|
368 | */ |
---|
369 | switch (opts->flags & CBQCLF_CLASSMASK) { |
---|
370 | case CBQCLF_ROOTCLASS: |
---|
371 | if (parent != NULL) |
---|
372 | return (EINVAL); |
---|
373 | if (cbqp->ifnp.root_) |
---|
374 | return (EINVAL); |
---|
375 | break; |
---|
376 | case CBQCLF_DEFCLASS: |
---|
377 | if (cbqp->ifnp.default_) |
---|
378 | return (EINVAL); |
---|
379 | break; |
---|
380 | case 0: |
---|
381 | if (a->qid == 0) |
---|
382 | return (EINVAL); |
---|
383 | break; |
---|
384 | default: |
---|
385 | /* more than two flags bits set */ |
---|
386 | return (EINVAL); |
---|
387 | } |
---|
388 | |
---|
389 | /* |
---|
390 | * create a class. if this is a root class, initialize the |
---|
391 | * interface. |
---|
392 | */ |
---|
393 | if ((opts->flags & CBQCLF_CLASSMASK) == CBQCLF_ROOTCLASS) { |
---|
394 | rmc_init(cbqp->ifnp.ifq_, &cbqp->ifnp, opts->ns_per_byte, |
---|
395 | cbqrestart, a->qlimit, RM_MAXQUEUED, |
---|
396 | opts->maxidle, opts->minidle, opts->offtime, |
---|
397 | opts->flags); |
---|
398 | cl = cbqp->ifnp.root_; |
---|
399 | } else { |
---|
400 | cl = rmc_newclass(a->priority, |
---|
401 | &cbqp->ifnp, opts->ns_per_byte, |
---|
402 | rmc_delay_action, a->qlimit, parent, borrow, |
---|
403 | opts->maxidle, opts->minidle, opts->offtime, |
---|
404 | opts->pktsize, opts->flags); |
---|
405 | } |
---|
406 | if (cl == NULL) |
---|
407 | return (ENOMEM); |
---|
408 | |
---|
409 | /* return handle to user space. */ |
---|
410 | cl->stats_.handle = a->qid; |
---|
411 | cl->stats_.depth = cl->depth_; |
---|
412 | |
---|
413 | /* save the allocated class */ |
---|
414 | cbqp->cbq_class_tbl[i] = cl; |
---|
415 | |
---|
416 | if ((opts->flags & CBQCLF_CLASSMASK) == CBQCLF_DEFCLASS) |
---|
417 | cbqp->ifnp.default_ = cl; |
---|
418 | |
---|
419 | return (0); |
---|
420 | } |
---|
421 | |
---|
422 | int |
---|
423 | cbq_remove_queue(struct pf_altq *a) |
---|
424 | { |
---|
425 | struct rm_class *cl; |
---|
426 | cbq_state_t *cbqp; |
---|
427 | int i; |
---|
428 | |
---|
429 | if ((cbqp = a->altq_disc) == NULL) |
---|
430 | return (EINVAL); |
---|
431 | |
---|
432 | if ((cl = clh_to_clp(cbqp, a->qid)) == NULL) |
---|
433 | return (EINVAL); |
---|
434 | |
---|
435 | /* if we are a parent class, then return an error. */ |
---|
436 | if (is_a_parent_class(cl)) |
---|
437 | return (EINVAL); |
---|
438 | |
---|
439 | /* delete the class */ |
---|
440 | rmc_delete_class(&cbqp->ifnp, cl); |
---|
441 | |
---|
442 | /* |
---|
443 | * free the class handle |
---|
444 | */ |
---|
445 | for (i = 0; i < CBQ_MAX_CLASSES; i++) |
---|
446 | if (cbqp->cbq_class_tbl[i] == cl) { |
---|
447 | cbqp->cbq_class_tbl[i] = NULL; |
---|
448 | if (cl == cbqp->ifnp.root_) |
---|
449 | cbqp->ifnp.root_ = NULL; |
---|
450 | if (cl == cbqp->ifnp.default_) |
---|
451 | cbqp->ifnp.default_ = NULL; |
---|
452 | break; |
---|
453 | } |
---|
454 | |
---|
455 | return (0); |
---|
456 | } |
---|
457 | |
---|
458 | int |
---|
459 | cbq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) |
---|
460 | { |
---|
461 | cbq_state_t *cbqp; |
---|
462 | struct rm_class *cl; |
---|
463 | class_stats_t stats; |
---|
464 | int error = 0; |
---|
465 | |
---|
466 | if ((cbqp = altq_lookup(a->ifname, ALTQT_CBQ)) == NULL) |
---|
467 | return (EBADF); |
---|
468 | |
---|
469 | if ((cl = clh_to_clp(cbqp, a->qid)) == NULL) |
---|
470 | return (EINVAL); |
---|
471 | |
---|
472 | if (*nbytes < sizeof(stats)) |
---|
473 | return (EINVAL); |
---|
474 | |
---|
475 | get_class_stats(&stats, cl); |
---|
476 | |
---|
477 | if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0) |
---|
478 | return (error); |
---|
479 | *nbytes = sizeof(stats); |
---|
480 | return (0); |
---|
481 | } |
---|
482 | |
---|
483 | /* |
---|
484 | * int |
---|
485 | * cbq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pattr) |
---|
486 | * - Queue data packets. |
---|
487 | * |
---|
488 | * cbq_enqueue is set to ifp->if_altqenqueue and called by an upper |
---|
489 | * layer (e.g. ether_output). cbq_enqueue queues the given packet |
---|
490 | * to the cbq, then invokes the driver's start routine. |
---|
491 | * |
---|
492 | * Assumptions: called in splimp |
---|
493 | * Returns: 0 if the queueing is successful. |
---|
494 | * ENOBUFS if a packet dropping occurred as a result of |
---|
495 | * the queueing. |
---|
496 | */ |
---|
497 | |
---|
498 | static int |
---|
499 | cbq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr) |
---|
500 | { |
---|
501 | cbq_state_t *cbqp = (cbq_state_t *)ifq->altq_disc; |
---|
502 | struct rm_class *cl; |
---|
503 | struct pf_mtag *t; |
---|
504 | int len; |
---|
505 | |
---|
506 | IFQ_LOCK_ASSERT(ifq); |
---|
507 | |
---|
508 | /* grab class set by classifier */ |
---|
509 | if ((m->m_flags & M_PKTHDR) == 0) { |
---|
510 | /* should not happen */ |
---|
511 | printf("altq: packet for %s does not have pkthdr\n", |
---|
512 | ifq->altq_ifp->if_xname); |
---|
513 | m_freem(m); |
---|
514 | return (ENOBUFS); |
---|
515 | } |
---|
516 | cl = NULL; |
---|
517 | if ((t = pf_find_mtag(m)) != NULL) |
---|
518 | cl = clh_to_clp(cbqp, t->qid); |
---|
519 | #ifdef ALTQ3_COMPAT |
---|
520 | else if ((ifq->altq_flags & ALTQF_CLASSIFY) && pktattr != NULL) |
---|
521 | cl = pktattr->pattr_class; |
---|
522 | #endif |
---|
523 | if (cl == NULL) { |
---|
524 | cl = cbqp->ifnp.default_; |
---|
525 | if (cl == NULL) { |
---|
526 | m_freem(m); |
---|
527 | return (ENOBUFS); |
---|
528 | } |
---|
529 | } |
---|
530 | #ifdef ALTQ3_COMPAT |
---|
531 | if (pktattr != NULL) |
---|
532 | cl->pktattr_ = pktattr; /* save proto hdr used by ECN */ |
---|
533 | else |
---|
534 | #endif |
---|
535 | cl->pktattr_ = NULL; |
---|
536 | len = m_pktlen(m); |
---|
537 | if (rmc_queue_packet(cl, m) != 0) { |
---|
538 | /* drop occurred. some mbuf was freed in rmc_queue_packet. */ |
---|
539 | PKTCNTR_ADD(&cl->stats_.drop_cnt, len); |
---|
540 | return (ENOBUFS); |
---|
541 | } |
---|
542 | |
---|
543 | /* successfully queued. */ |
---|
544 | ++cbqp->cbq_qlen; |
---|
545 | IFQ_INC_LEN(ifq); |
---|
546 | return (0); |
---|
547 | } |
---|
548 | |
---|
549 | static struct mbuf * |
---|
550 | cbq_dequeue(struct ifaltq *ifq, int op) |
---|
551 | { |
---|
552 | cbq_state_t *cbqp = (cbq_state_t *)ifq->altq_disc; |
---|
553 | struct mbuf *m; |
---|
554 | |
---|
555 | IFQ_LOCK_ASSERT(ifq); |
---|
556 | |
---|
557 | m = rmc_dequeue_next(&cbqp->ifnp, op); |
---|
558 | |
---|
559 | if (m && op == ALTDQ_REMOVE) { |
---|
560 | --cbqp->cbq_qlen; /* decrement # of packets in cbq */ |
---|
561 | IFQ_DEC_LEN(ifq); |
---|
562 | |
---|
563 | /* Update the class. */ |
---|
564 | rmc_update_class_util(&cbqp->ifnp); |
---|
565 | } |
---|
566 | return (m); |
---|
567 | } |
---|
568 | |
---|
569 | /* |
---|
570 | * void |
---|
571 | * cbqrestart(queue_t *) - Restart sending of data. |
---|
572 | * called from rmc_restart in splimp via timeout after waking up |
---|
573 | * a suspended class. |
---|
574 | * Returns: NONE |
---|
575 | */ |
---|
576 | |
---|
577 | static void |
---|
578 | cbqrestart(struct ifaltq *ifq) |
---|
579 | { |
---|
580 | cbq_state_t *cbqp; |
---|
581 | struct ifnet *ifp; |
---|
582 | |
---|
583 | IFQ_LOCK_ASSERT(ifq); |
---|
584 | |
---|
585 | if (!ALTQ_IS_ENABLED(ifq)) |
---|
586 | /* cbq must have been detached */ |
---|
587 | return; |
---|
588 | |
---|
589 | if ((cbqp = (cbq_state_t *)ifq->altq_disc) == NULL) |
---|
590 | /* should not happen */ |
---|
591 | return; |
---|
592 | |
---|
593 | ifp = ifq->altq_ifp; |
---|
594 | if (ifp->if_start && |
---|
595 | cbqp->cbq_qlen > 0 && (ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { |
---|
596 | IFQ_UNLOCK(ifq); |
---|
597 | (*ifp->if_start)(ifp); |
---|
598 | IFQ_LOCK(ifq); |
---|
599 | } |
---|
600 | } |
---|
601 | |
---|
602 | static void cbq_purge(cbq_state_t *cbqp) |
---|
603 | { |
---|
604 | struct rm_class *cl; |
---|
605 | int i; |
---|
606 | |
---|
607 | for (i = 0; i < CBQ_MAX_CLASSES; i++) |
---|
608 | if ((cl = cbqp->cbq_class_tbl[i]) != NULL) |
---|
609 | rmc_dropall(cl); |
---|
610 | if (ALTQ_IS_ENABLED(cbqp->ifnp.ifq_)) |
---|
611 | cbqp->ifnp.ifq_->ifq_len = 0; |
---|
612 | } |
---|
613 | #ifdef ALTQ3_COMPAT |
---|
614 | |
---|
615 | static int |
---|
616 | cbq_add_class(acp) |
---|
617 | struct cbq_add_class *acp; |
---|
618 | { |
---|
619 | char *ifacename; |
---|
620 | struct rm_class *borrow, *parent; |
---|
621 | cbq_state_t *cbqp; |
---|
622 | |
---|
623 | ifacename = acp->cbq_iface.cbq_ifacename; |
---|
624 | if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL) |
---|
625 | return (EBADF); |
---|
626 | |
---|
627 | /* check parameters */ |
---|
628 | if (acp->cbq_class.priority >= CBQ_MAXPRI || |
---|
629 | acp->cbq_class.maxq > CBQ_MAXQSIZE) |
---|
630 | return (EINVAL); |
---|
631 | |
---|
632 | /* Get pointers to parent and borrow classes. */ |
---|
633 | parent = clh_to_clp(cbqp, acp->cbq_class.parent_class_handle); |
---|
634 | borrow = clh_to_clp(cbqp, acp->cbq_class.borrow_class_handle); |
---|
635 | |
---|
636 | /* |
---|
637 | * A class must borrow from it's parent or it can not |
---|
638 | * borrow at all. Hence, borrow can be null. |
---|
639 | */ |
---|
640 | if (parent == NULL && (acp->cbq_class.flags & CBQCLF_ROOTCLASS) == 0) { |
---|
641 | printf("cbq_add_class: no parent class!\n"); |
---|
642 | return (EINVAL); |
---|
643 | } |
---|
644 | |
---|
645 | if ((borrow != parent) && (borrow != NULL)) { |
---|
646 | printf("cbq_add_class: borrow class != parent\n"); |
---|
647 | return (EINVAL); |
---|
648 | } |
---|
649 | |
---|
650 | return cbq_class_create(cbqp, acp, parent, borrow); |
---|
651 | } |
---|
652 | |
---|
653 | static int |
---|
654 | cbq_delete_class(dcp) |
---|
655 | struct cbq_delete_class *dcp; |
---|
656 | { |
---|
657 | char *ifacename; |
---|
658 | struct rm_class *cl; |
---|
659 | cbq_state_t *cbqp; |
---|
660 | |
---|
661 | ifacename = dcp->cbq_iface.cbq_ifacename; |
---|
662 | if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL) |
---|
663 | return (EBADF); |
---|
664 | |
---|
665 | if ((cl = clh_to_clp(cbqp, dcp->cbq_class_handle)) == NULL) |
---|
666 | return (EINVAL); |
---|
667 | |
---|
668 | /* if we are a parent class, then return an error. */ |
---|
669 | if (is_a_parent_class(cl)) |
---|
670 | return (EINVAL); |
---|
671 | |
---|
672 | /* if a filter has a reference to this class delete the filter */ |
---|
673 | acc_discard_filters(&cbqp->cbq_classifier, cl, 0); |
---|
674 | |
---|
675 | return cbq_class_destroy(cbqp, cl); |
---|
676 | } |
---|
677 | |
---|
678 | static int |
---|
679 | cbq_modify_class(acp) |
---|
680 | struct cbq_modify_class *acp; |
---|
681 | { |
---|
682 | char *ifacename; |
---|
683 | struct rm_class *cl; |
---|
684 | cbq_state_t *cbqp; |
---|
685 | |
---|
686 | ifacename = acp->cbq_iface.cbq_ifacename; |
---|
687 | if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL) |
---|
688 | return (EBADF); |
---|
689 | |
---|
690 | /* Get pointer to this class */ |
---|
691 | if ((cl = clh_to_clp(cbqp, acp->cbq_class_handle)) == NULL) |
---|
692 | return (EINVAL); |
---|
693 | |
---|
694 | if (rmc_modclass(cl, acp->cbq_class.nano_sec_per_byte, |
---|
695 | acp->cbq_class.maxq, acp->cbq_class.maxidle, |
---|
696 | acp->cbq_class.minidle, acp->cbq_class.offtime, |
---|
697 | acp->cbq_class.pktsize) < 0) |
---|
698 | return (EINVAL); |
---|
699 | return (0); |
---|
700 | } |
---|
701 | |
---|
702 | /* |
---|
703 | * struct rm_class * |
---|
704 | * cbq_class_create(cbq_mod_state_t *cbqp, struct cbq_add_class *acp, |
---|
705 | * struct rm_class *parent, struct rm_class *borrow) |
---|
706 | * |
---|
707 | * This function create a new traffic class in the CBQ class hierarchy of |
---|
708 | * given paramters. The class that created is either the root, default, |
---|
709 | * or a new dynamic class. If CBQ is not initilaized, the the root class |
---|
710 | * will be created. |
---|
711 | */ |
---|
712 | static int |
---|
713 | cbq_class_create(cbqp, acp, parent, borrow) |
---|
714 | cbq_state_t *cbqp; |
---|
715 | struct cbq_add_class *acp; |
---|
716 | struct rm_class *parent, *borrow; |
---|
717 | { |
---|
718 | struct rm_class *cl; |
---|
719 | cbq_class_spec_t *spec = &acp->cbq_class; |
---|
720 | u_int32_t chandle; |
---|
721 | int i; |
---|
722 | |
---|
723 | /* |
---|
724 | * allocate class handle |
---|
725 | */ |
---|
726 | for (i = 1; i < CBQ_MAX_CLASSES; i++) |
---|
727 | if (cbqp->cbq_class_tbl[i] == NULL) |
---|
728 | break; |
---|
729 | if (i == CBQ_MAX_CLASSES) |
---|
730 | return (EINVAL); |
---|
731 | chandle = i; /* use the slot number as class handle */ |
---|
732 | |
---|
733 | /* |
---|
734 | * create a class. if this is a root class, initialize the |
---|
735 | * interface. |
---|
736 | */ |
---|
737 | if ((spec->flags & CBQCLF_CLASSMASK) == CBQCLF_ROOTCLASS) { |
---|
738 | rmc_init(cbqp->ifnp.ifq_, &cbqp->ifnp, spec->nano_sec_per_byte, |
---|
739 | cbqrestart, spec->maxq, RM_MAXQUEUED, |
---|
740 | spec->maxidle, spec->minidle, spec->offtime, |
---|
741 | spec->flags); |
---|
742 | cl = cbqp->ifnp.root_; |
---|
743 | } else { |
---|
744 | cl = rmc_newclass(spec->priority, |
---|
745 | &cbqp->ifnp, spec->nano_sec_per_byte, |
---|
746 | rmc_delay_action, spec->maxq, parent, borrow, |
---|
747 | spec->maxidle, spec->minidle, spec->offtime, |
---|
748 | spec->pktsize, spec->flags); |
---|
749 | } |
---|
750 | if (cl == NULL) |
---|
751 | return (ENOMEM); |
---|
752 | |
---|
753 | /* return handle to user space. */ |
---|
754 | acp->cbq_class_handle = chandle; |
---|
755 | |
---|
756 | cl->stats_.handle = chandle; |
---|
757 | cl->stats_.depth = cl->depth_; |
---|
758 | |
---|
759 | /* save the allocated class */ |
---|
760 | cbqp->cbq_class_tbl[i] = cl; |
---|
761 | |
---|
762 | if ((spec->flags & CBQCLF_CLASSMASK) == CBQCLF_DEFCLASS) |
---|
763 | cbqp->ifnp.default_ = cl; |
---|
764 | if ((spec->flags & CBQCLF_CLASSMASK) == CBQCLF_CTLCLASS) |
---|
765 | cbqp->ifnp.ctl_ = cl; |
---|
766 | |
---|
767 | return (0); |
---|
768 | } |
---|
769 | |
---|
770 | static int |
---|
771 | cbq_add_filter(afp) |
---|
772 | struct cbq_add_filter *afp; |
---|
773 | { |
---|
774 | char *ifacename; |
---|
775 | cbq_state_t *cbqp; |
---|
776 | struct rm_class *cl; |
---|
777 | |
---|
778 | ifacename = afp->cbq_iface.cbq_ifacename; |
---|
779 | if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL) |
---|
780 | return (EBADF); |
---|
781 | |
---|
782 | /* Get the pointer to class. */ |
---|
783 | if ((cl = clh_to_clp(cbqp, afp->cbq_class_handle)) == NULL) |
---|
784 | return (EINVAL); |
---|
785 | |
---|
786 | return acc_add_filter(&cbqp->cbq_classifier, &afp->cbq_filter, |
---|
787 | cl, &afp->cbq_filter_handle); |
---|
788 | } |
---|
789 | |
---|
790 | static int |
---|
791 | cbq_delete_filter(dfp) |
---|
792 | struct cbq_delete_filter *dfp; |
---|
793 | { |
---|
794 | char *ifacename; |
---|
795 | cbq_state_t *cbqp; |
---|
796 | |
---|
797 | ifacename = dfp->cbq_iface.cbq_ifacename; |
---|
798 | if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL) |
---|
799 | return (EBADF); |
---|
800 | |
---|
801 | return acc_delete_filter(&cbqp->cbq_classifier, |
---|
802 | dfp->cbq_filter_handle); |
---|
803 | } |
---|
804 | |
---|
805 | /* |
---|
806 | * cbq_clear_hierarchy deletes all classes and their filters on the |
---|
807 | * given interface. |
---|
808 | */ |
---|
809 | static int |
---|
810 | cbq_clear_hierarchy(ifacep) |
---|
811 | struct cbq_interface *ifacep; |
---|
812 | { |
---|
813 | char *ifacename; |
---|
814 | cbq_state_t *cbqp; |
---|
815 | |
---|
816 | ifacename = ifacep->cbq_ifacename; |
---|
817 | if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL) |
---|
818 | return (EBADF); |
---|
819 | |
---|
820 | return cbq_clear_interface(cbqp); |
---|
821 | } |
---|
822 | |
---|
823 | /* |
---|
824 | * static int |
---|
825 | * cbq_set_enable(struct cbq_enable *ep) - this function processed the |
---|
826 | * ioctl request to enable class based queueing. It searches the list |
---|
827 | * of interfaces for the specified interface and then enables CBQ on |
---|
828 | * that interface. |
---|
829 | * |
---|
830 | * Returns: 0, for no error. |
---|
831 | * EBADF, for specified inteface not found. |
---|
832 | */ |
---|
833 | |
---|
834 | static int |
---|
835 | cbq_set_enable(ep, enable) |
---|
836 | struct cbq_interface *ep; |
---|
837 | int enable; |
---|
838 | { |
---|
839 | int error = 0; |
---|
840 | cbq_state_t *cbqp; |
---|
841 | char *ifacename; |
---|
842 | |
---|
843 | ifacename = ep->cbq_ifacename; |
---|
844 | if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL) |
---|
845 | return (EBADF); |
---|
846 | |
---|
847 | switch (enable) { |
---|
848 | case ENABLE: |
---|
849 | if (cbqp->ifnp.root_ == NULL || cbqp->ifnp.default_ == NULL || |
---|
850 | cbqp->ifnp.ctl_ == NULL) { |
---|
851 | if (cbqp->ifnp.root_ == NULL) |
---|
852 | printf("No Root Class for %s\n", ifacename); |
---|
853 | if (cbqp->ifnp.default_ == NULL) |
---|
854 | printf("No Default Class for %s\n", ifacename); |
---|
855 | if (cbqp->ifnp.ctl_ == NULL) |
---|
856 | printf("No Control Class for %s\n", ifacename); |
---|
857 | error = EINVAL; |
---|
858 | } else if ((error = altq_enable(cbqp->ifnp.ifq_)) == 0) { |
---|
859 | cbqp->cbq_qlen = 0; |
---|
860 | } |
---|
861 | break; |
---|
862 | |
---|
863 | case DISABLE: |
---|
864 | error = altq_disable(cbqp->ifnp.ifq_); |
---|
865 | break; |
---|
866 | } |
---|
867 | return (error); |
---|
868 | } |
---|
869 | |
---|
870 | static int |
---|
871 | cbq_getstats(gsp) |
---|
872 | struct cbq_getstats *gsp; |
---|
873 | { |
---|
874 | char *ifacename; |
---|
875 | int i, n, nclasses; |
---|
876 | cbq_state_t *cbqp; |
---|
877 | struct rm_class *cl; |
---|
878 | class_stats_t stats, *usp; |
---|
879 | int error = 0; |
---|
880 | |
---|
881 | ifacename = gsp->iface.cbq_ifacename; |
---|
882 | nclasses = gsp->nclasses; |
---|
883 | usp = gsp->stats; |
---|
884 | |
---|
885 | if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL) |
---|
886 | return (EBADF); |
---|
887 | if (nclasses <= 0) |
---|
888 | return (EINVAL); |
---|
889 | |
---|
890 | for (n = 0, i = 0; n < nclasses && i < CBQ_MAX_CLASSES; n++, i++) { |
---|
891 | while ((cl = cbqp->cbq_class_tbl[i]) == NULL) |
---|
892 | if (++i >= CBQ_MAX_CLASSES) |
---|
893 | goto out; |
---|
894 | |
---|
895 | get_class_stats(&stats, cl); |
---|
896 | stats.handle = cl->stats_.handle; |
---|
897 | |
---|
898 | if ((error = copyout((caddr_t)&stats, (caddr_t)usp++, |
---|
899 | sizeof(stats))) != 0) |
---|
900 | return (error); |
---|
901 | } |
---|
902 | |
---|
903 | out: |
---|
904 | gsp->nclasses = n; |
---|
905 | return (error); |
---|
906 | } |
---|
907 | |
---|
908 | static int |
---|
909 | cbq_ifattach(ifacep) |
---|
910 | struct cbq_interface *ifacep; |
---|
911 | { |
---|
912 | int error = 0; |
---|
913 | char *ifacename; |
---|
914 | cbq_state_t *new_cbqp; |
---|
915 | struct ifnet *ifp; |
---|
916 | |
---|
917 | ifacename = ifacep->cbq_ifacename; |
---|
918 | if ((ifp = ifunit(ifacename)) == NULL) |
---|
919 | return (ENXIO); |
---|
920 | if (!ALTQ_IS_READY(&ifp->if_snd)) |
---|
921 | return (ENXIO); |
---|
922 | |
---|
923 | /* allocate and initialize cbq_state_t */ |
---|
924 | new_cbqp = malloc(sizeof(cbq_state_t), M_DEVBUF, M_WAITOK); |
---|
925 | if (new_cbqp == NULL) |
---|
926 | return (ENOMEM); |
---|
927 | bzero(new_cbqp, sizeof(cbq_state_t)); |
---|
928 | CALLOUT_INIT(&new_cbqp->cbq_callout); |
---|
929 | |
---|
930 | new_cbqp->cbq_qlen = 0; |
---|
931 | new_cbqp->ifnp.ifq_ = &ifp->if_snd; /* keep the ifq */ |
---|
932 | |
---|
933 | /* |
---|
934 | * set CBQ to this ifnet structure. |
---|
935 | */ |
---|
936 | error = altq_attach(&ifp->if_snd, ALTQT_CBQ, new_cbqp, |
---|
937 | cbq_enqueue, cbq_dequeue, cbq_request, |
---|
938 | &new_cbqp->cbq_classifier, acc_classify); |
---|
939 | if (error) { |
---|
940 | free(new_cbqp, M_DEVBUF); |
---|
941 | return (error); |
---|
942 | } |
---|
943 | |
---|
944 | /* prepend to the list of cbq_state_t's. */ |
---|
945 | new_cbqp->cbq_next = cbq_list; |
---|
946 | cbq_list = new_cbqp; |
---|
947 | |
---|
948 | return (0); |
---|
949 | } |
---|
950 | |
---|
951 | static int |
---|
952 | cbq_ifdetach(ifacep) |
---|
953 | struct cbq_interface *ifacep; |
---|
954 | { |
---|
955 | char *ifacename; |
---|
956 | cbq_state_t *cbqp; |
---|
957 | |
---|
958 | ifacename = ifacep->cbq_ifacename; |
---|
959 | if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL) |
---|
960 | return (EBADF); |
---|
961 | |
---|
962 | (void)cbq_set_enable(ifacep, DISABLE); |
---|
963 | |
---|
964 | cbq_clear_interface(cbqp); |
---|
965 | |
---|
966 | /* remove CBQ from the ifnet structure. */ |
---|
967 | (void)altq_detach(cbqp->ifnp.ifq_); |
---|
968 | |
---|
969 | /* remove from the list of cbq_state_t's. */ |
---|
970 | if (cbq_list == cbqp) |
---|
971 | cbq_list = cbqp->cbq_next; |
---|
972 | else { |
---|
973 | cbq_state_t *cp; |
---|
974 | |
---|
975 | for (cp = cbq_list; cp != NULL; cp = cp->cbq_next) |
---|
976 | if (cp->cbq_next == cbqp) { |
---|
977 | cp->cbq_next = cbqp->cbq_next; |
---|
978 | break; |
---|
979 | } |
---|
980 | ASSERT(cp != NULL); |
---|
981 | } |
---|
982 | |
---|
983 | /* deallocate cbq_state_t */ |
---|
984 | free(cbqp, M_DEVBUF); |
---|
985 | |
---|
986 | return (0); |
---|
987 | } |
---|
988 | |
---|
989 | /* |
---|
990 | * cbq device interface |
---|
991 | */ |
---|
992 | |
---|
993 | altqdev_decl(cbq); |
---|
994 | |
---|
995 | int |
---|
996 | cbqopen(dev, flag, fmt, p) |
---|
997 | dev_t dev; |
---|
998 | int flag, fmt; |
---|
999 | #if (__FreeBSD_version > 500000) |
---|
1000 | struct thread *p; |
---|
1001 | #else |
---|
1002 | struct proc *p; |
---|
1003 | #endif |
---|
1004 | { |
---|
1005 | return (0); |
---|
1006 | } |
---|
1007 | |
---|
1008 | int |
---|
1009 | cbqclose(dev, flag, fmt, p) |
---|
1010 | dev_t dev; |
---|
1011 | int flag, fmt; |
---|
1012 | #if (__FreeBSD_version > 500000) |
---|
1013 | struct thread *p; |
---|
1014 | #else |
---|
1015 | struct proc *p; |
---|
1016 | #endif |
---|
1017 | { |
---|
1018 | struct ifnet *ifp; |
---|
1019 | struct cbq_interface iface; |
---|
1020 | int err, error = 0; |
---|
1021 | |
---|
1022 | while (cbq_list) { |
---|
1023 | ifp = cbq_list->ifnp.ifq_->altq_ifp; |
---|
1024 | sprintf(iface.cbq_ifacename, "%s", ifp->if_xname); |
---|
1025 | err = cbq_ifdetach(&iface); |
---|
1026 | if (err != 0 && error == 0) |
---|
1027 | error = err; |
---|
1028 | } |
---|
1029 | |
---|
1030 | return (error); |
---|
1031 | } |
---|
1032 | |
---|
1033 | int |
---|
1034 | cbqioctl(dev, cmd, addr, flag, p) |
---|
1035 | dev_t dev; |
---|
1036 | ioctlcmd_t cmd; |
---|
1037 | caddr_t addr; |
---|
1038 | int flag; |
---|
1039 | #if (__FreeBSD_version > 500000) |
---|
1040 | struct thread *p; |
---|
1041 | #else |
---|
1042 | struct proc *p; |
---|
1043 | #endif |
---|
1044 | { |
---|
1045 | int error = 0; |
---|
1046 | |
---|
1047 | /* check cmd for superuser only */ |
---|
1048 | switch (cmd) { |
---|
1049 | case CBQ_GETSTATS: |
---|
1050 | /* currently only command that an ordinary user can call */ |
---|
1051 | break; |
---|
1052 | default: |
---|
1053 | #if (__FreeBSD_version > 700000) |
---|
1054 | error = priv_check(p, PRIV_ALTQ_MANAGE); |
---|
1055 | #elsif (__FreeBSD_version > 400000) |
---|
1056 | error = suser(p); |
---|
1057 | #else |
---|
1058 | error = suser(p->p_ucred, &p->p_acflag); |
---|
1059 | #endif |
---|
1060 | if (error) |
---|
1061 | return (error); |
---|
1062 | break; |
---|
1063 | } |
---|
1064 | |
---|
1065 | switch (cmd) { |
---|
1066 | |
---|
1067 | case CBQ_ENABLE: |
---|
1068 | error = cbq_set_enable((struct cbq_interface *)addr, ENABLE); |
---|
1069 | break; |
---|
1070 | |
---|
1071 | case CBQ_DISABLE: |
---|
1072 | error = cbq_set_enable((struct cbq_interface *)addr, DISABLE); |
---|
1073 | break; |
---|
1074 | |
---|
1075 | case CBQ_ADD_FILTER: |
---|
1076 | error = cbq_add_filter((struct cbq_add_filter *)addr); |
---|
1077 | break; |
---|
1078 | |
---|
1079 | case CBQ_DEL_FILTER: |
---|
1080 | error = cbq_delete_filter((struct cbq_delete_filter *)addr); |
---|
1081 | break; |
---|
1082 | |
---|
1083 | case CBQ_ADD_CLASS: |
---|
1084 | error = cbq_add_class((struct cbq_add_class *)addr); |
---|
1085 | break; |
---|
1086 | |
---|
1087 | case CBQ_DEL_CLASS: |
---|
1088 | error = cbq_delete_class((struct cbq_delete_class *)addr); |
---|
1089 | break; |
---|
1090 | |
---|
1091 | case CBQ_MODIFY_CLASS: |
---|
1092 | error = cbq_modify_class((struct cbq_modify_class *)addr); |
---|
1093 | break; |
---|
1094 | |
---|
1095 | case CBQ_CLEAR_HIERARCHY: |
---|
1096 | error = cbq_clear_hierarchy((struct cbq_interface *)addr); |
---|
1097 | break; |
---|
1098 | |
---|
1099 | case CBQ_IF_ATTACH: |
---|
1100 | error = cbq_ifattach((struct cbq_interface *)addr); |
---|
1101 | break; |
---|
1102 | |
---|
1103 | case CBQ_IF_DETACH: |
---|
1104 | error = cbq_ifdetach((struct cbq_interface *)addr); |
---|
1105 | break; |
---|
1106 | |
---|
1107 | case CBQ_GETSTATS: |
---|
1108 | error = cbq_getstats((struct cbq_getstats *)addr); |
---|
1109 | break; |
---|
1110 | |
---|
1111 | default: |
---|
1112 | error = EINVAL; |
---|
1113 | break; |
---|
1114 | } |
---|
1115 | |
---|
1116 | return error; |
---|
1117 | } |
---|
1118 | |
---|
1119 | #if 0 |
---|
1120 | /* for debug */ |
---|
1121 | static void cbq_class_dump(int); |
---|
1122 | |
---|
1123 | static void cbq_class_dump(i) |
---|
1124 | int i; |
---|
1125 | { |
---|
1126 | struct rm_class *cl; |
---|
1127 | rm_class_stats_t *s; |
---|
1128 | struct _class_queue_ *q; |
---|
1129 | |
---|
1130 | if (cbq_list == NULL) { |
---|
1131 | printf("cbq_class_dump: no cbq_state found\n"); |
---|
1132 | return; |
---|
1133 | } |
---|
1134 | cl = cbq_list->cbq_class_tbl[i]; |
---|
1135 | |
---|
1136 | printf("class %d cl=%p\n", i, cl); |
---|
1137 | if (cl != NULL) { |
---|
1138 | s = &cl->stats_; |
---|
1139 | q = cl->q_; |
---|
1140 | |
---|
1141 | printf("pri=%d, depth=%d, maxrate=%d, allotment=%d\n", |
---|
1142 | cl->pri_, cl->depth_, cl->maxrate_, cl->allotment_); |
---|
1143 | printf("w_allotment=%d, bytes_alloc=%d, avgidle=%d, maxidle=%d\n", |
---|
1144 | cl->w_allotment_, cl->bytes_alloc_, cl->avgidle_, |
---|
1145 | cl->maxidle_); |
---|
1146 | printf("minidle=%d, offtime=%d, sleeping=%d, leaf=%d\n", |
---|
1147 | cl->minidle_, cl->offtime_, cl->sleeping_, cl->leaf_); |
---|
1148 | printf("handle=%d, depth=%d, packets=%d, bytes=%d\n", |
---|
1149 | s->handle, s->depth, |
---|
1150 | (int)s->xmit_cnt.packets, (int)s->xmit_cnt.bytes); |
---|
1151 | printf("over=%d\n, borrows=%d, drops=%d, overactions=%d, delays=%d\n", |
---|
1152 | s->over, s->borrows, (int)s->drop_cnt.packets, |
---|
1153 | s->overactions, s->delays); |
---|
1154 | printf("tail=%p, head=%p, qlen=%d, qlim=%d, qthresh=%d,qtype=%d\n", |
---|
1155 | q->tail_, q->head_, q->qlen_, q->qlim_, |
---|
1156 | q->qthresh_, q->qtype_); |
---|
1157 | } |
---|
1158 | } |
---|
1159 | #endif /* 0 */ |
---|
1160 | |
---|
1161 | #ifdef KLD_MODULE |
---|
1162 | |
---|
1163 | static struct altqsw cbq_sw = |
---|
1164 | {"cbq", cbqopen, cbqclose, cbqioctl}; |
---|
1165 | |
---|
1166 | ALTQ_MODULE(altq_cbq, ALTQT_CBQ, &cbq_sw); |
---|
1167 | MODULE_DEPEND(altq_cbq, altq_red, 1, 1, 1); |
---|
1168 | MODULE_DEPEND(altq_cbq, altq_rio, 1, 1, 1); |
---|
1169 | |
---|
1170 | #endif /* KLD_MODULE */ |
---|
1171 | #endif /* ALTQ3_COMPAT */ |
---|
1172 | |
---|
1173 | #endif /* ALTQ_CBQ */ |
---|