Home | History | Annotate | Line # | Download | only in altq
altq_wfq.c revision 1.7.4.2
      1  1.7.4.2     yamt /*	$NetBSD: altq_wfq.c,v 1.7.4.2 2006/12/30 20:45:17 yamt Exp $	*/
      2  1.7.4.2     yamt /*	$KAME: altq_wfq.c,v 1.14 2005/04/13 03:44:25 suz Exp $	*/
      3      1.1  thorpej 
      4      1.1  thorpej /*
      5  1.7.4.2     yamt  * Copyright (C) 1997-2002
      6      1.1  thorpej  *	Sony Computer Science Laboratories Inc.  All rights reserved.
      7      1.1  thorpej  *
      8      1.1  thorpej  * Redistribution and use in source and binary forms, with or without
      9      1.1  thorpej  * modification, are permitted provided that the following conditions
     10      1.1  thorpej  * are met:
     11      1.1  thorpej  * 1. Redistributions of source code must retain the above copyright
     12      1.1  thorpej  *    notice, this list of conditions and the following disclaimer.
     13      1.1  thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     14      1.1  thorpej  *    notice, this list of conditions and the following disclaimer in the
     15      1.1  thorpej  *    documentation and/or other materials provided with the distribution.
     16      1.1  thorpej  *
     17      1.1  thorpej  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
     18      1.1  thorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19      1.1  thorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20      1.1  thorpej  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
     21      1.1  thorpej  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22      1.1  thorpej  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23      1.1  thorpej  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24      1.1  thorpej  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25      1.1  thorpej  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26      1.1  thorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27      1.1  thorpej  * SUCH DAMAGE.
     28      1.1  thorpej  */
     29      1.1  thorpej /*
     30      1.1  thorpej  *  March 27, 1997.  Written by Hiroshi Kyusojin of Keio University
     31      1.7    perry  *  (kyu (at) mt.cs.keio.ac.jp).
     32      1.1  thorpej  */
     33      1.4    lukem 
     34      1.4    lukem #include <sys/cdefs.h>
     35  1.7.4.2     yamt __KERNEL_RCSID(0, "$NetBSD: altq_wfq.c,v 1.7.4.2 2006/12/30 20:45:17 yamt Exp $");
     36      1.1  thorpej 
     37  1.7.4.2     yamt #ifdef _KERNEL_OPT
     38      1.1  thorpej #include "opt_altq.h"
     39      1.1  thorpej #include "opt_inet.h"
     40      1.1  thorpej #endif
     41  1.7.4.2     yamt 
     42      1.1  thorpej #ifdef ALTQ_WFQ
     43      1.1  thorpej 
     44      1.1  thorpej #include <sys/param.h>
     45      1.1  thorpej #include <sys/malloc.h>
     46      1.1  thorpej #include <sys/mbuf.h>
     47      1.1  thorpej #include <sys/uio.h>
     48      1.1  thorpej #include <sys/socket.h>
     49      1.1  thorpej #include <sys/systm.h>
     50      1.1  thorpej #include <sys/proc.h>
     51      1.1  thorpej #include <sys/errno.h>
     52      1.1  thorpej #include <sys/time.h>
     53      1.1  thorpej #include <sys/kernel.h>
     54  1.7.4.1     yamt #include <sys/kauth.h>
     55      1.1  thorpej 
     56      1.1  thorpej #include <net/if.h>
     57      1.1  thorpej #include <net/if_types.h>
     58      1.1  thorpej #include <netinet/in.h>
     59      1.1  thorpej 
     60      1.1  thorpej #include <altq/altq.h>
     61      1.1  thorpej #include <altq/altq_conf.h>
     62      1.1  thorpej #include <altq/altq_wfq.h>
     63      1.1  thorpej 
     64  1.7.4.2     yamt #ifdef ALTQ3_COMPAT
     65      1.1  thorpej /*
     66      1.1  thorpej #define	WFQ_DEBUG
     67      1.1  thorpej */
     68      1.1  thorpej 
     69      1.1  thorpej static int		wfq_setenable(struct wfq_interface *, int);
     70      1.1  thorpej static int		wfq_ifattach(struct wfq_interface *);
     71      1.1  thorpej static int		wfq_ifdetach(struct wfq_interface *);
     72      1.1  thorpej static int		wfq_ifenqueue(struct ifaltq *, struct mbuf *,
     73      1.1  thorpej 				      struct altq_pktattr *);
     74      1.1  thorpej static u_long		wfq_hash(struct flowinfo *, int);
     75  1.7.4.1     yamt static inline u_long	wfq_hashbydstaddr(struct flowinfo *, int);
     76  1.7.4.1     yamt static inline u_long	wfq_hashbysrcport(struct flowinfo *, int);
     77      1.1  thorpej static wfq		*wfq_maxqueue(wfq_state_t *);
     78      1.1  thorpej static struct mbuf	*wfq_ifdequeue(struct ifaltq *, int);
     79      1.1  thorpej static int		wfq_getqid(struct wfq_getqid *);
     80      1.1  thorpej static int		wfq_setweight(struct wfq_setweight *);
     81      1.1  thorpej static int		wfq_getstats(struct wfq_getstats *);
     82      1.1  thorpej static int		wfq_config(struct wfq_conf *);
     83  1.7.4.2     yamt static int		wfq_request(struct ifaltq *, int, void *);
     84      1.1  thorpej static int		wfq_flush(struct ifaltq *);
     85      1.1  thorpej static void		*wfq_classify(void *, struct mbuf *, int);
     86      1.1  thorpej 
     87      1.1  thorpej /* global value : pointer to wfq queue list */
     88      1.1  thorpej static wfq_state_t *wfq_list = NULL;
     89      1.1  thorpej 
     90      1.1  thorpej static int
     91  1.7.4.2     yamt wfq_setenable(struct wfq_interface *ifacep, int flag)
     92      1.1  thorpej {
     93      1.1  thorpej 	wfq_state_t *wfqp;
     94      1.1  thorpej 	int error = 0;
     95      1.1  thorpej 
     96      1.1  thorpej 	if ((wfqp = altq_lookup(ifacep->wfq_ifacename, ALTQT_WFQ)) == NULL)
     97      1.1  thorpej 		return (EBADF);
     98      1.1  thorpej 
     99      1.1  thorpej 	switch(flag){
    100      1.1  thorpej 	case ENABLE:
    101      1.1  thorpej 		error = altq_enable(wfqp->ifq);
    102      1.1  thorpej 		break;
    103      1.1  thorpej 	case DISABLE:
    104      1.1  thorpej 		error = altq_disable(wfqp->ifq);
    105      1.1  thorpej 		break;
    106      1.1  thorpej 	}
    107      1.1  thorpej 	return error;
    108      1.1  thorpej }
    109      1.1  thorpej 
    110      1.1  thorpej 
    111      1.1  thorpej static int
    112  1.7.4.2     yamt wfq_ifattach(struct wfq_interface *ifacep)
    113      1.1  thorpej {
    114      1.1  thorpej 	int error = 0, i;
    115      1.1  thorpej 	struct ifnet *ifp;
    116      1.1  thorpej 	wfq_state_t *new_wfqp;
    117      1.1  thorpej 	wfq *queue;
    118      1.1  thorpej 
    119      1.1  thorpej 	if ((ifp = ifunit(ifacep->wfq_ifacename)) == NULL) {
    120      1.1  thorpej #ifdef WFQ_DEBUG
    121      1.1  thorpej 		printf("wfq_ifattach()...no ifp found\n");
    122      1.1  thorpej #endif
    123      1.1  thorpej 		return (ENXIO);
    124      1.1  thorpej 	}
    125      1.1  thorpej 
    126      1.1  thorpej 	if (!ALTQ_IS_READY(&ifp->if_snd)) {
    127      1.1  thorpej #ifdef WFQ_DEBUG
    128      1.1  thorpej 		printf("wfq_ifattach()...altq is not ready\n");
    129      1.1  thorpej #endif
    130      1.1  thorpej 		return (ENXIO);
    131      1.1  thorpej 	}
    132      1.1  thorpej 
    133      1.1  thorpej 	/* allocate and initialize wfq_state_t */
    134  1.7.4.1     yamt 	new_wfqp = malloc(sizeof(wfq_state_t), M_DEVBUF, M_WAITOK|M_ZERO);
    135      1.1  thorpej 	if (new_wfqp == NULL)
    136      1.1  thorpej 		return (ENOMEM);
    137  1.7.4.2     yamt 
    138  1.7.4.1     yamt 	queue = malloc(sizeof(wfq) * DEFAULT_QSIZE, M_DEVBUF, M_WAITOK|M_ZERO);
    139      1.1  thorpej 	if (queue == NULL) {
    140  1.7.4.1     yamt 		free(new_wfqp, M_DEVBUF);
    141      1.1  thorpej 		return (ENOMEM);
    142      1.1  thorpej 	}
    143      1.1  thorpej 
    144      1.1  thorpej 	/* keep the ifq */
    145      1.1  thorpej 	new_wfqp->ifq = &ifp->if_snd;
    146      1.1  thorpej 	new_wfqp->nums = DEFAULT_QSIZE;
    147      1.1  thorpej 	new_wfqp->hwm = HWM;
    148      1.1  thorpej 	new_wfqp->bytes = 0;
    149      1.1  thorpej 	new_wfqp->rrp = NULL;
    150      1.1  thorpej 	new_wfqp->queue = queue;
    151      1.1  thorpej 	new_wfqp->hash_func = wfq_hashbydstaddr;
    152      1.1  thorpej 	new_wfqp->fbmask = FIMB4_DADDR;
    153      1.1  thorpej 
    154      1.1  thorpej 	for (i = 0; i < new_wfqp->nums; i++, queue++) {
    155      1.1  thorpej 		queue->next = queue->prev = NULL;
    156      1.1  thorpej 		queue->head = queue->tail = NULL;
    157      1.1  thorpej 		queue->bytes = queue->quota = 0;
    158      1.1  thorpej 		queue->weight = 100;
    159      1.1  thorpej 	}
    160      1.1  thorpej 
    161      1.1  thorpej 	/*
    162      1.1  thorpej 	 * set WFQ to this ifnet structure.
    163      1.1  thorpej 	 */
    164      1.1  thorpej 	if ((error = altq_attach(&ifp->if_snd, ALTQT_WFQ, new_wfqp,
    165      1.1  thorpej 				 wfq_ifenqueue, wfq_ifdequeue, wfq_request,
    166      1.1  thorpej 				 new_wfqp, wfq_classify)) != 0) {
    167  1.7.4.1     yamt 		free(queue, M_DEVBUF);
    168  1.7.4.1     yamt 		free(new_wfqp, M_DEVBUF);
    169      1.1  thorpej 		return (error);
    170      1.1  thorpej 	}
    171      1.1  thorpej 
    172      1.1  thorpej 	new_wfqp->next = wfq_list;
    173      1.1  thorpej 	wfq_list = new_wfqp;
    174      1.1  thorpej 
    175      1.1  thorpej 	return (error);
    176      1.1  thorpej }
    177      1.1  thorpej 
    178      1.1  thorpej 
    179      1.1  thorpej static int
    180  1.7.4.2     yamt wfq_ifdetach(struct wfq_interface *ifacep)
    181      1.1  thorpej {
    182      1.1  thorpej 	int		error = 0;
    183      1.1  thorpej 	wfq_state_t	*wfqp;
    184      1.1  thorpej 
    185      1.1  thorpej 	if ((wfqp = altq_lookup(ifacep->wfq_ifacename, ALTQT_WFQ)) == NULL)
    186      1.1  thorpej 		return (EBADF);
    187      1.1  thorpej 
    188      1.1  thorpej 	/* free queued mbuf */
    189      1.1  thorpej 	wfq_flush(wfqp->ifq);
    190      1.1  thorpej 
    191      1.1  thorpej 	/* remove WFQ from the ifnet structure. */
    192      1.1  thorpej 	(void)altq_disable(wfqp->ifq);
    193      1.1  thorpej 	(void)altq_detach(wfqp->ifq);
    194      1.7    perry 
    195      1.1  thorpej 	/* remove from the wfqstate list */
    196      1.1  thorpej 	if (wfq_list == wfqp)
    197      1.1  thorpej 		wfq_list = wfqp->next;
    198      1.1  thorpej 	else {
    199      1.1  thorpej 		wfq_state_t *wp = wfq_list;
    200      1.1  thorpej 		do {
    201      1.1  thorpej 			if (wp->next == wfqp) {
    202      1.1  thorpej 				wp->next = wfqp->next;
    203      1.1  thorpej 				break;
    204      1.1  thorpej 			}
    205      1.1  thorpej 		} while ((wp = wp->next) != NULL);
    206      1.1  thorpej 	}
    207      1.7    perry 
    208      1.1  thorpej 	/* deallocate wfq_state_t */
    209  1.7.4.1     yamt 	free(wfqp->queue, M_DEVBUF);
    210  1.7.4.1     yamt 	free(wfqp, M_DEVBUF);
    211      1.1  thorpej 	return (error);
    212      1.1  thorpej }
    213      1.1  thorpej 
    214      1.1  thorpej static int
    215  1.7.4.2     yamt wfq_request(struct ifaltq *ifq, int req, void *arg)
    216      1.1  thorpej {
    217      1.1  thorpej 	wfq_state_t *wfqp = (wfq_state_t *)ifq->altq_disc;
    218      1.1  thorpej 
    219      1.1  thorpej 	switch (req) {
    220      1.1  thorpej 	case ALTRQ_PURGE:
    221      1.1  thorpej 		wfq_flush(wfqp->ifq);
    222      1.1  thorpej 		break;
    223      1.1  thorpej 	}
    224      1.1  thorpej 	return (0);
    225      1.1  thorpej }
    226      1.1  thorpej 
    227      1.1  thorpej 
    228      1.1  thorpej static int
    229  1.7.4.2     yamt wfq_flush(struct ifaltq *ifq)
    230      1.1  thorpej {
    231      1.1  thorpej 	struct mbuf *mp;
    232      1.1  thorpej 
    233      1.1  thorpej 	while ((mp = wfq_ifdequeue(ifq, ALTDQ_REMOVE)) != NULL)
    234      1.1  thorpej 		m_freem(mp);
    235      1.1  thorpej 	if (ALTQ_IS_ENABLED(ifq))
    236      1.1  thorpej 		ifq->ifq_len = 0;
    237      1.1  thorpej 	return 0;
    238      1.1  thorpej }
    239      1.1  thorpej 
    240      1.1  thorpej static void *
    241  1.7.4.2     yamt wfq_classify(void *clfier, struct mbuf *m, int af)
    242      1.1  thorpej {
    243      1.1  thorpej 	wfq_state_t *wfqp = (wfq_state_t *)clfier;
    244      1.1  thorpej 	struct flowinfo flow;
    245      1.1  thorpej 
    246      1.1  thorpej 	altq_extractflow(m, af, &flow, wfqp->fbmask);
    247      1.1  thorpej 	return (&wfqp->queue[(*wfqp->hash_func)(&flow, wfqp->nums)]);
    248      1.1  thorpej }
    249      1.1  thorpej 
    250      1.1  thorpej static int
    251  1.7.4.2     yamt wfq_ifenqueue(struct ifaltq *ifq, struct mbuf *mp, struct altq_pktattr *pktattr)
    252      1.1  thorpej {
    253      1.1  thorpej 	wfq_state_t *wfqp;
    254      1.1  thorpej 	wfq *queue;
    255      1.1  thorpej 	int byte, error = 0;
    256      1.1  thorpej 
    257      1.1  thorpej 	wfqp = (wfq_state_t *)ifq->altq_disc;
    258      1.1  thorpej 	mp->m_nextpkt = NULL;
    259      1.1  thorpej 
    260      1.1  thorpej 	/* grab a queue selected by classifier */
    261      1.1  thorpej 	if (pktattr == NULL || (queue = pktattr->pattr_class) == NULL)
    262      1.1  thorpej 		queue = &wfqp->queue[0];
    263      1.1  thorpej 
    264      1.1  thorpej 	if (queue->tail == NULL)
    265      1.1  thorpej 		queue->head = mp;
    266      1.1  thorpej 	else
    267      1.1  thorpej 		queue->tail->m_nextpkt = mp;
    268      1.1  thorpej 	queue->tail = mp;
    269      1.1  thorpej 	byte = mp->m_pkthdr.len;
    270      1.1  thorpej 	queue->bytes += byte;
    271      1.1  thorpej 	wfqp->bytes += byte;
    272      1.1  thorpej 	ifq->ifq_len++;
    273      1.1  thorpej 
    274      1.1  thorpej 	if (queue->next == NULL) {
    275      1.1  thorpej 		/* this queue gets active. add the queue to the active list */
    276      1.1  thorpej 		if (wfqp->rrp == NULL){
    277      1.1  thorpej 			/* no queue in the active list */
    278      1.1  thorpej 			queue->next = queue->prev = queue;
    279      1.1  thorpej 			wfqp->rrp = queue;
    280      1.1  thorpej 			WFQ_ADDQUOTA(queue);
    281      1.1  thorpej 		} else {
    282      1.1  thorpej 			/* insert the queue at the tail of the active list */
    283      1.1  thorpej 			queue->prev = wfqp->rrp->prev;
    284      1.1  thorpej 			wfqp->rrp->prev->next = queue;
    285      1.1  thorpej 			wfqp->rrp->prev = queue;
    286      1.1  thorpej 			queue->next = wfqp->rrp;
    287      1.1  thorpej 			queue->quota = 0;
    288      1.1  thorpej 		}
    289      1.1  thorpej 	}
    290      1.1  thorpej 
    291      1.1  thorpej 	/* check overflow. if the total size exceeds the high water mark,
    292      1.1  thorpej 	   drop packets from the longest queue. */
    293      1.1  thorpej 	while (wfqp->bytes > wfqp->hwm) {
    294      1.1  thorpej 		wfq *drop_queue = wfq_maxqueue(wfqp);
    295      1.1  thorpej 
    296      1.1  thorpej 		/* drop the packet at the head. */
    297      1.1  thorpej 		mp = drop_queue->head;
    298      1.1  thorpej 		if ((drop_queue->head = mp->m_nextpkt) == NULL)
    299      1.1  thorpej 			drop_queue->tail = NULL;
    300      1.1  thorpej 		mp->m_nextpkt = NULL;
    301      1.1  thorpej 		byte = mp->m_pkthdr.len;
    302      1.1  thorpej 		drop_queue->bytes -= byte;
    303      1.1  thorpej 		PKTCNTR_ADD(&drop_queue->drop_cnt, byte);
    304      1.1  thorpej 		wfqp->bytes -= byte;
    305      1.1  thorpej 		m_freem(mp);
    306      1.1  thorpej 		ifq->ifq_len--;
    307      1.1  thorpej 		if(drop_queue == queue)
    308      1.1  thorpej 			/* the queue for this flow is selected to drop */
    309      1.1  thorpej 			error = ENOBUFS;
    310      1.1  thorpej 	}
    311      1.1  thorpej 	return error;
    312      1.1  thorpej }
    313      1.7    perry 
    314  1.7.4.2     yamt static u_long
    315  1.7.4.2     yamt wfq_hash(struct flowinfo *flow, int n)
    316      1.1  thorpej {
    317      1.1  thorpej 	u_long val = 0;
    318      1.1  thorpej 
    319      1.1  thorpej 	if (flow != NULL) {
    320      1.1  thorpej 		if (flow->fi_family == AF_INET) {
    321      1.1  thorpej 			struct flowinfo_in *fp = (struct flowinfo_in *)flow;
    322      1.1  thorpej 			u_long val2;
    323      1.1  thorpej 
    324      1.1  thorpej 			val = fp->fi_dst.s_addr ^ fp->fi_src.s_addr;
    325      1.1  thorpej 			val = val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24);
    326      1.1  thorpej 			val2 = fp->fi_dport ^ fp->fi_sport ^ fp->fi_proto;
    327      1.1  thorpej 			val2 = val2 ^ (val2 >> 8);
    328      1.1  thorpej 			val = val ^ val2;
    329      1.1  thorpej 		}
    330      1.1  thorpej #ifdef INET6
    331      1.1  thorpej 		else if (flow->fi_family == AF_INET6) {
    332      1.1  thorpej 			struct flowinfo_in6 *fp6 = (struct flowinfo_in6 *)flow;
    333      1.1  thorpej 
    334      1.1  thorpej 			val = ntohl(fp6->fi6_flowlabel);
    335      1.1  thorpej 		}
    336      1.1  thorpej #endif
    337      1.1  thorpej 	}
    338      1.1  thorpej 
    339      1.1  thorpej 	return (val % n);
    340      1.1  thorpej }
    341      1.1  thorpej 
    342  1.7.4.2     yamt static inline u_long
    343  1.7.4.2     yamt wfq_hashbydstaddr(struct flowinfo *flow, int n)
    344      1.1  thorpej {
    345      1.1  thorpej 	u_long val = 0;
    346      1.1  thorpej 
    347      1.1  thorpej 	if (flow != NULL) {
    348      1.1  thorpej 		if (flow->fi_family == AF_INET) {
    349      1.1  thorpej 			struct flowinfo_in *fp = (struct flowinfo_in *)flow;
    350      1.1  thorpej 
    351      1.1  thorpej 			val = fp->fi_dst.s_addr;
    352      1.1  thorpej 			val = val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24);
    353      1.1  thorpej 		}
    354      1.1  thorpej #ifdef INET6
    355      1.1  thorpej 		else if (flow->fi_family == AF_INET6) {
    356      1.1  thorpej 			struct flowinfo_in6 *fp6 = (struct flowinfo_in6 *)flow;
    357      1.1  thorpej 
    358      1.1  thorpej 			val = ntohl(fp6->fi6_flowlabel);
    359      1.1  thorpej 		}
    360      1.1  thorpej #endif
    361      1.1  thorpej 	}
    362      1.1  thorpej 
    363      1.1  thorpej 	return (val % n);
    364      1.1  thorpej }
    365      1.1  thorpej 
    366  1.7.4.2     yamt static inline u_long
    367  1.7.4.2     yamt wfq_hashbysrcport(struct flowinfo *flow, int n)
    368      1.1  thorpej {
    369      1.1  thorpej 	u_long val = 0;
    370      1.1  thorpej 
    371      1.1  thorpej 	if (flow != NULL) {
    372      1.1  thorpej 		if (flow->fi_family == AF_INET) {
    373      1.1  thorpej 			struct flowinfo_in *fp = (struct flowinfo_in *)flow;
    374      1.1  thorpej 
    375      1.1  thorpej 			val = fp->fi_sport;
    376      1.1  thorpej 		}
    377      1.1  thorpej #ifdef INET6
    378      1.1  thorpej 		else if (flow->fi_family == AF_INET6) {
    379      1.1  thorpej 			struct flowinfo_in6 *fp6 = (struct flowinfo_in6 *)flow;
    380      1.1  thorpej 
    381      1.1  thorpej 			val = fp6->fi6_sport;
    382      1.1  thorpej 		}
    383      1.1  thorpej #endif
    384      1.1  thorpej 	}
    385      1.1  thorpej 	val = val ^ (val >> 8);
    386      1.1  thorpej 
    387      1.1  thorpej 	return (val % n);
    388      1.1  thorpej }
    389      1.1  thorpej 
    390  1.7.4.2     yamt static wfq *
    391  1.7.4.2     yamt wfq_maxqueue(wfq_state_t *wfqp)
    392      1.1  thorpej {
    393      1.1  thorpej 	int byte, max_byte = 0;
    394      1.1  thorpej 	wfq *queue, *max_queue = NULL;
    395      1.1  thorpej 
    396      1.1  thorpej 	if((queue = wfqp->rrp) == NULL)
    397      1.1  thorpej 		/* never happens */
    398      1.1  thorpej 		return NULL;
    399      1.1  thorpej 	do{
    400      1.1  thorpej 		if ((byte = queue->bytes * 100 / queue->weight) > max_byte) {
    401      1.1  thorpej 			max_queue = queue;
    402      1.1  thorpej 			max_byte = byte;
    403      1.1  thorpej 		}
    404      1.1  thorpej 	} while ((queue = queue->next) != wfqp->rrp);
    405      1.1  thorpej 
    406      1.1  thorpej 	return max_queue;
    407      1.1  thorpej }
    408      1.1  thorpej 
    409      1.1  thorpej 
    410      1.1  thorpej static struct mbuf *
    411  1.7.4.2     yamt wfq_ifdequeue(struct ifaltq *ifq, int op)
    412      1.1  thorpej {
    413      1.1  thorpej 	wfq_state_t *wfqp;
    414      1.1  thorpej 	wfq *queue;
    415      1.1  thorpej 	struct mbuf *mp;
    416      1.1  thorpej 	int byte;
    417      1.1  thorpej 
    418      1.1  thorpej 	wfqp = (wfq_state_t *)ifq->altq_disc;
    419      1.1  thorpej 
    420      1.1  thorpej 	if ((wfqp->bytes == 0) || ((queue = wfqp->rrp) == NULL))
    421      1.1  thorpej 		/* no packet in the queues */
    422      1.1  thorpej 		return NULL;
    423      1.7    perry 
    424      1.1  thorpej 	while (1) {
    425      1.1  thorpej 		if (queue->quota > 0) {
    426      1.1  thorpej 			if (queue->bytes <= 0) {
    427      1.1  thorpej 				/* this queue no longer has packet.
    428      1.1  thorpej 				   remove the queue from the active list. */
    429      1.1  thorpej 				if (queue->next == queue){
    430      1.7    perry 					/* no other active queue
    431      1.1  thorpej 					   -- this case never happens in
    432      1.1  thorpej 					   this algorithm. */
    433      1.1  thorpej 					queue->next = queue->prev = NULL;
    434      1.1  thorpej 					wfqp->rrp = NULL;
    435      1.1  thorpej 					return NULL;
    436      1.1  thorpej 				} else {
    437      1.1  thorpej 					queue->prev->next = queue->next;
    438      1.1  thorpej 					queue->next->prev = queue->prev;
    439      1.1  thorpej 					/* the round-robin pointer points
    440      1.1  thorpej 					   to this queue, advance the rrp */
    441      1.1  thorpej 					wfqp->rrp = queue->next;
    442      1.1  thorpej 					queue->next = queue->prev = NULL;
    443      1.1  thorpej 					queue = wfqp->rrp;
    444      1.1  thorpej 					WFQ_ADDQUOTA(queue);
    445      1.1  thorpej 					continue;
    446      1.1  thorpej 				}
    447      1.1  thorpej 			}
    448      1.1  thorpej 
    449      1.1  thorpej 			/* dequeue a packet from this queue */
    450      1.1  thorpej 			mp = queue->head;
    451      1.1  thorpej 			if (op == ALTDQ_REMOVE) {
    452      1.1  thorpej 				if((queue->head = mp->m_nextpkt) == NULL)
    453      1.1  thorpej 					queue->tail = NULL;
    454      1.1  thorpej 				byte = mp->m_pkthdr.len;
    455      1.1  thorpej 				mp->m_nextpkt = NULL;
    456      1.1  thorpej 				queue->quota -= byte;
    457      1.1  thorpej 				queue->bytes -= byte;
    458      1.1  thorpej 				PKTCNTR_ADD(&queue->xmit_cnt, byte);
    459      1.1  thorpej 				wfqp->bytes -= byte;
    460      1.1  thorpej 				if (ALTQ_IS_ENABLED(ifq))
    461      1.1  thorpej 					ifq->ifq_len--;
    462      1.1  thorpej 			}
    463      1.1  thorpej 			return mp;
    464      1.1  thorpej 
    465      1.1  thorpej 			/* if the queue gets empty by this dequeueing,
    466      1.1  thorpej 			   the queue will be removed from the active list
    467      1.1  thorpej 			   at the next round */
    468      1.1  thorpej 		}
    469      1.7    perry 
    470      1.1  thorpej 		/* advance the round-robin pointer */
    471      1.1  thorpej 		queue = wfqp->rrp = queue->next;
    472      1.1  thorpej 		WFQ_ADDQUOTA(queue);
    473      1.1  thorpej 	}
    474      1.1  thorpej }
    475      1.1  thorpej 
    476      1.1  thorpej static int
    477  1.7.4.2     yamt wfq_getqid(struct wfq_getqid *gqidp)
    478      1.1  thorpej {
    479      1.1  thorpej 	wfq_state_t *wfqp;
    480      1.1  thorpej 
    481      1.1  thorpej 	if ((wfqp = altq_lookup(gqidp->iface.wfq_ifacename, ALTQT_WFQ))
    482      1.1  thorpej 	    == NULL)
    483      1.1  thorpej 		return (EBADF);
    484      1.7    perry 
    485      1.1  thorpej 	gqidp->qid = (*wfqp->hash_func)(&gqidp->flow, wfqp->nums);
    486      1.1  thorpej 	return 0;
    487      1.1  thorpej }
    488      1.1  thorpej 
    489      1.1  thorpej static int
    490  1.7.4.2     yamt wfq_setweight(struct wfq_setweight *swp)
    491      1.1  thorpej {
    492      1.1  thorpej 	wfq_state_t	*wfqp;
    493      1.1  thorpej 	wfq *queue;
    494      1.1  thorpej 	int old;
    495      1.1  thorpej 
    496      1.1  thorpej 	if (swp->weight < 0) {
    497      1.1  thorpej 		printf("set weight in natural number\n");
    498      1.1  thorpej 		return (EINVAL);
    499      1.1  thorpej 	}
    500      1.1  thorpej 
    501      1.1  thorpej 	if ((wfqp = altq_lookup(swp->iface.wfq_ifacename, ALTQT_WFQ)) == NULL)
    502      1.1  thorpej 		return (EBADF);
    503      1.1  thorpej 
    504      1.1  thorpej 	queue = &wfqp->queue[swp->qid];
    505      1.1  thorpej 	old = queue->weight;
    506      1.1  thorpej 	queue->weight = swp->weight;
    507      1.1  thorpej 	swp->weight = old;
    508      1.1  thorpej 	return 0;
    509      1.1  thorpej }
    510      1.1  thorpej 
    511      1.1  thorpej 
    512      1.1  thorpej static int
    513  1.7.4.2     yamt wfq_getstats(struct wfq_getstats *gsp)
    514      1.1  thorpej {
    515      1.1  thorpej 	wfq_state_t	*wfqp;
    516      1.1  thorpej 	wfq *queue;
    517      1.1  thorpej 	queue_stats *stats;
    518      1.1  thorpej 
    519      1.1  thorpej 	if ((wfqp = altq_lookup(gsp->iface.wfq_ifacename, ALTQT_WFQ)) == NULL)
    520      1.1  thorpej 		return (EBADF);
    521      1.1  thorpej 
    522      1.1  thorpej 	if (gsp->qid >= wfqp->nums)
    523      1.1  thorpej 		return (EINVAL);
    524      1.1  thorpej 
    525      1.1  thorpej 	queue = &wfqp->queue[gsp->qid];
    526      1.1  thorpej 	stats = &gsp->stats;
    527      1.1  thorpej 
    528      1.1  thorpej 	stats->bytes		= queue->bytes;
    529      1.1  thorpej 	stats->weight		= queue->weight;
    530      1.1  thorpej 	stats->xmit_cnt		= queue->xmit_cnt;
    531      1.1  thorpej 	stats->drop_cnt		= queue->drop_cnt;
    532      1.1  thorpej 
    533      1.1  thorpej 	return 0;
    534      1.1  thorpej }
    535      1.1  thorpej 
    536      1.1  thorpej 
    537      1.1  thorpej static int
    538  1.7.4.2     yamt wfq_config(struct wfq_conf *cf)
    539      1.1  thorpej {
    540      1.1  thorpej 	wfq_state_t	*wfqp;
    541      1.1  thorpej 	wfq		*queue;
    542      1.1  thorpej 	int		i, error = 0;
    543      1.1  thorpej 
    544      1.1  thorpej 	if ((wfqp = altq_lookup(cf->iface.wfq_ifacename, ALTQT_WFQ)) == NULL)
    545      1.1  thorpej 		return (EBADF);
    546      1.1  thorpej 
    547      1.1  thorpej 	if(cf->nqueues <= 0 ||  MAX_QSIZE < cf->nqueues)
    548      1.1  thorpej 		cf->nqueues = DEFAULT_QSIZE;
    549      1.1  thorpej 
    550      1.1  thorpej 	if (cf->nqueues != wfqp->nums) {
    551      1.1  thorpej 		/* free queued mbuf */
    552      1.1  thorpej 		wfq_flush(wfqp->ifq);
    553  1.7.4.1     yamt 		free(wfqp->queue, M_DEVBUF);
    554      1.1  thorpej 
    555  1.7.4.1     yamt 		queue = malloc(sizeof(wfq) * cf->nqueues, M_DEVBUF,
    556  1.7.4.1     yamt 		    M_WAITOK|M_ZERO);
    557      1.1  thorpej 		if (queue == NULL)
    558      1.1  thorpej 			return (ENOMEM);
    559      1.1  thorpej 
    560      1.1  thorpej 		wfqp->nums = cf->nqueues;
    561      1.1  thorpej 		wfqp->bytes = 0;
    562      1.1  thorpej 		wfqp->rrp = NULL;
    563      1.1  thorpej 		wfqp->queue = queue;
    564      1.1  thorpej 		for (i = 0; i < wfqp->nums; i++, queue++) {
    565      1.1  thorpej 			queue->next = queue->prev = NULL;
    566      1.1  thorpej 			queue->head = queue->tail = NULL;
    567      1.1  thorpej 			queue->bytes = queue->quota = 0;
    568      1.1  thorpej 			queue->weight = 100;
    569      1.1  thorpej 		}
    570      1.1  thorpej 	}
    571      1.1  thorpej 
    572      1.1  thorpej 	if (cf->qlimit != 0)
    573      1.1  thorpej 		wfqp->hwm = cf->qlimit;
    574      1.1  thorpej 
    575      1.1  thorpej 	switch (cf->hash_policy) {
    576      1.1  thorpej 	case WFQ_HASH_DSTADDR:
    577      1.1  thorpej 		wfqp->hash_func = wfq_hashbydstaddr;
    578      1.1  thorpej 		wfqp->fbmask = FIMB4_DADDR;
    579      1.1  thorpej #ifdef INET6
    580      1.1  thorpej 		wfqp->fbmask |= FIMB6_FLABEL;	/* use flowlabel for ipv6 */
    581      1.1  thorpej #endif
    582      1.1  thorpej 		break;
    583      1.1  thorpej 	case WFQ_HASH_SRCPORT:
    584      1.1  thorpej 		wfqp->hash_func = wfq_hashbysrcport;
    585      1.1  thorpej 		wfqp->fbmask = FIMB4_SPORT;
    586      1.1  thorpej #ifdef INET6
    587      1.1  thorpej 		wfqp->fbmask |= FIMB6_SPORT;
    588      1.1  thorpej #endif
    589      1.1  thorpej 		break;
    590      1.1  thorpej 	case WFQ_HASH_FULL:
    591      1.1  thorpej 		wfqp->hash_func = wfq_hash;
    592      1.1  thorpej 		wfqp->fbmask = FIMB4_ALL;
    593      1.1  thorpej #ifdef INET6
    594      1.1  thorpej 		wfqp->fbmask |= FIMB6_FLABEL;	/* use flowlabel for ipv6 */
    595      1.1  thorpej #endif
    596      1.1  thorpej 		break;
    597      1.1  thorpej 	default:
    598      1.1  thorpej 		error = EINVAL;
    599      1.1  thorpej 		break;
    600      1.1  thorpej 	}
    601      1.1  thorpej 	return error;
    602      1.1  thorpej }
    603      1.1  thorpej 
    604      1.1  thorpej /*
    605      1.1  thorpej  * wfq device interface
    606      1.1  thorpej  */
    607      1.1  thorpej 
    608      1.1  thorpej altqdev_decl(wfq);
    609      1.1  thorpej 
    610      1.1  thorpej int
    611  1.7.4.2     yamt wfqopen(dev_t dev, int flag, int fmt,
    612  1.7.4.2     yamt     struct lwp *l)
    613      1.1  thorpej {
    614      1.1  thorpej 	return 0;
    615      1.1  thorpej }
    616      1.1  thorpej 
    617      1.1  thorpej int
    618  1.7.4.2     yamt wfqclose(dev_t dev, int flag, int fmt,
    619  1.7.4.2     yamt     struct lwp *l)
    620      1.1  thorpej {
    621      1.1  thorpej 	struct ifnet *ifp;
    622      1.1  thorpej 	struct wfq_interface iface;
    623      1.1  thorpej 	wfq_state_t *wfqp;
    624      1.1  thorpej 	int s;
    625      1.7    perry 
    626      1.3  thorpej 	s = splnet();
    627      1.1  thorpej 	while ((wfqp = wfq_list) != NULL) {
    628      1.1  thorpej 		ifp = wfqp->ifq->altq_ifp;
    629      1.1  thorpej 		sprintf(iface.wfq_ifacename, "%s", ifp->if_xname);
    630      1.1  thorpej 		wfq_ifdetach(&iface);
    631      1.1  thorpej 	}
    632      1.1  thorpej 	splx(s);
    633      1.1  thorpej 	return 0;
    634      1.1  thorpej }
    635      1.1  thorpej 
    636      1.1  thorpej int
    637  1.7.4.2     yamt wfqioctl(dev_t dev, ioctlcmd_t cmd, caddr_t addr, int flag,
    638  1.7.4.2     yamt     struct lwp *l)
    639      1.1  thorpej {
    640      1.1  thorpej 	int	error = 0;
    641      1.1  thorpej 	int 	s;
    642      1.1  thorpej 
    643      1.1  thorpej 	/* check cmd for superuser only */
    644      1.1  thorpej 	switch (cmd) {
    645      1.1  thorpej 	case WFQ_GET_QID:
    646      1.1  thorpej 	case WFQ_GET_STATS:
    647      1.1  thorpej 		break;
    648      1.1  thorpej 	default:
    649      1.1  thorpej #if (__FreeBSD_version > 400000)
    650      1.1  thorpej 		if ((error = suser(p)) != 0)
    651      1.1  thorpej #else
    652  1.7.4.2     yamt 		if ((error = kauth_authorize_network(l->l_cred,
    653  1.7.4.2     yamt 		    KAUTH_NETWORK_ALTQ, KAUTH_REQ_NETWORK_ALTQ_WFQ, NULL,
    654  1.7.4.2     yamt 		    NULL, NULL)) != 0)
    655      1.1  thorpej #endif
    656      1.1  thorpej 			return (error);
    657      1.1  thorpej 		break;
    658      1.1  thorpej 	}
    659      1.1  thorpej 
    660      1.3  thorpej 	s = splnet();
    661      1.1  thorpej 	switch (cmd) {
    662      1.7    perry 
    663      1.1  thorpej 	case WFQ_ENABLE:
    664      1.1  thorpej 		error = wfq_setenable((struct wfq_interface *)addr, ENABLE);
    665      1.1  thorpej 		break;
    666      1.1  thorpej 
    667      1.1  thorpej 	case WFQ_DISABLE:
    668      1.1  thorpej 		error = wfq_setenable((struct wfq_interface *)addr, DISABLE);
    669      1.1  thorpej 		break;
    670      1.1  thorpej 
    671      1.1  thorpej 	case WFQ_IF_ATTACH:
    672      1.1  thorpej 		error = wfq_ifattach((struct wfq_interface *)addr);
    673      1.1  thorpej 		break;
    674      1.1  thorpej 
    675      1.1  thorpej 	case WFQ_IF_DETACH:
    676      1.1  thorpej 		error = wfq_ifdetach((struct wfq_interface *)addr);
    677      1.1  thorpej 		break;
    678      1.1  thorpej 
    679      1.1  thorpej 	case WFQ_GET_QID:
    680      1.1  thorpej 		error = wfq_getqid((struct wfq_getqid *)addr);
    681      1.1  thorpej 		break;
    682      1.1  thorpej 
    683      1.1  thorpej 	case WFQ_SET_WEIGHT:
    684      1.1  thorpej 		error = wfq_setweight((struct wfq_setweight *)addr);
    685      1.1  thorpej 		break;
    686      1.1  thorpej 
    687      1.1  thorpej 	case WFQ_GET_STATS:
    688      1.1  thorpej 		error = wfq_getstats((struct wfq_getstats *)addr);
    689      1.1  thorpej 		break;
    690      1.1  thorpej 
    691      1.1  thorpej 	case WFQ_CONFIG:
    692      1.1  thorpej 		error = wfq_config((struct wfq_conf *)addr);
    693      1.1  thorpej 		break;
    694      1.1  thorpej 
    695      1.1  thorpej 	default:
    696      1.1  thorpej 		error = EINVAL;
    697      1.1  thorpej 		break;
    698      1.1  thorpej 	}
    699      1.1  thorpej 	splx(s);
    700      1.1  thorpej 	return error;
    701      1.1  thorpej }
    702      1.1  thorpej 
    703      1.1  thorpej #ifdef KLD_MODULE
    704      1.1  thorpej 
    705      1.1  thorpej static struct altqsw wfq_sw =
    706      1.1  thorpej 	{"wfq", wfqopen, wfqclose, wfqioctl};
    707      1.1  thorpej 
    708      1.1  thorpej ALTQ_MODULE(altq_wfq, ALTQT_WFQ, &wfq_sw);
    709      1.1  thorpej 
    710      1.1  thorpej #endif /* KLD_MODULE */
    711      1.1  thorpej 
    712  1.7.4.2     yamt #endif /* ALTQ3_COMPAT */
    713      1.1  thorpej #endif /* ALTQ_WFQ */
    714