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