Annotation of sys/altq/altq_cbq.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: altq_cbq.c,v 1.22 2007/05/28 17:16:38 henning Exp $ */
2: /* $KAME: altq_cbq.c,v 1.9 2000/12/14 08:12:45 thorpej Exp $ */
3:
4: /*
5: * Copyright (c) Sun Microsystems, Inc. 1993-1998 All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: *
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: *
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: *
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the SMCC Technology
21: * Development Group at Sun Microsystems, Inc.
22: *
23: * 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or
24: * promote products derived from this software without specific prior
25: * written permission.
26: *
27: * SUN MICROSYSTEMS DOES NOT CLAIM MERCHANTABILITY OF THIS SOFTWARE OR THE
28: * SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE. The software is
29: * provided "as is" without express or implied warranty of any kind.
30: *
31: * These notices must be retained in any copies of any part of this software.
32: */
33:
34: #include <sys/param.h>
35: #include <sys/malloc.h>
36: #include <sys/mbuf.h>
37: #include <sys/socket.h>
38: #include <sys/systm.h>
39: #include <sys/errno.h>
40: #include <sys/time.h>
41:
42: #include <net/if.h>
43: #include <netinet/in.h>
44:
45: #include <net/pfvar.h>
46: #include <altq/altq.h>
47: #include <altq/altq_cbq.h>
48:
49: /*
50: * Forward Declarations.
51: */
52: static int cbq_class_destroy(cbq_state_t *, struct rm_class *);
53: static struct rm_class *clh_to_clp(cbq_state_t *, u_int32_t);
54: static int cbq_clear_interface(cbq_state_t *);
55: static int cbq_request(struct ifaltq *, int, void *);
56: static int cbq_enqueue(struct ifaltq *, struct mbuf *,
57: struct altq_pktattr *);
58: static struct mbuf *cbq_dequeue(struct ifaltq *, int);
59: static void cbqrestart(struct ifaltq *);
60: static void get_class_stats(class_stats_t *, struct rm_class *);
61: static void cbq_purge(cbq_state_t *);
62:
63: /*
64: * int
65: * cbq_class_destroy(cbq_mod_state_t *, struct rm_class *) - This
66: * function destroys a given traffic class. Before destroying
67: * the class, all traffic for that class is released.
68: */
69: static int
70: cbq_class_destroy(cbq_state_t *cbqp, struct rm_class *cl)
71: {
72: int i;
73:
74: /* delete the class */
75: rmc_delete_class(&cbqp->ifnp, cl);
76:
77: /*
78: * free the class handle
79: */
80: for (i = 0; i < CBQ_MAX_CLASSES; i++)
81: if (cbqp->cbq_class_tbl[i] == cl)
82: cbqp->cbq_class_tbl[i] = NULL;
83:
84: if (cl == cbqp->ifnp.root_)
85: cbqp->ifnp.root_ = NULL;
86: if (cl == cbqp->ifnp.default_)
87: cbqp->ifnp.default_ = NULL;
88: return (0);
89: }
90:
91: /* convert class handle to class pointer */
92: static struct rm_class *
93: clh_to_clp(cbq_state_t *cbqp, u_int32_t chandle)
94: {
95: int i;
96: struct rm_class *cl;
97:
98: if (chandle == 0)
99: return (NULL);
100: /*
101: * first, try the slot corresponding to the lower bits of the handle.
102: * if it does not match, do the linear table search.
103: */
104: i = chandle % CBQ_MAX_CLASSES;
105: if ((cl = cbqp->cbq_class_tbl[i]) != NULL &&
106: cl->stats_.handle == chandle)
107: return (cl);
108: for (i = 0; i < CBQ_MAX_CLASSES; i++)
109: if ((cl = cbqp->cbq_class_tbl[i]) != NULL &&
110: cl->stats_.handle == chandle)
111: return (cl);
112: return (NULL);
113: }
114:
115: static int
116: cbq_clear_interface(cbq_state_t *cbqp)
117: {
118: int again, i;
119: struct rm_class *cl;
120:
121: /* clear out the classes now */
122: do {
123: again = 0;
124: for (i = 0; i < CBQ_MAX_CLASSES; i++) {
125: if ((cl = cbqp->cbq_class_tbl[i]) != NULL) {
126: if (is_a_parent_class(cl))
127: again++;
128: else {
129: cbq_class_destroy(cbqp, cl);
130: cbqp->cbq_class_tbl[i] = NULL;
131: if (cl == cbqp->ifnp.root_)
132: cbqp->ifnp.root_ = NULL;
133: if (cl == cbqp->ifnp.default_)
134: cbqp->ifnp.default_ = NULL;
135: }
136: }
137: }
138: } while (again);
139:
140: return (0);
141: }
142:
143: static int
144: cbq_request(struct ifaltq *ifq, int req, void *arg)
145: {
146: cbq_state_t *cbqp = (cbq_state_t *)ifq->altq_disc;
147:
148: switch (req) {
149: case ALTRQ_PURGE:
150: cbq_purge(cbqp);
151: break;
152: }
153: return (0);
154: }
155:
156: /* copy the stats info in rm_class to class_states_t */
157: static void
158: get_class_stats(class_stats_t *statsp, struct rm_class *cl)
159: {
160: statsp->handle = cl->stats_.handle;
161: statsp->xmit_cnt = cl->stats_.xmit_cnt;
162: statsp->drop_cnt = cl->stats_.drop_cnt;
163: statsp->over = cl->stats_.over;
164: statsp->borrows = cl->stats_.borrows;
165: statsp->overactions = cl->stats_.overactions;
166: statsp->delays = cl->stats_.delays;
167:
168: statsp->depth = cl->depth_;
169: statsp->priority = cl->pri_;
170: statsp->maxidle = cl->maxidle_;
171: statsp->minidle = cl->minidle_;
172: statsp->offtime = cl->offtime_;
173: statsp->qmax = qlimit(cl->q_);
174: statsp->ns_per_byte = cl->ns_per_byte_;
175: statsp->wrr_allot = cl->w_allotment_;
176: statsp->qcnt = qlen(cl->q_);
177: statsp->avgidle = cl->avgidle_;
178:
179: statsp->qtype = qtype(cl->q_);
180: #ifdef ALTQ_RED
181: if (q_is_red(cl->q_))
182: red_getstats(cl->red_, &statsp->red[0]);
183: #endif
184: #ifdef ALTQ_RIO
185: if (q_is_rio(cl->q_))
186: rio_getstats((rio_t *)cl->red_, &statsp->red[0]);
187: #endif
188: }
189:
190: int
191: cbq_pfattach(struct pf_altq *a)
192: {
193: struct ifnet *ifp;
194: int s, error;
195:
196: if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL)
197: return (EINVAL);
198: s = splnet();
199: error = altq_attach(&ifp->if_snd, ALTQT_CBQ, a->altq_disc,
200: cbq_enqueue, cbq_dequeue, cbq_request, NULL, NULL);
201: splx(s);
202: return (error);
203: }
204:
205: int
206: cbq_add_altq(struct pf_altq *a)
207: {
208: cbq_state_t *cbqp;
209: struct ifnet *ifp;
210:
211: if ((ifp = ifunit(a->ifname)) == NULL)
212: return (EINVAL);
213: if (!ALTQ_IS_READY(&ifp->if_snd))
214: return (ENODEV);
215:
216: /* allocate and initialize cbq_state_t */
217: MALLOC(cbqp, cbq_state_t *, sizeof(cbq_state_t), M_DEVBUF, M_WAITOK);
218: if (cbqp == NULL)
219: return (ENOMEM);
220: bzero(cbqp, sizeof(cbq_state_t));
221: CALLOUT_INIT(&cbqp->cbq_callout);
222: cbqp->cbq_qlen = 0;
223: cbqp->ifnp.ifq_ = &ifp->if_snd; /* keep the ifq */
224:
225: /* keep the state in pf_altq */
226: a->altq_disc = cbqp;
227:
228: return (0);
229: }
230:
231: int
232: cbq_remove_altq(struct pf_altq *a)
233: {
234: cbq_state_t *cbqp;
235:
236: if ((cbqp = a->altq_disc) == NULL)
237: return (EINVAL);
238: a->altq_disc = NULL;
239:
240: cbq_clear_interface(cbqp);
241:
242: if (cbqp->ifnp.default_)
243: cbq_class_destroy(cbqp, cbqp->ifnp.default_);
244: if (cbqp->ifnp.root_)
245: cbq_class_destroy(cbqp, cbqp->ifnp.root_);
246:
247: /* deallocate cbq_state_t */
248: FREE(cbqp, M_DEVBUF);
249:
250: return (0);
251: }
252:
253: int
254: cbq_add_queue(struct pf_altq *a)
255: {
256: struct rm_class *borrow, *parent;
257: cbq_state_t *cbqp;
258: struct rm_class *cl;
259: struct cbq_opts *opts;
260: int i;
261:
262: if ((cbqp = a->altq_disc) == NULL)
263: return (EINVAL);
264: if (a->qid == 0)
265: return (EINVAL);
266:
267: /*
268: * find a free slot in the class table. if the slot matching
269: * the lower bits of qid is free, use this slot. otherwise,
270: * use the first free slot.
271: */
272: i = a->qid % CBQ_MAX_CLASSES;
273: if (cbqp->cbq_class_tbl[i] != NULL) {
274: for (i = 0; i < CBQ_MAX_CLASSES; i++)
275: if (cbqp->cbq_class_tbl[i] == NULL)
276: break;
277: if (i == CBQ_MAX_CLASSES)
278: return (EINVAL);
279: }
280:
281: opts = &a->pq_u.cbq_opts;
282: /* check parameters */
283: if (a->priority >= CBQ_MAXPRI)
284: return (EINVAL);
285:
286: /* Get pointers to parent and borrow classes. */
287: parent = clh_to_clp(cbqp, a->parent_qid);
288: if (opts->flags & CBQCLF_BORROW)
289: borrow = parent;
290: else
291: borrow = NULL;
292:
293: /*
294: * A class must borrow from its parent or it can not
295: * borrow at all. Hence, borrow can be null.
296: */
297: if (parent == NULL && (opts->flags & CBQCLF_ROOTCLASS) == 0) {
298: printf("cbq_add_queue: no parent class!\n");
299: return (EINVAL);
300: }
301:
302: if ((borrow != parent) && (borrow != NULL)) {
303: printf("cbq_add_class: borrow class != parent\n");
304: return (EINVAL);
305: }
306:
307: /*
308: * check parameters
309: */
310: switch (opts->flags & CBQCLF_CLASSMASK) {
311: case CBQCLF_ROOTCLASS:
312: if (parent != NULL)
313: return (EINVAL);
314: if (cbqp->ifnp.root_)
315: return (EINVAL);
316: break;
317: case CBQCLF_DEFCLASS:
318: if (cbqp->ifnp.default_)
319: return (EINVAL);
320: break;
321: case 0:
322: if (a->qid == 0)
323: return (EINVAL);
324: break;
325: default:
326: /* more than two flags bits set */
327: return (EINVAL);
328: }
329:
330: /*
331: * create a class. if this is a root class, initialize the
332: * interface.
333: */
334: if ((opts->flags & CBQCLF_CLASSMASK) == CBQCLF_ROOTCLASS) {
335: rmc_init(cbqp->ifnp.ifq_, &cbqp->ifnp, opts->ns_per_byte,
336: cbqrestart, a->qlimit, RM_MAXQUEUED,
337: opts->maxidle, opts->minidle, opts->offtime,
338: opts->flags);
339: cl = cbqp->ifnp.root_;
340: } else {
341: cl = rmc_newclass(a->priority,
342: &cbqp->ifnp, opts->ns_per_byte,
343: rmc_delay_action, a->qlimit, parent, borrow,
344: opts->maxidle, opts->minidle, opts->offtime,
345: opts->pktsize, opts->flags);
346: }
347: if (cl == NULL)
348: return (ENOMEM);
349:
350: /* return handle to user space. */
351: cl->stats_.handle = a->qid;
352: cl->stats_.depth = cl->depth_;
353:
354: /* save the allocated class */
355: cbqp->cbq_class_tbl[i] = cl;
356:
357: if ((opts->flags & CBQCLF_CLASSMASK) == CBQCLF_DEFCLASS)
358: cbqp->ifnp.default_ = cl;
359:
360: return (0);
361: }
362:
363: int
364: cbq_remove_queue(struct pf_altq *a)
365: {
366: struct rm_class *cl;
367: cbq_state_t *cbqp;
368: int i;
369:
370: if ((cbqp = a->altq_disc) == NULL)
371: return (EINVAL);
372:
373: if ((cl = clh_to_clp(cbqp, a->qid)) == NULL)
374: return (EINVAL);
375:
376: /* if we are a parent class, then return an error. */
377: if (is_a_parent_class(cl))
378: return (EINVAL);
379:
380: /* delete the class */
381: rmc_delete_class(&cbqp->ifnp, cl);
382:
383: /*
384: * free the class handle
385: */
386: for (i = 0; i < CBQ_MAX_CLASSES; i++)
387: if (cbqp->cbq_class_tbl[i] == cl) {
388: cbqp->cbq_class_tbl[i] = NULL;
389: if (cl == cbqp->ifnp.root_)
390: cbqp->ifnp.root_ = NULL;
391: if (cl == cbqp->ifnp.default_)
392: cbqp->ifnp.default_ = NULL;
393: break;
394: }
395:
396: return (0);
397: }
398:
399: int
400: cbq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
401: {
402: cbq_state_t *cbqp;
403: struct rm_class *cl;
404: class_stats_t stats;
405: int error = 0;
406:
407: if ((cbqp = altq_lookup(a->ifname, ALTQT_CBQ)) == NULL)
408: return (EBADF);
409:
410: if ((cl = clh_to_clp(cbqp, a->qid)) == NULL)
411: return (EINVAL);
412:
413: if (*nbytes < sizeof(stats))
414: return (EINVAL);
415:
416: get_class_stats(&stats, cl);
417:
418: if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0)
419: return (error);
420: *nbytes = sizeof(stats);
421: return (0);
422: }
423:
424: /*
425: * int
426: * cbq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pattr)
427: * - Queue data packets.
428: *
429: * cbq_enqueue is set to ifp->if_altqenqueue and called by an upper
430: * layer (e.g. ether_output). cbq_enqueue queues the given packet
431: * to the cbq, then invokes the driver's start routine.
432: *
433: * Assumptions: called in splnet
434: * Returns: 0 if the queueing is successful.
435: * ENOBUFS if a packet dropping occurred as a result of
436: * the queueing.
437: */
438:
439: static int
440: cbq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
441: {
442: cbq_state_t *cbqp = (cbq_state_t *)ifq->altq_disc;
443: struct rm_class *cl;
444: int len;
445:
446: /* grab class set by classifier */
447: if ((m->m_flags & M_PKTHDR) == 0) {
448: /* should not happen */
449: printf("altq: packet for %s does not have pkthdr\n",
450: ifq->altq_ifp->if_xname);
451: m_freem(m);
452: return (ENOBUFS);
453: }
454: if ((cl = clh_to_clp(cbqp, m->m_pkthdr.pf.qid)) == NULL) {
455: cl = cbqp->ifnp.default_;
456: if (cl == NULL) {
457: m_freem(m);
458: return (ENOBUFS);
459: }
460: cl->pktattr_ = NULL;
461: }
462:
463: len = m_pktlen(m);
464: if (rmc_queue_packet(cl, m) != 0) {
465: /* drop occurred. some mbuf was freed in rmc_queue_packet. */
466: PKTCNTR_ADD(&cl->stats_.drop_cnt, len);
467: return (ENOBUFS);
468: }
469:
470: /* successfully queued. */
471: ++cbqp->cbq_qlen;
472: IFQ_INC_LEN(ifq);
473: return (0);
474: }
475:
476: static struct mbuf *
477: cbq_dequeue(struct ifaltq *ifq, int op)
478: {
479: cbq_state_t *cbqp = (cbq_state_t *)ifq->altq_disc;
480: struct mbuf *m;
481:
482: m = rmc_dequeue_next(&cbqp->ifnp, op);
483:
484: if (m && op == ALTDQ_REMOVE) {
485: --cbqp->cbq_qlen; /* decrement # of packets in cbq */
486: IFQ_DEC_LEN(ifq);
487:
488: /* Update the class. */
489: rmc_update_class_util(&cbqp->ifnp);
490: }
491: return (m);
492: }
493:
494: /*
495: * void
496: * cbqrestart(queue_t *) - Restart sending of data.
497: * called from rmc_restart in splnet via timeout after waking up
498: * a suspended class.
499: * Returns: NONE
500: */
501:
502: static void
503: cbqrestart(struct ifaltq *ifq)
504: {
505: cbq_state_t *cbqp;
506: struct ifnet *ifp;
507:
508: if (!ALTQ_IS_ENABLED(ifq))
509: /* cbq must have been detached */
510: return;
511:
512: if ((cbqp = (cbq_state_t *)ifq->altq_disc) == NULL)
513: /* should not happen */
514: return;
515:
516: ifp = ifq->altq_ifp;
517: if (ifp->if_start &&
518: cbqp->cbq_qlen > 0 && (ifp->if_flags & IFF_OACTIVE) == 0)
519: (*ifp->if_start)(ifp);
520: }
521:
522: static void cbq_purge(cbq_state_t *cbqp)
523: {
524: struct rm_class *cl;
525: int i;
526:
527: for (i = 0; i < CBQ_MAX_CLASSES; i++)
528: if ((cl = cbqp->cbq_class_tbl[i]) != NULL)
529: rmc_dropall(cl);
530: if (ALTQ_IS_ENABLED(cbqp->ifnp.ifq_))
531: cbqp->ifnp.ifq_->ifq_len = 0;
532: }
CVSweb