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