source: rtems-libbsd/freebsd/sys/contrib/altq/altq/altq_cbq.c @ 2017a6d

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 2017a6d was 2017a6d, checked in by Sebastian Huber <sebastian.huber@…>, on 04/07/16 at 07:48:12

Directly use <sys/time.h> provided by Newlib

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