source: rtems-libbsd/freebsd/contrib/altq/rtems/freebsd/altq/altq_cbq.c @ e2d2bf5

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since e2d2bf5 was e2d2bf5, checked in by Joel Sherrill <joel.sherrill@…>, on 03/08/12 at 13:25:21

Move rtems/freebsd to freebsd and contrib to freebsd/contrib

  • Property mode set to 100644
File size: 27.4 KB
Line 
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 */
74static cbq_state_t *cbq_list = NULL;
75#endif
76
77/*
78 * Forward Declarations.
79 */
80static int               cbq_class_destroy(cbq_state_t *, struct rm_class *);
81static struct rm_class  *clh_to_clp(cbq_state_t *, u_int32_t);
82static int               cbq_clear_interface(cbq_state_t *);
83static int               cbq_request(struct ifaltq *, int, void *);
84static int               cbq_enqueue(struct ifaltq *, struct mbuf *,
85                             struct altq_pktattr *);
86static struct mbuf      *cbq_dequeue(struct ifaltq *, int);
87static void              cbqrestart(struct ifaltq *);
88static void              get_class_stats(class_stats_t *, struct rm_class *);
89static void              cbq_purge(cbq_state_t *);
90#ifdef ALTQ3_COMPAT
91static int      cbq_add_class(struct cbq_add_class *);
92static int      cbq_delete_class(struct cbq_delete_class *);
93static int      cbq_modify_class(struct cbq_modify_class *);
94static int      cbq_class_create(cbq_state_t *, struct cbq_add_class *,
95                                 struct rm_class *, struct rm_class *);
96static int      cbq_clear_hierarchy(struct cbq_interface *);
97static int      cbq_set_enable(struct cbq_interface *, int);
98static int      cbq_ifattach(struct cbq_interface *);
99static int      cbq_ifdetach(struct cbq_interface *);
100static int      cbq_getstats(struct cbq_getstats *);
101
102static int      cbq_add_filter(struct cbq_add_filter *);
103static 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 */
112static int
113cbq_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 */
139static struct rm_class *
140clh_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
162static int
163cbq_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
199static int
200cbq_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 */
215static void
216get_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
247int
248cbq_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
266int
267cbq_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
292int
293cbq_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
314int
315cbq_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
424int
425cbq_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
460int
461cbq_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
500static int
501cbq_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
557static struct mbuf *
558cbq_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
585static void
586cbqrestart(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
610static 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
623static int
624cbq_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
661static int
662cbq_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
686static int
687cbq_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 */
720static int
721cbq_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
778static int
779cbq_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
798static int
799cbq_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 */
817static int
818cbq_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
842static int
843cbq_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
878static int
879cbq_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
916static int
917cbq_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
959static int
960cbq_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
1001altqdev_decl(cbq);
1002
1003int
1004cbqopen(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
1016int
1017cbqclose(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
1047int
1048cbqioctl(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 */
1135static void cbq_class_dump(int);
1136
1137static 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
1177static struct altqsw cbq_sw =
1178        {"cbq", cbqopen, cbqclose, cbqioctl};
1179
1180ALTQ_MODULE(altq_cbq, ALTQT_CBQ, &cbq_sw);
1181MODULE_DEPEND(altq_cbq, altq_red, 1, 1, 1);
1182MODULE_DEPEND(altq_cbq, altq_rio, 1, 1, 1);
1183
1184#endif /* KLD_MODULE */
1185#endif /* ALTQ3_COMPAT */
1186
1187#endif /* ALTQ_CBQ */
Note: See TracBrowser for help on using the repository browser.