1a5b789f6SErmal Luçi /*
2a5b789f6SErmal Luçi * Copyright (c) 2008 The DragonFly Project. All rights reserved.
3a5b789f6SErmal Luçi *
4a5b789f6SErmal Luçi * This code is derived from software contributed to The DragonFly Project
5a5b789f6SErmal Luçi * by Matthew Dillon <dillon@backplane.com>
6a5b789f6SErmal Luçi *
7a5b789f6SErmal Luçi * Redistribution and use in source and binary forms, with or without
8a5b789f6SErmal Luçi * modification, are permitted provided that the following conditions
9a5b789f6SErmal Luçi * are met:
10a5b789f6SErmal Luçi *
11a5b789f6SErmal Luçi * 1. Redistributions of source code must retain the above copyright
12a5b789f6SErmal Luçi * notice, this list of conditions and the following disclaimer.
13a5b789f6SErmal Luçi * 2. Redistributions in binary form must reproduce the above copyright
14a5b789f6SErmal Luçi * notice, this list of conditions and the following disclaimer in
15a5b789f6SErmal Luçi * the documentation and/or other materials provided with the
16a5b789f6SErmal Luçi * distribution.
17a5b789f6SErmal Luçi * 3. Neither the name of The DragonFly Project nor the names of its
18a5b789f6SErmal Luçi * contributors may be used to endorse or promote products derived
19a5b789f6SErmal Luçi * from this software without specific, prior written permission.
20a5b789f6SErmal Luçi *
21a5b789f6SErmal Luçi * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22a5b789f6SErmal Luçi * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23a5b789f6SErmal Luçi * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24a5b789f6SErmal Luçi * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25a5b789f6SErmal Luçi * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26a5b789f6SErmal Luçi * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27a5b789f6SErmal Luçi * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28a5b789f6SErmal Luçi * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29a5b789f6SErmal Luçi * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30a5b789f6SErmal Luçi * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31a5b789f6SErmal Luçi * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32a5b789f6SErmal Luçi * SUCH DAMAGE.
33a5b789f6SErmal Luçi *
34a5b789f6SErmal Luçi * $DragonFly: src/sys/net/altq/altq_fairq.c,v 1.1 2008/04/06 18:58:15 dillon Exp $
35a5b789f6SErmal Luçi */
36a5b789f6SErmal Luçi /*
37a5b789f6SErmal Luçi * Matt: I gutted altq_priq.c and used it as a skeleton on which to build
38a5b789f6SErmal Luçi * fairq. The fairq algorithm is completely different then priq, of course,
39a5b789f6SErmal Luçi * but because I used priq's skeleton I believe I should include priq's
40a5b789f6SErmal Luçi * copyright.
41a5b789f6SErmal Luçi *
42a5b789f6SErmal Luçi * Copyright (C) 2000-2003
43a5b789f6SErmal Luçi * Sony Computer Science Laboratories Inc. All rights reserved.
44a5b789f6SErmal Luçi *
45a5b789f6SErmal Luçi * Redistribution and use in source and binary forms, with or without
46a5b789f6SErmal Luçi * modification, are permitted provided that the following conditions
47a5b789f6SErmal Luçi * are met:
48a5b789f6SErmal Luçi * 1. Redistributions of source code must retain the above copyright
49a5b789f6SErmal Luçi * notice, this list of conditions and the following disclaimer.
50a5b789f6SErmal Luçi * 2. Redistributions in binary form must reproduce the above copyright
51a5b789f6SErmal Luçi * notice, this list of conditions and the following disclaimer in the
52a5b789f6SErmal Luçi * documentation and/or other materials provided with the distribution.
53a5b789f6SErmal Luçi *
54a5b789f6SErmal Luçi * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
55a5b789f6SErmal Luçi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56a5b789f6SErmal Luçi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57a5b789f6SErmal Luçi * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
58a5b789f6SErmal Luçi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59a5b789f6SErmal Luçi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60a5b789f6SErmal Luçi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61a5b789f6SErmal Luçi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62a5b789f6SErmal Luçi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63a5b789f6SErmal Luçi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64a5b789f6SErmal Luçi * SUCH DAMAGE.
65a5b789f6SErmal Luçi */
66a5b789f6SErmal Luçi
67a5b789f6SErmal Luçi /*
68a5b789f6SErmal Luçi * FAIRQ - take traffic classified by keep state (hashed into
69a5b789f6SErmal Luçi * mbuf->m_pkthdr.altq_state_hash) and bucketize it. Fairly extract
70a5b789f6SErmal Luçi * the first packet from each bucket in a round-robin fashion.
71a5b789f6SErmal Luçi *
72a5b789f6SErmal Luçi * TODO - better overall qlimit support (right now it is per-bucket).
73a5b789f6SErmal Luçi * - NOTE: red etc is per bucket, not overall.
74a5b789f6SErmal Luçi * - better service curve support.
75a5b789f6SErmal Luçi *
76a5b789f6SErmal Luçi * EXAMPLE:
77a5b789f6SErmal Luçi *
78a5b789f6SErmal Luçi * altq on em0 fairq bandwidth 650Kb queue { std, bulk }
79a5b789f6SErmal Luçi * queue std priority 3 bandwidth 400Kb \
80a5b789f6SErmal Luçi * fairq (buckets 64, default, hogs 1Kb) qlimit 50
81a5b789f6SErmal Luçi * queue bulk priority 2 bandwidth 100Kb \
82a5b789f6SErmal Luçi * fairq (buckets 64, hogs 1Kb) qlimit 50
83a5b789f6SErmal Luçi *
84a5b789f6SErmal Luçi * pass out on em0 from any to any keep state queue std
85a5b789f6SErmal Luçi * pass out on em0 inet proto tcp ..... port ... keep state queue bulk
86a5b789f6SErmal Luçi */
87a5b789f6SErmal Luçi #include "opt_altq.h"
88a5b789f6SErmal Luçi #include "opt_inet.h"
89a5b789f6SErmal Luçi #include "opt_inet6.h"
90a5b789f6SErmal Luçi
91a5b789f6SErmal Luçi #ifdef ALTQ_FAIRQ /* fairq is enabled in the kernel conf */
92a5b789f6SErmal Luçi
93a5b789f6SErmal Luçi #include <sys/param.h>
94a5b789f6SErmal Luçi #include <sys/malloc.h>
95a5b789f6SErmal Luçi #include <sys/mbuf.h>
96a5b789f6SErmal Luçi #include <sys/socket.h>
97a5b789f6SErmal Luçi #include <sys/sockio.h>
98a5b789f6SErmal Luçi #include <sys/systm.h>
99a5b789f6SErmal Luçi #include <sys/proc.h>
100a5b789f6SErmal Luçi #include <sys/errno.h>
101a5b789f6SErmal Luçi #include <sys/kernel.h>
102a5b789f6SErmal Luçi #include <sys/queue.h>
103a5b789f6SErmal Luçi
104a5b789f6SErmal Luçi #include <net/if.h>
105cd2bc2efSErmal Luçi #include <net/if_var.h>
106*2c2b37adSJustin Hibbits #include <net/if_private.h>
107a5b789f6SErmal Luçi #include <netinet/in.h>
108a5b789f6SErmal Luçi
109cd2bc2efSErmal Luçi #include <netpfil/pf/pf.h>
110cd2bc2efSErmal Luçi #include <netpfil/pf/pf_altq.h>
111cd2bc2efSErmal Luçi #include <netpfil/pf/pf_mtag.h>
112a5b789f6SErmal Luçi #include <net/altq/altq.h>
113a5b789f6SErmal Luçi #include <net/altq/altq_fairq.h>
114a5b789f6SErmal Luçi
115a5b789f6SErmal Luçi /*
116a5b789f6SErmal Luçi * function prototypes
117a5b789f6SErmal Luçi */
118a5b789f6SErmal Luçi static int fairq_clear_interface(struct fairq_if *);
119a5b789f6SErmal Luçi static int fairq_request(struct ifaltq *, int, void *);
120a5b789f6SErmal Luçi static void fairq_purge(struct fairq_if *);
121a5b789f6SErmal Luçi static struct fairq_class *fairq_class_create(struct fairq_if *, int, int, u_int, struct fairq_opts *, int);
122a5b789f6SErmal Luçi static int fairq_class_destroy(struct fairq_class *);
123a5b789f6SErmal Luçi static int fairq_enqueue(struct ifaltq *, struct mbuf *, struct altq_pktattr *);
124a5b789f6SErmal Luçi static struct mbuf *fairq_dequeue(struct ifaltq *, int);
125a5b789f6SErmal Luçi
126a5b789f6SErmal Luçi static int fairq_addq(struct fairq_class *, struct mbuf *, u_int32_t);
127a5b789f6SErmal Luçi static struct mbuf *fairq_getq(struct fairq_class *, uint64_t);
128a5b789f6SErmal Luçi static struct mbuf *fairq_pollq(struct fairq_class *, uint64_t, int *);
129a5b789f6SErmal Luçi static fairq_bucket_t *fairq_selectq(struct fairq_class *, int);
130a5b789f6SErmal Luçi static void fairq_purgeq(struct fairq_class *);
131a5b789f6SErmal Luçi
132a5b789f6SErmal Luçi static void get_class_stats(struct fairq_classstats *, struct fairq_class *);
133a5b789f6SErmal Luçi static struct fairq_class *clh_to_clp(struct fairq_if *, uint32_t);
134a5b789f6SErmal Luçi
135a5b789f6SErmal Luçi int
fairq_pfattach(struct pf_altq * a)136a5b789f6SErmal Luçi fairq_pfattach(struct pf_altq *a)
137a5b789f6SErmal Luçi {
138a5b789f6SErmal Luçi struct ifnet *ifp;
139a5b789f6SErmal Luçi int error;
140a5b789f6SErmal Luçi
141a5b789f6SErmal Luçi if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL)
142a5b789f6SErmal Luçi return (EINVAL);
143a5b789f6SErmal Luçi
144a5b789f6SErmal Luçi error = altq_attach(&ifp->if_snd, ALTQT_FAIRQ, a->altq_disc,
14527b2aa49SKristof Provost fairq_enqueue, fairq_dequeue, fairq_request);
146a5b789f6SErmal Luçi
147a5b789f6SErmal Luçi return (error);
148a5b789f6SErmal Luçi }
149a5b789f6SErmal Luçi
150a5b789f6SErmal Luçi int
fairq_add_altq(struct ifnet * ifp,struct pf_altq * a)1518f2ac656SPatrick Kelsey fairq_add_altq(struct ifnet *ifp, struct pf_altq *a)
152a5b789f6SErmal Luçi {
153a5b789f6SErmal Luçi struct fairq_if *pif;
154a5b789f6SErmal Luçi
1558f2ac656SPatrick Kelsey if (ifp == NULL)
156a5b789f6SErmal Luçi return (EINVAL);
157a5b789f6SErmal Luçi if (!ALTQ_IS_READY(&ifp->if_snd))
158a5b789f6SErmal Luçi return (ENODEV);
159a5b789f6SErmal Luçi
160a5b789f6SErmal Luçi pif = malloc(sizeof(struct fairq_if),
161a5b789f6SErmal Luçi M_DEVBUF, M_WAITOK | M_ZERO);
162a5b789f6SErmal Luçi pif->pif_bandwidth = a->ifbandwidth;
163a5b789f6SErmal Luçi pif->pif_maxpri = -1;
164a5b789f6SErmal Luçi pif->pif_ifq = &ifp->if_snd;
165a5b789f6SErmal Luçi
166a5b789f6SErmal Luçi /* keep the state in pf_altq */
167a5b789f6SErmal Luçi a->altq_disc = pif;
168a5b789f6SErmal Luçi
169a5b789f6SErmal Luçi return (0);
170a5b789f6SErmal Luçi }
171a5b789f6SErmal Luçi
172a5b789f6SErmal Luçi int
fairq_remove_altq(struct pf_altq * a)173a5b789f6SErmal Luçi fairq_remove_altq(struct pf_altq *a)
174a5b789f6SErmal Luçi {
175a5b789f6SErmal Luçi struct fairq_if *pif;
176a5b789f6SErmal Luçi
177a5b789f6SErmal Luçi if ((pif = a->altq_disc) == NULL)
178a5b789f6SErmal Luçi return (EINVAL);
179a5b789f6SErmal Luçi a->altq_disc = NULL;
180a5b789f6SErmal Luçi
181a5b789f6SErmal Luçi fairq_clear_interface(pif);
182a5b789f6SErmal Luçi
183a5b789f6SErmal Luçi free(pif, M_DEVBUF);
184a5b789f6SErmal Luçi return (0);
185a5b789f6SErmal Luçi }
186a5b789f6SErmal Luçi
187a5b789f6SErmal Luçi int
fairq_add_queue(struct pf_altq * a)188a5b789f6SErmal Luçi fairq_add_queue(struct pf_altq *a)
189a5b789f6SErmal Luçi {
190a5b789f6SErmal Luçi struct fairq_if *pif;
191a5b789f6SErmal Luçi struct fairq_class *cl;
192a5b789f6SErmal Luçi
193a5b789f6SErmal Luçi if ((pif = a->altq_disc) == NULL)
194a5b789f6SErmal Luçi return (EINVAL);
195a5b789f6SErmal Luçi
196a5b789f6SErmal Luçi /* check parameters */
197a5b789f6SErmal Luçi if (a->priority >= FAIRQ_MAXPRI)
198a5b789f6SErmal Luçi return (EINVAL);
199a5b789f6SErmal Luçi if (a->qid == 0)
200a5b789f6SErmal Luçi return (EINVAL);
201a5b789f6SErmal Luçi if (pif->pif_classes[a->priority] != NULL)
202a5b789f6SErmal Luçi return (EBUSY);
203a5b789f6SErmal Luçi if (clh_to_clp(pif, a->qid) != NULL)
204a5b789f6SErmal Luçi return (EBUSY);
205a5b789f6SErmal Luçi
206a5b789f6SErmal Luçi cl = fairq_class_create(pif, a->priority, a->qlimit, a->bandwidth,
207a5b789f6SErmal Luçi &a->pq_u.fairq_opts, a->qid);
208a5b789f6SErmal Luçi if (cl == NULL)
209a5b789f6SErmal Luçi return (ENOMEM);
210a5b789f6SErmal Luçi
211a5b789f6SErmal Luçi return (0);
212a5b789f6SErmal Luçi }
213a5b789f6SErmal Luçi
214a5b789f6SErmal Luçi int
fairq_remove_queue(struct pf_altq * a)215a5b789f6SErmal Luçi fairq_remove_queue(struct pf_altq *a)
216a5b789f6SErmal Luçi {
217a5b789f6SErmal Luçi struct fairq_if *pif;
218a5b789f6SErmal Luçi struct fairq_class *cl;
219a5b789f6SErmal Luçi
220a5b789f6SErmal Luçi if ((pif = a->altq_disc) == NULL)
221a5b789f6SErmal Luçi return (EINVAL);
222a5b789f6SErmal Luçi
223a5b789f6SErmal Luçi if ((cl = clh_to_clp(pif, a->qid)) == NULL)
224a5b789f6SErmal Luçi return (EINVAL);
225a5b789f6SErmal Luçi
226a5b789f6SErmal Luçi return (fairq_class_destroy(cl));
227a5b789f6SErmal Luçi }
228a5b789f6SErmal Luçi
229a5b789f6SErmal Luçi int
fairq_getqstats(struct pf_altq * a,void * ubuf,int * nbytes,int version)230249cc75fSPatrick Kelsey fairq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes, int version)
231a5b789f6SErmal Luçi {
232a5b789f6SErmal Luçi struct fairq_if *pif;
233a5b789f6SErmal Luçi struct fairq_class *cl;
234a5b789f6SErmal Luçi struct fairq_classstats stats;
235a5b789f6SErmal Luçi int error = 0;
236a5b789f6SErmal Luçi
237a5b789f6SErmal Luçi if ((pif = altq_lookup(a->ifname, ALTQT_FAIRQ)) == NULL)
238a5b789f6SErmal Luçi return (EBADF);
239a5b789f6SErmal Luçi
240a5b789f6SErmal Luçi if ((cl = clh_to_clp(pif, a->qid)) == NULL)
241a5b789f6SErmal Luçi return (EINVAL);
242a5b789f6SErmal Luçi
243a5b789f6SErmal Luçi if (*nbytes < sizeof(stats))
244a5b789f6SErmal Luçi return (EINVAL);
245a5b789f6SErmal Luçi
246a5b789f6SErmal Luçi get_class_stats(&stats, cl);
247a5b789f6SErmal Luçi
248a5b789f6SErmal Luçi if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0)
249a5b789f6SErmal Luçi return (error);
250a5b789f6SErmal Luçi *nbytes = sizeof(stats);
251a5b789f6SErmal Luçi return (0);
252a5b789f6SErmal Luçi }
253a5b789f6SErmal Luçi
254a5b789f6SErmal Luçi /*
255a5b789f6SErmal Luçi * bring the interface back to the initial state by discarding
256a5b789f6SErmal Luçi * all the filters and classes.
257a5b789f6SErmal Luçi */
258a5b789f6SErmal Luçi static int
fairq_clear_interface(struct fairq_if * pif)259a5b789f6SErmal Luçi fairq_clear_interface(struct fairq_if *pif)
260a5b789f6SErmal Luçi {
261a5b789f6SErmal Luçi struct fairq_class *cl;
262a5b789f6SErmal Luçi int pri;
263a5b789f6SErmal Luçi
264a5b789f6SErmal Luçi /* clear out the classes */
265a5b789f6SErmal Luçi for (pri = 0; pri <= pif->pif_maxpri; pri++) {
266a5b789f6SErmal Luçi if ((cl = pif->pif_classes[pri]) != NULL)
267a5b789f6SErmal Luçi fairq_class_destroy(cl);
268a5b789f6SErmal Luçi }
269a5b789f6SErmal Luçi
270a5b789f6SErmal Luçi return (0);
271a5b789f6SErmal Luçi }
272a5b789f6SErmal Luçi
273a5b789f6SErmal Luçi static int
fairq_request(struct ifaltq * ifq,int req,void * arg)274a5b789f6SErmal Luçi fairq_request(struct ifaltq *ifq, int req, void *arg)
275a5b789f6SErmal Luçi {
276a5b789f6SErmal Luçi struct fairq_if *pif = (struct fairq_if *)ifq->altq_disc;
277a5b789f6SErmal Luçi
278a5b789f6SErmal Luçi IFQ_LOCK_ASSERT(ifq);
279a5b789f6SErmal Luçi
280a5b789f6SErmal Luçi switch (req) {
281a5b789f6SErmal Luçi case ALTRQ_PURGE:
282a5b789f6SErmal Luçi fairq_purge(pif);
283a5b789f6SErmal Luçi break;
284a5b789f6SErmal Luçi }
285a5b789f6SErmal Luçi return (0);
286a5b789f6SErmal Luçi }
287a5b789f6SErmal Luçi
288a5b789f6SErmal Luçi /* discard all the queued packets on the interface */
289a5b789f6SErmal Luçi static void
fairq_purge(struct fairq_if * pif)290a5b789f6SErmal Luçi fairq_purge(struct fairq_if *pif)
291a5b789f6SErmal Luçi {
292a5b789f6SErmal Luçi struct fairq_class *cl;
293a5b789f6SErmal Luçi int pri;
294a5b789f6SErmal Luçi
295a5b789f6SErmal Luçi for (pri = 0; pri <= pif->pif_maxpri; pri++) {
296a5b789f6SErmal Luçi if ((cl = pif->pif_classes[pri]) != NULL && cl->cl_head)
297a5b789f6SErmal Luçi fairq_purgeq(cl);
298a5b789f6SErmal Luçi }
299a5b789f6SErmal Luçi if (ALTQ_IS_ENABLED(pif->pif_ifq))
300a5b789f6SErmal Luçi pif->pif_ifq->ifq_len = 0;
301a5b789f6SErmal Luçi }
302a5b789f6SErmal Luçi
303a5b789f6SErmal Luçi static struct fairq_class *
fairq_class_create(struct fairq_if * pif,int pri,int qlimit,u_int bandwidth,struct fairq_opts * opts,int qid)304a5b789f6SErmal Luçi fairq_class_create(struct fairq_if *pif, int pri, int qlimit,
305a5b789f6SErmal Luçi u_int bandwidth, struct fairq_opts *opts, int qid)
306a5b789f6SErmal Luçi {
307a5b789f6SErmal Luçi struct fairq_class *cl;
308a5b789f6SErmal Luçi int flags = opts->flags;
309a5b789f6SErmal Luçi u_int nbuckets = opts->nbuckets;
310a5b789f6SErmal Luçi int i;
311a5b789f6SErmal Luçi
312a5b789f6SErmal Luçi #ifndef ALTQ_RED
313a5b789f6SErmal Luçi if (flags & FARF_RED) {
314a5b789f6SErmal Luçi #ifdef ALTQ_DEBUG
315a5b789f6SErmal Luçi printf("fairq_class_create: RED not configured for FAIRQ!\n");
316a5b789f6SErmal Luçi #endif
317a5b789f6SErmal Luçi return (NULL);
318a5b789f6SErmal Luçi }
319a5b789f6SErmal Luçi #endif
3200a70aaf8SLuiz Otavio O Souza #ifndef ALTQ_CODEL
3210a70aaf8SLuiz Otavio O Souza if (flags & FARF_CODEL) {
3220a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_DEBUG
3230a70aaf8SLuiz Otavio O Souza printf("fairq_class_create: CODEL not configured for FAIRQ!\n");
3240a70aaf8SLuiz Otavio O Souza #endif
3250a70aaf8SLuiz Otavio O Souza return (NULL);
3260a70aaf8SLuiz Otavio O Souza }
3270a70aaf8SLuiz Otavio O Souza #endif
328a5b789f6SErmal Luçi if (nbuckets == 0)
329a5b789f6SErmal Luçi nbuckets = 256;
330a5b789f6SErmal Luçi if (nbuckets > FAIRQ_MAX_BUCKETS)
331a5b789f6SErmal Luçi nbuckets = FAIRQ_MAX_BUCKETS;
332a5b789f6SErmal Luçi /* enforce power-of-2 size */
333a5b789f6SErmal Luçi while ((nbuckets ^ (nbuckets - 1)) != ((nbuckets << 1) - 1))
334a5b789f6SErmal Luçi ++nbuckets;
335a5b789f6SErmal Luçi
336a5b789f6SErmal Luçi if ((cl = pif->pif_classes[pri]) != NULL) {
337a5b789f6SErmal Luçi /* modify the class instead of creating a new one */
338a5b789f6SErmal Luçi IFQ_LOCK(cl->cl_pif->pif_ifq);
339a5b789f6SErmal Luçi if (cl->cl_head)
340a5b789f6SErmal Luçi fairq_purgeq(cl);
341a5b789f6SErmal Luçi IFQ_UNLOCK(cl->cl_pif->pif_ifq);
342a5b789f6SErmal Luçi #ifdef ALTQ_RIO
343a5b789f6SErmal Luçi if (cl->cl_qtype == Q_RIO)
344a5b789f6SErmal Luçi rio_destroy((rio_t *)cl->cl_red);
345a5b789f6SErmal Luçi #endif
346a5b789f6SErmal Luçi #ifdef ALTQ_RED
347a5b789f6SErmal Luçi if (cl->cl_qtype == Q_RED)
348a5b789f6SErmal Luçi red_destroy(cl->cl_red);
349a5b789f6SErmal Luçi #endif
3500a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL
3510a70aaf8SLuiz Otavio O Souza if (cl->cl_qtype == Q_CODEL)
3520a70aaf8SLuiz Otavio O Souza codel_destroy(cl->cl_codel);
3530a70aaf8SLuiz Otavio O Souza #endif
354a5b789f6SErmal Luçi } else {
355a5b789f6SErmal Luçi cl = malloc(sizeof(struct fairq_class),
356a5b789f6SErmal Luçi M_DEVBUF, M_WAITOK | M_ZERO);
357a5b789f6SErmal Luçi cl->cl_nbuckets = nbuckets;
358a5b789f6SErmal Luçi cl->cl_nbucket_mask = nbuckets - 1;
359a5b789f6SErmal Luçi
360a5b789f6SErmal Luçi cl->cl_buckets = malloc(
361a5b789f6SErmal Luçi sizeof(struct fairq_bucket) * cl->cl_nbuckets,
362a5b789f6SErmal Luçi M_DEVBUF, M_WAITOK | M_ZERO);
363a5b789f6SErmal Luçi cl->cl_head = NULL;
364a5b789f6SErmal Luçi }
365a5b789f6SErmal Luçi
366a5b789f6SErmal Luçi pif->pif_classes[pri] = cl;
367a5b789f6SErmal Luçi if (flags & FARF_DEFAULTCLASS)
368a5b789f6SErmal Luçi pif->pif_default = cl;
369a5b789f6SErmal Luçi if (qlimit == 0)
370a5b789f6SErmal Luçi qlimit = 50; /* use default */
371a5b789f6SErmal Luçi cl->cl_qlimit = qlimit;
372a5b789f6SErmal Luçi for (i = 0; i < cl->cl_nbuckets; ++i) {
373a5b789f6SErmal Luçi qlimit(&cl->cl_buckets[i].queue) = qlimit;
374a5b789f6SErmal Luçi }
375a5b789f6SErmal Luçi cl->cl_bandwidth = bandwidth / 8;
376a5b789f6SErmal Luçi cl->cl_qtype = Q_DROPTAIL;
377a5b789f6SErmal Luçi cl->cl_flags = flags & FARF_USERFLAGS;
378a5b789f6SErmal Luçi cl->cl_pri = pri;
379a5b789f6SErmal Luçi if (pri > pif->pif_maxpri)
380a5b789f6SErmal Luçi pif->pif_maxpri = pri;
381a5b789f6SErmal Luçi cl->cl_pif = pif;
382a5b789f6SErmal Luçi cl->cl_handle = qid;
383a5b789f6SErmal Luçi cl->cl_hogs_m1 = opts->hogs_m1 / 8;
384a5b789f6SErmal Luçi cl->cl_lssc_m1 = opts->lssc_m1 / 8; /* NOT YET USED */
385a5b789f6SErmal Luçi
386a5b789f6SErmal Luçi #ifdef ALTQ_RED
387a5b789f6SErmal Luçi if (flags & (FARF_RED|FARF_RIO)) {
388a5b789f6SErmal Luçi int red_flags, red_pkttime;
389a5b789f6SErmal Luçi
390a5b789f6SErmal Luçi red_flags = 0;
391a5b789f6SErmal Luçi if (flags & FARF_ECN)
392a5b789f6SErmal Luçi red_flags |= REDF_ECN;
393a5b789f6SErmal Luçi #ifdef ALTQ_RIO
394a5b789f6SErmal Luçi if (flags & FARF_CLEARDSCP)
395a5b789f6SErmal Luçi red_flags |= RIOF_CLEARDSCP;
396a5b789f6SErmal Luçi #endif
397a5b789f6SErmal Luçi if (pif->pif_bandwidth < 8)
398a5b789f6SErmal Luçi red_pkttime = 1000 * 1000 * 1000; /* 1 sec */
399a5b789f6SErmal Luçi else
400a5b789f6SErmal Luçi red_pkttime = (int64_t)pif->pif_ifq->altq_ifp->if_mtu
401a5b789f6SErmal Luçi * 1000 * 1000 * 1000 / (pif->pif_bandwidth / 8);
402a5b789f6SErmal Luçi #ifdef ALTQ_RIO
403a5b789f6SErmal Luçi if (flags & FARF_RIO) {
404a5b789f6SErmal Luçi cl->cl_red = (red_t *)rio_alloc(0, NULL,
405a5b789f6SErmal Luçi red_flags, red_pkttime);
406a5b789f6SErmal Luçi if (cl->cl_red != NULL)
407a5b789f6SErmal Luçi cl->cl_qtype = Q_RIO;
408a5b789f6SErmal Luçi } else
409a5b789f6SErmal Luçi #endif
410a5b789f6SErmal Luçi if (flags & FARF_RED) {
411a5b789f6SErmal Luçi cl->cl_red = red_alloc(0, 0,
412a5b789f6SErmal Luçi cl->cl_qlimit * 10/100,
413a5b789f6SErmal Luçi cl->cl_qlimit * 30/100,
414a5b789f6SErmal Luçi red_flags, red_pkttime);
415a5b789f6SErmal Luçi if (cl->cl_red != NULL)
416a5b789f6SErmal Luçi cl->cl_qtype = Q_RED;
417a5b789f6SErmal Luçi }
418a5b789f6SErmal Luçi }
419a5b789f6SErmal Luçi #endif /* ALTQ_RED */
4200a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL
4210a70aaf8SLuiz Otavio O Souza if (flags & FARF_CODEL) {
4220a70aaf8SLuiz Otavio O Souza cl->cl_codel = codel_alloc(5, 100, 0);
4230a70aaf8SLuiz Otavio O Souza if (cl->cl_codel != NULL)
4240a70aaf8SLuiz Otavio O Souza cl->cl_qtype = Q_CODEL;
4250a70aaf8SLuiz Otavio O Souza }
4260a70aaf8SLuiz Otavio O Souza #endif
427a5b789f6SErmal Luçi
428a5b789f6SErmal Luçi return (cl);
429a5b789f6SErmal Luçi }
430a5b789f6SErmal Luçi
431a5b789f6SErmal Luçi static int
fairq_class_destroy(struct fairq_class * cl)432a5b789f6SErmal Luçi fairq_class_destroy(struct fairq_class *cl)
433a5b789f6SErmal Luçi {
434a5b789f6SErmal Luçi struct fairq_if *pif;
435a5b789f6SErmal Luçi int pri;
436a5b789f6SErmal Luçi
437a5b789f6SErmal Luçi IFQ_LOCK(cl->cl_pif->pif_ifq);
438a5b789f6SErmal Luçi
439a5b789f6SErmal Luçi if (cl->cl_head)
440a5b789f6SErmal Luçi fairq_purgeq(cl);
441a5b789f6SErmal Luçi
442a5b789f6SErmal Luçi pif = cl->cl_pif;
443a5b789f6SErmal Luçi pif->pif_classes[cl->cl_pri] = NULL;
444a5b789f6SErmal Luçi if (pif->pif_poll_cache == cl)
445a5b789f6SErmal Luçi pif->pif_poll_cache = NULL;
446a5b789f6SErmal Luçi if (pif->pif_maxpri == cl->cl_pri) {
447a5b789f6SErmal Luçi for (pri = cl->cl_pri; pri >= 0; pri--)
448a5b789f6SErmal Luçi if (pif->pif_classes[pri] != NULL) {
449a5b789f6SErmal Luçi pif->pif_maxpri = pri;
450a5b789f6SErmal Luçi break;
451a5b789f6SErmal Luçi }
452a5b789f6SErmal Luçi if (pri < 0)
453a5b789f6SErmal Luçi pif->pif_maxpri = -1;
454a5b789f6SErmal Luçi }
455a5b789f6SErmal Luçi IFQ_UNLOCK(cl->cl_pif->pif_ifq);
456a5b789f6SErmal Luçi
457a5b789f6SErmal Luçi if (cl->cl_red != NULL) {
458a5b789f6SErmal Luçi #ifdef ALTQ_RIO
459a5b789f6SErmal Luçi if (cl->cl_qtype == Q_RIO)
460a5b789f6SErmal Luçi rio_destroy((rio_t *)cl->cl_red);
461a5b789f6SErmal Luçi #endif
462a5b789f6SErmal Luçi #ifdef ALTQ_RED
463a5b789f6SErmal Luçi if (cl->cl_qtype == Q_RED)
464a5b789f6SErmal Luçi red_destroy(cl->cl_red);
465a5b789f6SErmal Luçi #endif
4660a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL
4670a70aaf8SLuiz Otavio O Souza if (cl->cl_qtype == Q_CODEL)
4680a70aaf8SLuiz Otavio O Souza codel_destroy(cl->cl_codel);
4690a70aaf8SLuiz Otavio O Souza #endif
470a5b789f6SErmal Luçi }
471a5b789f6SErmal Luçi free(cl->cl_buckets, M_DEVBUF);
472a5b789f6SErmal Luçi free(cl, M_DEVBUF);
473a5b789f6SErmal Luçi
474a5b789f6SErmal Luçi return (0);
475a5b789f6SErmal Luçi }
476a5b789f6SErmal Luçi
477a5b789f6SErmal Luçi /*
478a5b789f6SErmal Luçi * fairq_enqueue is an enqueue function to be registered to
479a5b789f6SErmal Luçi * (*altq_enqueue) in struct ifaltq.
480a5b789f6SErmal Luçi */
481a5b789f6SErmal Luçi static int
fairq_enqueue(struct ifaltq * ifq,struct mbuf * m,struct altq_pktattr * pktattr)482a5b789f6SErmal Luçi fairq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
483a5b789f6SErmal Luçi {
484a5b789f6SErmal Luçi struct fairq_if *pif = (struct fairq_if *)ifq->altq_disc;
485a5b789f6SErmal Luçi struct fairq_class *cl = NULL; /* Make compiler happy */
486a5b789f6SErmal Luçi struct pf_mtag *t;
487a5b789f6SErmal Luçi u_int32_t qid_hash = 0;
488a5b789f6SErmal Luçi int len;
489a5b789f6SErmal Luçi
490a5b789f6SErmal Luçi IFQ_LOCK_ASSERT(ifq);
491a5b789f6SErmal Luçi
492a5b789f6SErmal Luçi /* grab class set by classifier */
493a5b789f6SErmal Luçi if ((m->m_flags & M_PKTHDR) == 0) {
494a5b789f6SErmal Luçi /* should not happen */
495a5b789f6SErmal Luçi printf("altq: packet for %s does not have pkthdr\n",
496a5b789f6SErmal Luçi ifq->altq_ifp->if_xname);
497a5b789f6SErmal Luçi m_freem(m);
498a5b789f6SErmal Luçi return (ENOBUFS);
499a5b789f6SErmal Luçi }
500a5b789f6SErmal Luçi
501a5b789f6SErmal Luçi if ((t = pf_find_mtag(m)) != NULL) {
502a5b789f6SErmal Luçi cl = clh_to_clp(pif, t->qid);
503a5b789f6SErmal Luçi qid_hash = t->qid_hash;
504a5b789f6SErmal Luçi }
505a5b789f6SErmal Luçi if (cl == NULL) {
506a5b789f6SErmal Luçi cl = pif->pif_default;
507a5b789f6SErmal Luçi if (cl == NULL) {
508a5b789f6SErmal Luçi m_freem(m);
509a5b789f6SErmal Luçi return (ENOBUFS);
510a5b789f6SErmal Luçi }
511a5b789f6SErmal Luçi }
512a5b789f6SErmal Luçi cl->cl_flags |= FARF_HAS_PACKETS;
513a5b789f6SErmal Luçi cl->cl_pktattr = NULL;
514a5b789f6SErmal Luçi len = m_pktlen(m);
515a5b789f6SErmal Luçi if (fairq_addq(cl, m, qid_hash) != 0) {
516a5b789f6SErmal Luçi /* drop occurred. mbuf was freed in fairq_addq. */
517a5b789f6SErmal Luçi PKTCNTR_ADD(&cl->cl_dropcnt, len);
518a5b789f6SErmal Luçi return (ENOBUFS);
519a5b789f6SErmal Luçi }
520a5b789f6SErmal Luçi IFQ_INC_LEN(ifq);
521a5b789f6SErmal Luçi
522a5b789f6SErmal Luçi return (0);
523a5b789f6SErmal Luçi }
524a5b789f6SErmal Luçi
525a5b789f6SErmal Luçi /*
526a5b789f6SErmal Luçi * fairq_dequeue is a dequeue function to be registered to
527a5b789f6SErmal Luçi * (*altq_dequeue) in struct ifaltq.
528a5b789f6SErmal Luçi *
529a5b789f6SErmal Luçi * note: ALTDQ_POLL returns the next packet without removing the packet
530a5b789f6SErmal Luçi * from the queue. ALTDQ_REMOVE is a normal dequeue operation.
531a5b789f6SErmal Luçi * ALTDQ_REMOVE must return the same packet if called immediately
532a5b789f6SErmal Luçi * after ALTDQ_POLL.
533a5b789f6SErmal Luçi */
534a5b789f6SErmal Luçi static struct mbuf *
fairq_dequeue(struct ifaltq * ifq,int op)535a5b789f6SErmal Luçi fairq_dequeue(struct ifaltq *ifq, int op)
536a5b789f6SErmal Luçi {
537a5b789f6SErmal Luçi struct fairq_if *pif = (struct fairq_if *)ifq->altq_disc;
538a5b789f6SErmal Luçi struct fairq_class *cl;
539a5b789f6SErmal Luçi struct fairq_class *best_cl;
540a5b789f6SErmal Luçi struct mbuf *best_m;
541a5b789f6SErmal Luçi struct mbuf *m = NULL;
542a5b789f6SErmal Luçi uint64_t cur_time = read_machclk();
543a5b789f6SErmal Luçi int pri;
544a5b789f6SErmal Luçi int hit_limit;
545a5b789f6SErmal Luçi
546a5b789f6SErmal Luçi IFQ_LOCK_ASSERT(ifq);
547a5b789f6SErmal Luçi
548a5b789f6SErmal Luçi if (IFQ_IS_EMPTY(ifq)) {
549a5b789f6SErmal Luçi return (NULL);
550a5b789f6SErmal Luçi }
551a5b789f6SErmal Luçi
552a5b789f6SErmal Luçi if (pif->pif_poll_cache && op == ALTDQ_REMOVE) {
553a5b789f6SErmal Luçi best_cl = pif->pif_poll_cache;
554a5b789f6SErmal Luçi m = fairq_getq(best_cl, cur_time);
555a5b789f6SErmal Luçi pif->pif_poll_cache = NULL;
556a5b789f6SErmal Luçi if (m) {
557a5b789f6SErmal Luçi IFQ_DEC_LEN(ifq);
558a5b789f6SErmal Luçi PKTCNTR_ADD(&best_cl->cl_xmitcnt, m_pktlen(m));
559a5b789f6SErmal Luçi return (m);
560a5b789f6SErmal Luçi }
561a5b789f6SErmal Luçi } else {
562a5b789f6SErmal Luçi best_cl = NULL;
563a5b789f6SErmal Luçi best_m = NULL;
564a5b789f6SErmal Luçi
565a5b789f6SErmal Luçi for (pri = pif->pif_maxpri; pri >= 0; pri--) {
566a5b789f6SErmal Luçi if ((cl = pif->pif_classes[pri]) == NULL)
567a5b789f6SErmal Luçi continue;
568a5b789f6SErmal Luçi if ((cl->cl_flags & FARF_HAS_PACKETS) == 0)
569a5b789f6SErmal Luçi continue;
570a5b789f6SErmal Luçi m = fairq_pollq(cl, cur_time, &hit_limit);
571a5b789f6SErmal Luçi if (m == NULL) {
572a5b789f6SErmal Luçi cl->cl_flags &= ~FARF_HAS_PACKETS;
573a5b789f6SErmal Luçi continue;
574a5b789f6SErmal Luçi }
575a5b789f6SErmal Luçi
576a5b789f6SErmal Luçi /*
577a5b789f6SErmal Luçi * Only override the best choice if we are under
578a5b789f6SErmal Luçi * the BW limit.
579a5b789f6SErmal Luçi */
580a5b789f6SErmal Luçi if (hit_limit == 0 || best_cl == NULL) {
581a5b789f6SErmal Luçi best_cl = cl;
582a5b789f6SErmal Luçi best_m = m;
583a5b789f6SErmal Luçi }
584a5b789f6SErmal Luçi
585a5b789f6SErmal Luçi /*
586a5b789f6SErmal Luçi * Remember the highest priority mbuf in case we
587a5b789f6SErmal Luçi * do not find any lower priority mbufs.
588a5b789f6SErmal Luçi */
589a5b789f6SErmal Luçi if (hit_limit)
590a5b789f6SErmal Luçi continue;
591a5b789f6SErmal Luçi break;
592a5b789f6SErmal Luçi }
593a5b789f6SErmal Luçi if (op == ALTDQ_POLL) {
594a5b789f6SErmal Luçi pif->pif_poll_cache = best_cl;
595a5b789f6SErmal Luçi m = best_m;
596a5b789f6SErmal Luçi } else if (best_cl) {
597a5b789f6SErmal Luçi m = fairq_getq(best_cl, cur_time);
598a5b789f6SErmal Luçi if (m != NULL) {
599a5b789f6SErmal Luçi IFQ_DEC_LEN(ifq);
600a5b789f6SErmal Luçi PKTCNTR_ADD(&best_cl->cl_xmitcnt, m_pktlen(m));
601a5b789f6SErmal Luçi }
602a5b789f6SErmal Luçi }
603a5b789f6SErmal Luçi return (m);
604a5b789f6SErmal Luçi }
605a5b789f6SErmal Luçi return (NULL);
606a5b789f6SErmal Luçi }
607a5b789f6SErmal Luçi
608a5b789f6SErmal Luçi static int
fairq_addq(struct fairq_class * cl,struct mbuf * m,u_int32_t bucketid)609a5b789f6SErmal Luçi fairq_addq(struct fairq_class *cl, struct mbuf *m, u_int32_t bucketid)
610a5b789f6SErmal Luçi {
611a5b789f6SErmal Luçi fairq_bucket_t *b;
612a5b789f6SErmal Luçi u_int hindex;
613a5b789f6SErmal Luçi uint64_t bw;
614a5b789f6SErmal Luçi
615a5b789f6SErmal Luçi /*
616a5b789f6SErmal Luçi * If the packet doesn't have any keep state put it on the end of
617a5b789f6SErmal Luçi * our queue. XXX this can result in out of order delivery.
618a5b789f6SErmal Luçi */
619a5b789f6SErmal Luçi if (bucketid == 0) {
620a5b789f6SErmal Luçi if (cl->cl_head)
621a5b789f6SErmal Luçi b = cl->cl_head->prev;
622a5b789f6SErmal Luçi else
623a5b789f6SErmal Luçi b = &cl->cl_buckets[0];
624a5b789f6SErmal Luçi } else {
625a5b789f6SErmal Luçi hindex = bucketid & cl->cl_nbucket_mask;
626a5b789f6SErmal Luçi b = &cl->cl_buckets[hindex];
627a5b789f6SErmal Luçi }
628a5b789f6SErmal Luçi
629a5b789f6SErmal Luçi /*
630a5b789f6SErmal Luçi * Add the bucket to the end of the circular list of active buckets.
631a5b789f6SErmal Luçi *
632a5b789f6SErmal Luçi * As a special case we add the bucket to the beginning of the list
633a5b789f6SErmal Luçi * instead of the end if it was not previously on the list and if
634a5b789f6SErmal Luçi * its traffic is less then the hog level.
635a5b789f6SErmal Luçi */
636a5b789f6SErmal Luçi if (b->in_use == 0) {
637a5b789f6SErmal Luçi b->in_use = 1;
638a5b789f6SErmal Luçi if (cl->cl_head == NULL) {
639a5b789f6SErmal Luçi cl->cl_head = b;
640a5b789f6SErmal Luçi b->next = b;
641a5b789f6SErmal Luçi b->prev = b;
642a5b789f6SErmal Luçi } else {
643a5b789f6SErmal Luçi b->next = cl->cl_head;
644a5b789f6SErmal Luçi b->prev = cl->cl_head->prev;
645a5b789f6SErmal Luçi b->prev->next = b;
646a5b789f6SErmal Luçi b->next->prev = b;
647a5b789f6SErmal Luçi
648a5b789f6SErmal Luçi if (b->bw_delta && cl->cl_hogs_m1) {
649a5b789f6SErmal Luçi bw = b->bw_bytes * machclk_freq / b->bw_delta;
650a5b789f6SErmal Luçi if (bw < cl->cl_hogs_m1)
651a5b789f6SErmal Luçi cl->cl_head = b;
652a5b789f6SErmal Luçi }
653a5b789f6SErmal Luçi }
654a5b789f6SErmal Luçi }
655a5b789f6SErmal Luçi
656a5b789f6SErmal Luçi #ifdef ALTQ_RIO
657a5b789f6SErmal Luçi if (cl->cl_qtype == Q_RIO)
658a5b789f6SErmal Luçi return rio_addq((rio_t *)cl->cl_red, &b->queue, m, cl->cl_pktattr);
659a5b789f6SErmal Luçi #endif
660a5b789f6SErmal Luçi #ifdef ALTQ_RED
661a5b789f6SErmal Luçi if (cl->cl_qtype == Q_RED)
662a5b789f6SErmal Luçi return red_addq(cl->cl_red, &b->queue, m, cl->cl_pktattr);
663a5b789f6SErmal Luçi #endif
6640a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL
6650a70aaf8SLuiz Otavio O Souza if (cl->cl_qtype == Q_CODEL)
6660a70aaf8SLuiz Otavio O Souza return codel_addq(cl->cl_codel, &b->queue, m);
6670a70aaf8SLuiz Otavio O Souza #endif
668a5b789f6SErmal Luçi if (qlen(&b->queue) >= qlimit(&b->queue)) {
669a5b789f6SErmal Luçi m_freem(m);
670a5b789f6SErmal Luçi return (-1);
671a5b789f6SErmal Luçi }
672a5b789f6SErmal Luçi
673a5b789f6SErmal Luçi if (cl->cl_flags & FARF_CLEARDSCP)
674a5b789f6SErmal Luçi write_dsfield(m, cl->cl_pktattr, 0);
675a5b789f6SErmal Luçi
676a5b789f6SErmal Luçi _addq(&b->queue, m);
677a5b789f6SErmal Luçi
678a5b789f6SErmal Luçi return (0);
679a5b789f6SErmal Luçi }
680a5b789f6SErmal Luçi
681a5b789f6SErmal Luçi static struct mbuf *
fairq_getq(struct fairq_class * cl,uint64_t cur_time)682a5b789f6SErmal Luçi fairq_getq(struct fairq_class *cl, uint64_t cur_time)
683a5b789f6SErmal Luçi {
684a5b789f6SErmal Luçi fairq_bucket_t *b;
685a5b789f6SErmal Luçi struct mbuf *m;
686a5b789f6SErmal Luçi
687a5b789f6SErmal Luçi b = fairq_selectq(cl, 0);
688a5b789f6SErmal Luçi if (b == NULL)
689a5b789f6SErmal Luçi m = NULL;
690a5b789f6SErmal Luçi #ifdef ALTQ_RIO
691a5b789f6SErmal Luçi else if (cl->cl_qtype == Q_RIO)
692a5b789f6SErmal Luçi m = rio_getq((rio_t *)cl->cl_red, &b->queue);
693a5b789f6SErmal Luçi #endif
694a5b789f6SErmal Luçi #ifdef ALTQ_RED
695a5b789f6SErmal Luçi else if (cl->cl_qtype == Q_RED)
696a5b789f6SErmal Luçi m = red_getq(cl->cl_red, &b->queue);
697a5b789f6SErmal Luçi #endif
6980a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL
6990a70aaf8SLuiz Otavio O Souza else if (cl->cl_qtype == Q_CODEL)
7000a70aaf8SLuiz Otavio O Souza m = codel_getq(cl->cl_codel, &b->queue);
7010a70aaf8SLuiz Otavio O Souza #endif
702a5b789f6SErmal Luçi else
703a5b789f6SErmal Luçi m = _getq(&b->queue);
704a5b789f6SErmal Luçi
705a5b789f6SErmal Luçi /*
706a5b789f6SErmal Luçi * Calculate the BW change
707a5b789f6SErmal Luçi */
708a5b789f6SErmal Luçi if (m != NULL) {
709a5b789f6SErmal Luçi uint64_t delta;
710a5b789f6SErmal Luçi
711a5b789f6SErmal Luçi /*
712a5b789f6SErmal Luçi * Per-class bandwidth calculation
713a5b789f6SErmal Luçi */
714a5b789f6SErmal Luçi delta = (cur_time - cl->cl_last_time);
715a5b789f6SErmal Luçi if (delta > machclk_freq * 8)
716a5b789f6SErmal Luçi delta = machclk_freq * 8;
717a5b789f6SErmal Luçi cl->cl_bw_delta += delta;
718a5b789f6SErmal Luçi cl->cl_bw_bytes += m->m_pkthdr.len;
719a5b789f6SErmal Luçi cl->cl_last_time = cur_time;
720a5b789f6SErmal Luçi cl->cl_bw_delta -= cl->cl_bw_delta >> 3;
721a5b789f6SErmal Luçi cl->cl_bw_bytes -= cl->cl_bw_bytes >> 3;
722a5b789f6SErmal Luçi
723a5b789f6SErmal Luçi /*
724a5b789f6SErmal Luçi * Per-bucket bandwidth calculation
725a5b789f6SErmal Luçi */
726a5b789f6SErmal Luçi delta = (cur_time - b->last_time);
727a5b789f6SErmal Luçi if (delta > machclk_freq * 8)
728a5b789f6SErmal Luçi delta = machclk_freq * 8;
729a5b789f6SErmal Luçi b->bw_delta += delta;
730a5b789f6SErmal Luçi b->bw_bytes += m->m_pkthdr.len;
731a5b789f6SErmal Luçi b->last_time = cur_time;
732a5b789f6SErmal Luçi b->bw_delta -= b->bw_delta >> 3;
733a5b789f6SErmal Luçi b->bw_bytes -= b->bw_bytes >> 3;
734a5b789f6SErmal Luçi }
735a5b789f6SErmal Luçi return(m);
736a5b789f6SErmal Luçi }
737a5b789f6SErmal Luçi
738a5b789f6SErmal Luçi /*
739a5b789f6SErmal Luçi * Figure out what the next packet would be if there were no limits. If
740a5b789f6SErmal Luçi * this class hits its bandwidth limit *hit_limit is set to no-zero, otherwise
741a5b789f6SErmal Luçi * it is set to 0. A non-NULL mbuf is returned either way.
742a5b789f6SErmal Luçi */
743a5b789f6SErmal Luçi static struct mbuf *
fairq_pollq(struct fairq_class * cl,uint64_t cur_time,int * hit_limit)744a5b789f6SErmal Luçi fairq_pollq(struct fairq_class *cl, uint64_t cur_time, int *hit_limit)
745a5b789f6SErmal Luçi {
746a5b789f6SErmal Luçi fairq_bucket_t *b;
747a5b789f6SErmal Luçi struct mbuf *m;
748a5b789f6SErmal Luçi uint64_t delta;
749a5b789f6SErmal Luçi uint64_t bw;
750a5b789f6SErmal Luçi
751a5b789f6SErmal Luçi *hit_limit = 0;
752a5b789f6SErmal Luçi b = fairq_selectq(cl, 1);
753a5b789f6SErmal Luçi if (b == NULL)
754a5b789f6SErmal Luçi return(NULL);
755a5b789f6SErmal Luçi m = qhead(&b->queue);
756a5b789f6SErmal Luçi
757a5b789f6SErmal Luçi /*
758a5b789f6SErmal Luçi * Did this packet exceed the class bandwidth? Calculate the
759a5b789f6SErmal Luçi * bandwidth component of the packet.
760a5b789f6SErmal Luçi *
761a5b789f6SErmal Luçi * - Calculate bytes per second
762a5b789f6SErmal Luçi */
763a5b789f6SErmal Luçi delta = cur_time - cl->cl_last_time;
764a5b789f6SErmal Luçi if (delta > machclk_freq * 8)
765a5b789f6SErmal Luçi delta = machclk_freq * 8;
766a5b789f6SErmal Luçi cl->cl_bw_delta += delta;
767a5b789f6SErmal Luçi cl->cl_last_time = cur_time;
768a5b789f6SErmal Luçi if (cl->cl_bw_delta) {
769a5b789f6SErmal Luçi bw = cl->cl_bw_bytes * machclk_freq / cl->cl_bw_delta;
770a5b789f6SErmal Luçi
771a5b789f6SErmal Luçi if (bw > cl->cl_bandwidth)
772a5b789f6SErmal Luçi *hit_limit = 1;
773a5b789f6SErmal Luçi #ifdef ALTQ_DEBUG
7749656119dSBjoern A. Zeeb printf("BW %6ju relative to %6u %d queue %p\n",
7759656119dSBjoern A. Zeeb (uintmax_t)bw, cl->cl_bandwidth, *hit_limit, b);
776a5b789f6SErmal Luçi #endif
777a5b789f6SErmal Luçi }
778a5b789f6SErmal Luçi return(m);
779a5b789f6SErmal Luçi }
780a5b789f6SErmal Luçi
781a5b789f6SErmal Luçi /*
782a5b789f6SErmal Luçi * Locate the next queue we want to pull a packet out of. This code
783a5b789f6SErmal Luçi * is also responsible for removing empty buckets from the circular list.
784a5b789f6SErmal Luçi */
785a5b789f6SErmal Luçi static
786a5b789f6SErmal Luçi fairq_bucket_t *
fairq_selectq(struct fairq_class * cl,int ispoll)787a5b789f6SErmal Luçi fairq_selectq(struct fairq_class *cl, int ispoll)
788a5b789f6SErmal Luçi {
789a5b789f6SErmal Luçi fairq_bucket_t *b;
790a5b789f6SErmal Luçi uint64_t bw;
791a5b789f6SErmal Luçi
792a5b789f6SErmal Luçi if (ispoll == 0 && cl->cl_polled) {
793a5b789f6SErmal Luçi b = cl->cl_polled;
794a5b789f6SErmal Luçi cl->cl_polled = NULL;
795a5b789f6SErmal Luçi return(b);
796a5b789f6SErmal Luçi }
797a5b789f6SErmal Luçi
798a5b789f6SErmal Luçi while ((b = cl->cl_head) != NULL) {
799a5b789f6SErmal Luçi /*
800a5b789f6SErmal Luçi * Remove empty queues from consideration
801a5b789f6SErmal Luçi */
802a5b789f6SErmal Luçi if (qempty(&b->queue)) {
803a5b789f6SErmal Luçi b->in_use = 0;
804a5b789f6SErmal Luçi cl->cl_head = b->next;
805a5b789f6SErmal Luçi if (cl->cl_head == b) {
806a5b789f6SErmal Luçi cl->cl_head = NULL;
807a5b789f6SErmal Luçi } else {
808a5b789f6SErmal Luçi b->next->prev = b->prev;
809a5b789f6SErmal Luçi b->prev->next = b->next;
810a5b789f6SErmal Luçi }
811a5b789f6SErmal Luçi continue;
812a5b789f6SErmal Luçi }
813a5b789f6SErmal Luçi
814a5b789f6SErmal Luçi /*
815a5b789f6SErmal Luçi * Advance the round robin. Queues with bandwidths less
816a5b789f6SErmal Luçi * then the hog bandwidth are allowed to burst.
817a5b789f6SErmal Luçi */
818a5b789f6SErmal Luçi if (cl->cl_hogs_m1 == 0) {
819a5b789f6SErmal Luçi cl->cl_head = b->next;
820a5b789f6SErmal Luçi } else if (b->bw_delta) {
821a5b789f6SErmal Luçi bw = b->bw_bytes * machclk_freq / b->bw_delta;
822a5b789f6SErmal Luçi if (bw >= cl->cl_hogs_m1) {
823a5b789f6SErmal Luçi cl->cl_head = b->next;
824a5b789f6SErmal Luçi }
825a5b789f6SErmal Luçi /*
826a5b789f6SErmal Luçi * XXX TODO -
827a5b789f6SErmal Luçi */
828a5b789f6SErmal Luçi }
829a5b789f6SErmal Luçi
830a5b789f6SErmal Luçi /*
831a5b789f6SErmal Luçi * Return bucket b.
832a5b789f6SErmal Luçi */
833a5b789f6SErmal Luçi break;
834a5b789f6SErmal Luçi }
835a5b789f6SErmal Luçi if (ispoll)
836a5b789f6SErmal Luçi cl->cl_polled = b;
837a5b789f6SErmal Luçi return(b);
838a5b789f6SErmal Luçi }
839a5b789f6SErmal Luçi
840a5b789f6SErmal Luçi static void
fairq_purgeq(struct fairq_class * cl)841a5b789f6SErmal Luçi fairq_purgeq(struct fairq_class *cl)
842a5b789f6SErmal Luçi {
843a5b789f6SErmal Luçi fairq_bucket_t *b;
844a5b789f6SErmal Luçi struct mbuf *m;
845a5b789f6SErmal Luçi
846a5b789f6SErmal Luçi while ((b = fairq_selectq(cl, 0)) != NULL) {
847a5b789f6SErmal Luçi while ((m = _getq(&b->queue)) != NULL) {
848a5b789f6SErmal Luçi PKTCNTR_ADD(&cl->cl_dropcnt, m_pktlen(m));
849a5b789f6SErmal Luçi m_freem(m);
850a5b789f6SErmal Luçi }
851a5b789f6SErmal Luçi ASSERT(qlen(&b->queue) == 0);
852a5b789f6SErmal Luçi }
853a5b789f6SErmal Luçi }
854a5b789f6SErmal Luçi
855a5b789f6SErmal Luçi static void
get_class_stats(struct fairq_classstats * sp,struct fairq_class * cl)856a5b789f6SErmal Luçi get_class_stats(struct fairq_classstats *sp, struct fairq_class *cl)
857a5b789f6SErmal Luçi {
858a5b789f6SErmal Luçi fairq_bucket_t *b;
859a5b789f6SErmal Luçi
860a5b789f6SErmal Luçi sp->class_handle = cl->cl_handle;
861a5b789f6SErmal Luçi sp->qlimit = cl->cl_qlimit;
862a5b789f6SErmal Luçi sp->xmit_cnt = cl->cl_xmitcnt;
863a5b789f6SErmal Luçi sp->drop_cnt = cl->cl_dropcnt;
864a5b789f6SErmal Luçi sp->qtype = cl->cl_qtype;
865a5b789f6SErmal Luçi sp->qlength = 0;
866a5b789f6SErmal Luçi
867a5b789f6SErmal Luçi if (cl->cl_head) {
868a5b789f6SErmal Luçi b = cl->cl_head;
869a5b789f6SErmal Luçi do {
870a5b789f6SErmal Luçi sp->qlength += qlen(&b->queue);
871a5b789f6SErmal Luçi b = b->next;
872a5b789f6SErmal Luçi } while (b != cl->cl_head);
873a5b789f6SErmal Luçi }
874a5b789f6SErmal Luçi
875a5b789f6SErmal Luçi #ifdef ALTQ_RED
876a5b789f6SErmal Luçi if (cl->cl_qtype == Q_RED)
877a5b789f6SErmal Luçi red_getstats(cl->cl_red, &sp->red[0]);
878a5b789f6SErmal Luçi #endif
879a5b789f6SErmal Luçi #ifdef ALTQ_RIO
880a5b789f6SErmal Luçi if (cl->cl_qtype == Q_RIO)
881a5b789f6SErmal Luçi rio_getstats((rio_t *)cl->cl_red, &sp->red[0]);
882a5b789f6SErmal Luçi #endif
8830a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL
8840a70aaf8SLuiz Otavio O Souza if (cl->cl_qtype == Q_CODEL)
8850a70aaf8SLuiz Otavio O Souza codel_getstats(cl->cl_codel, &sp->codel);
8860a70aaf8SLuiz Otavio O Souza #endif
887a5b789f6SErmal Luçi }
888a5b789f6SErmal Luçi
889a5b789f6SErmal Luçi /* convert a class handle to the corresponding class pointer */
890a5b789f6SErmal Luçi static struct fairq_class *
clh_to_clp(struct fairq_if * pif,uint32_t chandle)891a5b789f6SErmal Luçi clh_to_clp(struct fairq_if *pif, uint32_t chandle)
892a5b789f6SErmal Luçi {
893a5b789f6SErmal Luçi struct fairq_class *cl;
894a5b789f6SErmal Luçi int idx;
895a5b789f6SErmal Luçi
896a5b789f6SErmal Luçi if (chandle == 0)
897a5b789f6SErmal Luçi return (NULL);
898a5b789f6SErmal Luçi
899a5b789f6SErmal Luçi for (idx = pif->pif_maxpri; idx >= 0; idx--)
900a5b789f6SErmal Luçi if ((cl = pif->pif_classes[idx]) != NULL &&
901a5b789f6SErmal Luçi cl->cl_handle == chandle)
902a5b789f6SErmal Luçi return (cl);
903a5b789f6SErmal Luçi
904a5b789f6SErmal Luçi return (NULL);
905a5b789f6SErmal Luçi }
906a5b789f6SErmal Luçi
907a5b789f6SErmal Luçi #endif /* ALTQ_FAIRQ */
908