Home | History | Annotate | Line # | Download | only in altq
altq_wfq.c revision 1.19.28.1
      1  1.19.28.1      yamt /*	$NetBSD: altq_wfq.c,v 1.19.28.1 2014/05/22 11:39:25 yamt Exp $	*/
      2       1.15     peter /*	$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.15     peter  * 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.19.28.1      yamt __KERNEL_RCSID(0, "$NetBSD: altq_wfq.c,v 1.19.28.1 2014/05/22 11:39:25 yamt Exp $");
     36        1.1   thorpej 
     37       1.15     peter #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.15     peter 
     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.12  christos #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.15     peter #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.9     perry static inline u_long	wfq_hashbydstaddr(struct flowinfo *, int);
     76       1.19     joerg static inline u_long	wfq_hashbysrcaddr(struct flowinfo *, int);
     77        1.9     perry static inline u_long	wfq_hashbysrcport(struct flowinfo *, int);
     78        1.1   thorpej static wfq		*wfq_maxqueue(wfq_state_t *);
     79        1.1   thorpej static struct mbuf	*wfq_ifdequeue(struct ifaltq *, int);
     80        1.1   thorpej static int		wfq_getqid(struct wfq_getqid *);
     81        1.1   thorpej static int		wfq_setweight(struct wfq_setweight *);
     82        1.1   thorpej static int		wfq_getstats(struct wfq_getstats *);
     83        1.1   thorpej static int		wfq_config(struct wfq_conf *);
     84       1.15     peter static int		wfq_request(struct ifaltq *, int, void *);
     85        1.1   thorpej static int		wfq_flush(struct ifaltq *);
     86        1.1   thorpej static void		*wfq_classify(void *, struct mbuf *, int);
     87        1.1   thorpej 
     88        1.1   thorpej /* global value : pointer to wfq queue list */
     89        1.1   thorpej static wfq_state_t *wfq_list = NULL;
     90        1.1   thorpej 
     91        1.1   thorpej static int
     92       1.15     peter wfq_setenable(struct wfq_interface *ifacep, int flag)
     93        1.1   thorpej {
     94        1.1   thorpej 	wfq_state_t *wfqp;
     95        1.1   thorpej 	int error = 0;
     96        1.1   thorpej 
     97        1.1   thorpej 	if ((wfqp = altq_lookup(ifacep->wfq_ifacename, ALTQT_WFQ)) == NULL)
     98        1.1   thorpej 		return (EBADF);
     99        1.1   thorpej 
    100        1.1   thorpej 	switch(flag){
    101        1.1   thorpej 	case ENABLE:
    102        1.1   thorpej 		error = altq_enable(wfqp->ifq);
    103        1.1   thorpej 		break;
    104        1.1   thorpej 	case DISABLE:
    105        1.1   thorpej 		error = altq_disable(wfqp->ifq);
    106        1.1   thorpej 		break;
    107        1.1   thorpej 	}
    108        1.1   thorpej 	return error;
    109        1.1   thorpej }
    110        1.1   thorpej 
    111        1.1   thorpej 
    112        1.1   thorpej static int
    113       1.15     peter wfq_ifattach(struct wfq_interface *ifacep)
    114        1.1   thorpej {
    115        1.1   thorpej 	int error = 0, i;
    116        1.1   thorpej 	struct ifnet *ifp;
    117        1.1   thorpej 	wfq_state_t *new_wfqp;
    118        1.1   thorpej 	wfq *queue;
    119        1.1   thorpej 
    120        1.1   thorpej 	if ((ifp = ifunit(ifacep->wfq_ifacename)) == NULL) {
    121        1.1   thorpej #ifdef WFQ_DEBUG
    122        1.1   thorpej 		printf("wfq_ifattach()...no ifp found\n");
    123        1.1   thorpej #endif
    124        1.1   thorpej 		return (ENXIO);
    125        1.1   thorpej 	}
    126        1.1   thorpej 
    127        1.1   thorpej 	if (!ALTQ_IS_READY(&ifp->if_snd)) {
    128        1.1   thorpej #ifdef WFQ_DEBUG
    129        1.1   thorpej 		printf("wfq_ifattach()...altq is not ready\n");
    130        1.1   thorpej #endif
    131        1.1   thorpej 		return (ENXIO);
    132        1.1   thorpej 	}
    133        1.1   thorpej 
    134        1.1   thorpej 	/* allocate and initialize wfq_state_t */
    135       1.10  christos 	new_wfqp = malloc(sizeof(wfq_state_t), M_DEVBUF, M_WAITOK|M_ZERO);
    136        1.1   thorpej 	if (new_wfqp == NULL)
    137        1.1   thorpej 		return (ENOMEM);
    138       1.15     peter 
    139       1.10  christos 	queue = malloc(sizeof(wfq) * DEFAULT_QSIZE, M_DEVBUF, M_WAITOK|M_ZERO);
    140        1.1   thorpej 	if (queue == NULL) {
    141       1.10  christos 		free(new_wfqp, M_DEVBUF);
    142        1.1   thorpej 		return (ENOMEM);
    143        1.1   thorpej 	}
    144        1.1   thorpej 
    145        1.1   thorpej 	/* keep the ifq */
    146        1.1   thorpej 	new_wfqp->ifq = &ifp->if_snd;
    147        1.1   thorpej 	new_wfqp->nums = DEFAULT_QSIZE;
    148        1.1   thorpej 	new_wfqp->hwm = HWM;
    149        1.1   thorpej 	new_wfqp->bytes = 0;
    150        1.1   thorpej 	new_wfqp->rrp = NULL;
    151        1.1   thorpej 	new_wfqp->queue = queue;
    152        1.1   thorpej 	new_wfqp->hash_func = wfq_hashbydstaddr;
    153        1.1   thorpej 	new_wfqp->fbmask = FIMB4_DADDR;
    154        1.1   thorpej 
    155        1.1   thorpej 	for (i = 0; i < new_wfqp->nums; i++, queue++) {
    156        1.1   thorpej 		queue->next = queue->prev = NULL;
    157        1.1   thorpej 		queue->head = queue->tail = NULL;
    158        1.1   thorpej 		queue->bytes = queue->quota = 0;
    159        1.1   thorpej 		queue->weight = 100;
    160        1.1   thorpej 	}
    161        1.1   thorpej 
    162        1.1   thorpej 	/*
    163        1.1   thorpej 	 * set WFQ to this ifnet structure.
    164        1.1   thorpej 	 */
    165        1.1   thorpej 	if ((error = altq_attach(&ifp->if_snd, ALTQT_WFQ, new_wfqp,
    166        1.1   thorpej 				 wfq_ifenqueue, wfq_ifdequeue, wfq_request,
    167        1.1   thorpej 				 new_wfqp, wfq_classify)) != 0) {
    168       1.10  christos 		free(queue, M_DEVBUF);
    169       1.10  christos 		free(new_wfqp, M_DEVBUF);
    170        1.1   thorpej 		return (error);
    171        1.1   thorpej 	}
    172        1.1   thorpej 
    173        1.1   thorpej 	new_wfqp->next = wfq_list;
    174        1.1   thorpej 	wfq_list = new_wfqp;
    175        1.1   thorpej 
    176        1.1   thorpej 	return (error);
    177        1.1   thorpej }
    178        1.1   thorpej 
    179        1.1   thorpej 
    180        1.1   thorpej static int
    181       1.15     peter wfq_ifdetach(struct wfq_interface *ifacep)
    182        1.1   thorpej {
    183        1.1   thorpej 	int		error = 0;
    184        1.1   thorpej 	wfq_state_t	*wfqp;
    185        1.1   thorpej 
    186        1.1   thorpej 	if ((wfqp = altq_lookup(ifacep->wfq_ifacename, ALTQT_WFQ)) == NULL)
    187        1.1   thorpej 		return (EBADF);
    188        1.1   thorpej 
    189        1.1   thorpej 	/* free queued mbuf */
    190        1.1   thorpej 	wfq_flush(wfqp->ifq);
    191        1.1   thorpej 
    192        1.1   thorpej 	/* remove WFQ from the ifnet structure. */
    193        1.1   thorpej 	(void)altq_disable(wfqp->ifq);
    194        1.1   thorpej 	(void)altq_detach(wfqp->ifq);
    195        1.7     perry 
    196        1.1   thorpej 	/* remove from the wfqstate list */
    197        1.1   thorpej 	if (wfq_list == wfqp)
    198        1.1   thorpej 		wfq_list = wfqp->next;
    199        1.1   thorpej 	else {
    200        1.1   thorpej 		wfq_state_t *wp = wfq_list;
    201        1.1   thorpej 		do {
    202        1.1   thorpej 			if (wp->next == wfqp) {
    203        1.1   thorpej 				wp->next = wfqp->next;
    204        1.1   thorpej 				break;
    205        1.1   thorpej 			}
    206        1.1   thorpej 		} while ((wp = wp->next) != NULL);
    207        1.1   thorpej 	}
    208        1.7     perry 
    209        1.1   thorpej 	/* deallocate wfq_state_t */
    210       1.10  christos 	free(wfqp->queue, M_DEVBUF);
    211       1.10  christos 	free(wfqp, M_DEVBUF);
    212        1.1   thorpej 	return (error);
    213        1.1   thorpej }
    214        1.1   thorpej 
    215        1.1   thorpej static int
    216       1.17  christos wfq_request(struct ifaltq *ifq, int req, void *arg)
    217        1.1   thorpej {
    218        1.1   thorpej 	wfq_state_t *wfqp = (wfq_state_t *)ifq->altq_disc;
    219        1.1   thorpej 
    220        1.1   thorpej 	switch (req) {
    221        1.1   thorpej 	case ALTRQ_PURGE:
    222        1.1   thorpej 		wfq_flush(wfqp->ifq);
    223        1.1   thorpej 		break;
    224        1.1   thorpej 	}
    225        1.1   thorpej 	return (0);
    226        1.1   thorpej }
    227        1.1   thorpej 
    228        1.1   thorpej 
    229        1.1   thorpej static int
    230       1.15     peter wfq_flush(struct ifaltq *ifq)
    231        1.1   thorpej {
    232        1.1   thorpej 	struct mbuf *mp;
    233        1.1   thorpej 
    234        1.1   thorpej 	while ((mp = wfq_ifdequeue(ifq, ALTDQ_REMOVE)) != NULL)
    235        1.1   thorpej 		m_freem(mp);
    236        1.1   thorpej 	if (ALTQ_IS_ENABLED(ifq))
    237        1.1   thorpej 		ifq->ifq_len = 0;
    238        1.1   thorpej 	return 0;
    239        1.1   thorpej }
    240        1.1   thorpej 
    241        1.1   thorpej static void *
    242       1.15     peter wfq_classify(void *clfier, struct mbuf *m, int af)
    243        1.1   thorpej {
    244        1.1   thorpej 	wfq_state_t *wfqp = (wfq_state_t *)clfier;
    245        1.1   thorpej 	struct flowinfo flow;
    246        1.1   thorpej 
    247        1.1   thorpej 	altq_extractflow(m, af, &flow, wfqp->fbmask);
    248        1.1   thorpej 	return (&wfqp->queue[(*wfqp->hash_func)(&flow, wfqp->nums)]);
    249        1.1   thorpej }
    250        1.1   thorpej 
    251        1.1   thorpej static int
    252       1.15     peter wfq_ifenqueue(struct ifaltq *ifq, struct mbuf *mp, struct altq_pktattr *pktattr)
    253        1.1   thorpej {
    254        1.1   thorpej 	wfq_state_t *wfqp;
    255        1.1   thorpej 	wfq *queue;
    256        1.1   thorpej 	int byte, error = 0;
    257        1.1   thorpej 
    258        1.1   thorpej 	wfqp = (wfq_state_t *)ifq->altq_disc;
    259        1.1   thorpej 	mp->m_nextpkt = NULL;
    260        1.1   thorpej 
    261        1.1   thorpej 	/* grab a queue selected by classifier */
    262        1.1   thorpej 	if (pktattr == NULL || (queue = pktattr->pattr_class) == NULL)
    263        1.1   thorpej 		queue = &wfqp->queue[0];
    264        1.1   thorpej 
    265        1.1   thorpej 	if (queue->tail == NULL)
    266        1.1   thorpej 		queue->head = mp;
    267        1.1   thorpej 	else
    268        1.1   thorpej 		queue->tail->m_nextpkt = mp;
    269        1.1   thorpej 	queue->tail = mp;
    270        1.1   thorpej 	byte = mp->m_pkthdr.len;
    271        1.1   thorpej 	queue->bytes += byte;
    272        1.1   thorpej 	wfqp->bytes += byte;
    273        1.1   thorpej 	ifq->ifq_len++;
    274        1.1   thorpej 
    275        1.1   thorpej 	if (queue->next == NULL) {
    276        1.1   thorpej 		/* this queue gets active. add the queue to the active list */
    277        1.1   thorpej 		if (wfqp->rrp == NULL){
    278        1.1   thorpej 			/* no queue in the active list */
    279        1.1   thorpej 			queue->next = queue->prev = queue;
    280        1.1   thorpej 			wfqp->rrp = queue;
    281        1.1   thorpej 			WFQ_ADDQUOTA(queue);
    282        1.1   thorpej 		} else {
    283        1.1   thorpej 			/* insert the queue at the tail of the active list */
    284        1.1   thorpej 			queue->prev = wfqp->rrp->prev;
    285        1.1   thorpej 			wfqp->rrp->prev->next = queue;
    286        1.1   thorpej 			wfqp->rrp->prev = queue;
    287        1.1   thorpej 			queue->next = wfqp->rrp;
    288        1.1   thorpej 			queue->quota = 0;
    289        1.1   thorpej 		}
    290        1.1   thorpej 	}
    291        1.1   thorpej 
    292        1.1   thorpej 	/* check overflow. if the total size exceeds the high water mark,
    293        1.1   thorpej 	   drop packets from the longest queue. */
    294        1.1   thorpej 	while (wfqp->bytes > wfqp->hwm) {
    295        1.1   thorpej 		wfq *drop_queue = wfq_maxqueue(wfqp);
    296        1.1   thorpej 
    297        1.1   thorpej 		/* drop the packet at the head. */
    298        1.1   thorpej 		mp = drop_queue->head;
    299        1.1   thorpej 		if ((drop_queue->head = mp->m_nextpkt) == NULL)
    300        1.1   thorpej 			drop_queue->tail = NULL;
    301        1.1   thorpej 		mp->m_nextpkt = NULL;
    302        1.1   thorpej 		byte = mp->m_pkthdr.len;
    303        1.1   thorpej 		drop_queue->bytes -= byte;
    304        1.1   thorpej 		PKTCNTR_ADD(&drop_queue->drop_cnt, byte);
    305        1.1   thorpej 		wfqp->bytes -= byte;
    306        1.1   thorpej 		m_freem(mp);
    307        1.1   thorpej 		ifq->ifq_len--;
    308        1.1   thorpej 		if(drop_queue == queue)
    309        1.1   thorpej 			/* the queue for this flow is selected to drop */
    310        1.1   thorpej 			error = ENOBUFS;
    311        1.1   thorpej 	}
    312        1.1   thorpej 	return error;
    313        1.1   thorpej }
    314        1.7     perry 
    315       1.15     peter static u_long
    316       1.15     peter wfq_hash(struct flowinfo *flow, int n)
    317        1.1   thorpej {
    318        1.1   thorpej 	u_long val = 0;
    319        1.1   thorpej 
    320        1.1   thorpej 	if (flow != NULL) {
    321        1.1   thorpej 		if (flow->fi_family == AF_INET) {
    322        1.1   thorpej 			struct flowinfo_in *fp = (struct flowinfo_in *)flow;
    323        1.1   thorpej 			u_long val2;
    324        1.1   thorpej 
    325        1.1   thorpej 			val = fp->fi_dst.s_addr ^ fp->fi_src.s_addr;
    326        1.1   thorpej 			val = val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24);
    327        1.1   thorpej 			val2 = fp->fi_dport ^ fp->fi_sport ^ fp->fi_proto;
    328        1.1   thorpej 			val2 = val2 ^ (val2 >> 8);
    329        1.1   thorpej 			val = val ^ val2;
    330        1.1   thorpej 		}
    331        1.1   thorpej #ifdef INET6
    332        1.1   thorpej 		else if (flow->fi_family == AF_INET6) {
    333        1.1   thorpej 			struct flowinfo_in6 *fp6 = (struct flowinfo_in6 *)flow;
    334        1.1   thorpej 
    335        1.1   thorpej 			val = ntohl(fp6->fi6_flowlabel);
    336        1.1   thorpej 		}
    337        1.1   thorpej #endif
    338        1.1   thorpej 	}
    339        1.1   thorpej 
    340        1.1   thorpej 	return (val % n);
    341        1.1   thorpej }
    342        1.1   thorpej 
    343       1.15     peter static inline u_long
    344       1.15     peter wfq_hashbydstaddr(struct flowinfo *flow, int n)
    345        1.1   thorpej {
    346        1.1   thorpej 	u_long val = 0;
    347        1.1   thorpej 
    348        1.1   thorpej 	if (flow != NULL) {
    349        1.1   thorpej 		if (flow->fi_family == AF_INET) {
    350        1.1   thorpej 			struct flowinfo_in *fp = (struct flowinfo_in *)flow;
    351        1.1   thorpej 
    352        1.1   thorpej 			val = fp->fi_dst.s_addr;
    353        1.1   thorpej 			val = val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24);
    354        1.1   thorpej 		}
    355        1.1   thorpej #ifdef INET6
    356        1.1   thorpej 		else if (flow->fi_family == AF_INET6) {
    357        1.1   thorpej 			struct flowinfo_in6 *fp6 = (struct flowinfo_in6 *)flow;
    358        1.1   thorpej 
    359        1.1   thorpej 			val = ntohl(fp6->fi6_flowlabel);
    360        1.1   thorpej 		}
    361        1.1   thorpej #endif
    362        1.1   thorpej 	}
    363        1.1   thorpej 
    364        1.1   thorpej 	return (val % n);
    365        1.1   thorpej }
    366        1.1   thorpej 
    367       1.15     peter static inline u_long
    368       1.19     joerg wfq_hashbysrcaddr(struct flowinfo *flow, int n)
    369       1.19     joerg {
    370       1.19     joerg 	u_long val = 0;
    371       1.19     joerg 
    372       1.19     joerg 	if (flow != NULL) {
    373       1.19     joerg 		if (flow->fi_family == AF_INET) {
    374       1.19     joerg 			struct flowinfo_in *fp = (struct flowinfo_in *)flow;
    375       1.19     joerg 
    376       1.19     joerg 			val = fp->fi_src.s_addr;
    377       1.19     joerg 			val = val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24);
    378       1.19     joerg 		}
    379       1.19     joerg #ifdef INET6
    380       1.19     joerg 		else if (flow->fi_family == AF_INET6) {
    381       1.19     joerg 			struct flowinfo_in6 *fp6 = (struct flowinfo_in6 *)flow;
    382       1.19     joerg 
    383       1.19     joerg 			val = ntohl(fp6->fi6_flowlabel);
    384       1.19     joerg 		}
    385       1.19     joerg #endif
    386       1.19     joerg 	}
    387       1.19     joerg 
    388       1.19     joerg 	return (val % n);
    389       1.19     joerg }
    390       1.19     joerg 
    391       1.19     joerg static inline u_long
    392       1.15     peter wfq_hashbysrcport(struct flowinfo *flow, int n)
    393        1.1   thorpej {
    394        1.1   thorpej 	u_long val = 0;
    395        1.1   thorpej 
    396        1.1   thorpej 	if (flow != NULL) {
    397        1.1   thorpej 		if (flow->fi_family == AF_INET) {
    398        1.1   thorpej 			struct flowinfo_in *fp = (struct flowinfo_in *)flow;
    399        1.1   thorpej 
    400        1.1   thorpej 			val = fp->fi_sport;
    401        1.1   thorpej 		}
    402        1.1   thorpej #ifdef INET6
    403        1.1   thorpej 		else if (flow->fi_family == AF_INET6) {
    404        1.1   thorpej 			struct flowinfo_in6 *fp6 = (struct flowinfo_in6 *)flow;
    405        1.1   thorpej 
    406        1.1   thorpej 			val = fp6->fi6_sport;
    407        1.1   thorpej 		}
    408        1.1   thorpej #endif
    409        1.1   thorpej 	}
    410        1.1   thorpej 	val = val ^ (val >> 8);
    411        1.1   thorpej 
    412        1.1   thorpej 	return (val % n);
    413        1.1   thorpej }
    414        1.1   thorpej 
    415       1.15     peter static wfq *
    416       1.15     peter wfq_maxqueue(wfq_state_t *wfqp)
    417        1.1   thorpej {
    418        1.1   thorpej 	int byte, max_byte = 0;
    419        1.1   thorpej 	wfq *queue, *max_queue = NULL;
    420        1.1   thorpej 
    421        1.1   thorpej 	if((queue = wfqp->rrp) == NULL)
    422        1.1   thorpej 		/* never happens */
    423        1.1   thorpej 		return NULL;
    424        1.1   thorpej 	do{
    425        1.1   thorpej 		if ((byte = queue->bytes * 100 / queue->weight) > max_byte) {
    426        1.1   thorpej 			max_queue = queue;
    427        1.1   thorpej 			max_byte = byte;
    428        1.1   thorpej 		}
    429        1.1   thorpej 	} while ((queue = queue->next) != wfqp->rrp);
    430        1.1   thorpej 
    431        1.1   thorpej 	return max_queue;
    432        1.1   thorpej }
    433        1.1   thorpej 
    434        1.1   thorpej 
    435        1.1   thorpej static struct mbuf *
    436       1.15     peter wfq_ifdequeue(struct ifaltq *ifq, int op)
    437        1.1   thorpej {
    438        1.1   thorpej 	wfq_state_t *wfqp;
    439        1.1   thorpej 	wfq *queue;
    440        1.1   thorpej 	struct mbuf *mp;
    441        1.1   thorpej 	int byte;
    442        1.1   thorpej 
    443        1.1   thorpej 	wfqp = (wfq_state_t *)ifq->altq_disc;
    444        1.1   thorpej 
    445        1.1   thorpej 	if ((wfqp->bytes == 0) || ((queue = wfqp->rrp) == NULL))
    446        1.1   thorpej 		/* no packet in the queues */
    447        1.1   thorpej 		return NULL;
    448        1.7     perry 
    449        1.1   thorpej 	while (1) {
    450        1.1   thorpej 		if (queue->quota > 0) {
    451        1.1   thorpej 			if (queue->bytes <= 0) {
    452        1.1   thorpej 				/* this queue no longer has packet.
    453        1.1   thorpej 				   remove the queue from the active list. */
    454        1.1   thorpej 				if (queue->next == queue){
    455        1.7     perry 					/* no other active queue
    456        1.1   thorpej 					   -- this case never happens in
    457        1.1   thorpej 					   this algorithm. */
    458        1.1   thorpej 					queue->next = queue->prev = NULL;
    459        1.1   thorpej 					wfqp->rrp = NULL;
    460        1.1   thorpej 					return NULL;
    461        1.1   thorpej 				} else {
    462        1.1   thorpej 					queue->prev->next = queue->next;
    463        1.1   thorpej 					queue->next->prev = queue->prev;
    464        1.1   thorpej 					/* the round-robin pointer points
    465        1.1   thorpej 					   to this queue, advance the rrp */
    466        1.1   thorpej 					wfqp->rrp = queue->next;
    467        1.1   thorpej 					queue->next = queue->prev = NULL;
    468        1.1   thorpej 					queue = wfqp->rrp;
    469        1.1   thorpej 					WFQ_ADDQUOTA(queue);
    470        1.1   thorpej 					continue;
    471        1.1   thorpej 				}
    472        1.1   thorpej 			}
    473        1.1   thorpej 
    474        1.1   thorpej 			/* dequeue a packet from this queue */
    475        1.1   thorpej 			mp = queue->head;
    476        1.1   thorpej 			if (op == ALTDQ_REMOVE) {
    477        1.1   thorpej 				if((queue->head = mp->m_nextpkt) == NULL)
    478        1.1   thorpej 					queue->tail = NULL;
    479        1.1   thorpej 				byte = mp->m_pkthdr.len;
    480        1.1   thorpej 				mp->m_nextpkt = NULL;
    481        1.1   thorpej 				queue->quota -= byte;
    482        1.1   thorpej 				queue->bytes -= byte;
    483        1.1   thorpej 				PKTCNTR_ADD(&queue->xmit_cnt, byte);
    484        1.1   thorpej 				wfqp->bytes -= byte;
    485        1.1   thorpej 				if (ALTQ_IS_ENABLED(ifq))
    486        1.1   thorpej 					ifq->ifq_len--;
    487        1.1   thorpej 			}
    488        1.1   thorpej 			return mp;
    489        1.1   thorpej 
    490        1.1   thorpej 			/* if the queue gets empty by this dequeueing,
    491        1.1   thorpej 			   the queue will be removed from the active list
    492        1.1   thorpej 			   at the next round */
    493        1.1   thorpej 		}
    494        1.7     perry 
    495        1.1   thorpej 		/* advance the round-robin pointer */
    496        1.1   thorpej 		queue = wfqp->rrp = queue->next;
    497        1.1   thorpej 		WFQ_ADDQUOTA(queue);
    498        1.1   thorpej 	}
    499        1.1   thorpej }
    500        1.1   thorpej 
    501        1.1   thorpej static int
    502       1.15     peter wfq_getqid(struct wfq_getqid *gqidp)
    503        1.1   thorpej {
    504        1.1   thorpej 	wfq_state_t *wfqp;
    505        1.1   thorpej 
    506        1.1   thorpej 	if ((wfqp = altq_lookup(gqidp->iface.wfq_ifacename, ALTQT_WFQ))
    507        1.1   thorpej 	    == NULL)
    508        1.1   thorpej 		return (EBADF);
    509        1.7     perry 
    510        1.1   thorpej 	gqidp->qid = (*wfqp->hash_func)(&gqidp->flow, wfqp->nums);
    511        1.1   thorpej 	return 0;
    512        1.1   thorpej }
    513        1.1   thorpej 
    514        1.1   thorpej static int
    515       1.15     peter wfq_setweight(struct wfq_setweight *swp)
    516        1.1   thorpej {
    517        1.1   thorpej 	wfq_state_t	*wfqp;
    518        1.1   thorpej 	wfq *queue;
    519        1.1   thorpej 	int old;
    520        1.1   thorpej 
    521        1.1   thorpej 	if (swp->weight < 0) {
    522        1.1   thorpej 		printf("set weight in natural number\n");
    523        1.1   thorpej 		return (EINVAL);
    524        1.1   thorpej 	}
    525        1.1   thorpej 
    526        1.1   thorpej 	if ((wfqp = altq_lookup(swp->iface.wfq_ifacename, ALTQT_WFQ)) == NULL)
    527        1.1   thorpej 		return (EBADF);
    528        1.1   thorpej 
    529        1.1   thorpej 	queue = &wfqp->queue[swp->qid];
    530        1.1   thorpej 	old = queue->weight;
    531        1.1   thorpej 	queue->weight = swp->weight;
    532        1.1   thorpej 	swp->weight = old;
    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.15     peter wfq_getstats(struct wfq_getstats *gsp)
    539        1.1   thorpej {
    540        1.1   thorpej 	wfq_state_t	*wfqp;
    541        1.1   thorpej 	wfq *queue;
    542        1.1   thorpej 	queue_stats *stats;
    543        1.1   thorpej 
    544        1.1   thorpej 	if ((wfqp = altq_lookup(gsp->iface.wfq_ifacename, ALTQT_WFQ)) == NULL)
    545        1.1   thorpej 		return (EBADF);
    546        1.1   thorpej 
    547        1.1   thorpej 	if (gsp->qid >= wfqp->nums)
    548        1.1   thorpej 		return (EINVAL);
    549        1.1   thorpej 
    550        1.1   thorpej 	queue = &wfqp->queue[gsp->qid];
    551        1.1   thorpej 	stats = &gsp->stats;
    552        1.1   thorpej 
    553        1.1   thorpej 	stats->bytes		= queue->bytes;
    554        1.1   thorpej 	stats->weight		= queue->weight;
    555        1.1   thorpej 	stats->xmit_cnt		= queue->xmit_cnt;
    556        1.1   thorpej 	stats->drop_cnt		= queue->drop_cnt;
    557        1.1   thorpej 
    558        1.1   thorpej 	return 0;
    559        1.1   thorpej }
    560        1.1   thorpej 
    561        1.1   thorpej 
    562        1.1   thorpej static int
    563       1.15     peter wfq_config(struct wfq_conf *cf)
    564        1.1   thorpej {
    565        1.1   thorpej 	wfq_state_t	*wfqp;
    566        1.1   thorpej 	wfq		*queue;
    567        1.1   thorpej 	int		i, error = 0;
    568        1.1   thorpej 
    569        1.1   thorpej 	if ((wfqp = altq_lookup(cf->iface.wfq_ifacename, ALTQT_WFQ)) == NULL)
    570        1.1   thorpej 		return (EBADF);
    571        1.1   thorpej 
    572        1.1   thorpej 	if(cf->nqueues <= 0 ||  MAX_QSIZE < cf->nqueues)
    573        1.1   thorpej 		cf->nqueues = DEFAULT_QSIZE;
    574        1.1   thorpej 
    575        1.1   thorpej 	if (cf->nqueues != wfqp->nums) {
    576        1.1   thorpej 		/* free queued mbuf */
    577        1.1   thorpej 		wfq_flush(wfqp->ifq);
    578       1.10  christos 		free(wfqp->queue, M_DEVBUF);
    579        1.1   thorpej 
    580       1.10  christos 		queue = malloc(sizeof(wfq) * cf->nqueues, M_DEVBUF,
    581       1.10  christos 		    M_WAITOK|M_ZERO);
    582        1.1   thorpej 		if (queue == NULL)
    583        1.1   thorpej 			return (ENOMEM);
    584        1.1   thorpej 
    585        1.1   thorpej 		wfqp->nums = cf->nqueues;
    586        1.1   thorpej 		wfqp->bytes = 0;
    587        1.1   thorpej 		wfqp->rrp = NULL;
    588        1.1   thorpej 		wfqp->queue = queue;
    589        1.1   thorpej 		for (i = 0; i < wfqp->nums; i++, queue++) {
    590        1.1   thorpej 			queue->next = queue->prev = NULL;
    591        1.1   thorpej 			queue->head = queue->tail = NULL;
    592        1.1   thorpej 			queue->bytes = queue->quota = 0;
    593        1.1   thorpej 			queue->weight = 100;
    594        1.1   thorpej 		}
    595        1.1   thorpej 	}
    596        1.1   thorpej 
    597        1.1   thorpej 	if (cf->qlimit != 0)
    598        1.1   thorpej 		wfqp->hwm = cf->qlimit;
    599        1.1   thorpej 
    600        1.1   thorpej 	switch (cf->hash_policy) {
    601        1.1   thorpej 	case WFQ_HASH_DSTADDR:
    602        1.1   thorpej 		wfqp->hash_func = wfq_hashbydstaddr;
    603        1.1   thorpej 		wfqp->fbmask = FIMB4_DADDR;
    604        1.1   thorpej #ifdef INET6
    605        1.1   thorpej 		wfqp->fbmask |= FIMB6_FLABEL;	/* use flowlabel for ipv6 */
    606        1.1   thorpej #endif
    607        1.1   thorpej 		break;
    608        1.1   thorpej 	case WFQ_HASH_SRCPORT:
    609        1.1   thorpej 		wfqp->hash_func = wfq_hashbysrcport;
    610        1.1   thorpej 		wfqp->fbmask = FIMB4_SPORT;
    611        1.1   thorpej #ifdef INET6
    612        1.1   thorpej 		wfqp->fbmask |= FIMB6_SPORT;
    613        1.1   thorpej #endif
    614        1.1   thorpej 		break;
    615        1.1   thorpej 	case WFQ_HASH_FULL:
    616        1.1   thorpej 		wfqp->hash_func = wfq_hash;
    617        1.1   thorpej 		wfqp->fbmask = FIMB4_ALL;
    618        1.1   thorpej #ifdef INET6
    619        1.1   thorpej 		wfqp->fbmask |= FIMB6_FLABEL;	/* use flowlabel for ipv6 */
    620        1.1   thorpej #endif
    621        1.1   thorpej 		break;
    622       1.19     joerg 	case WFQ_HASH_SRCADDR:
    623       1.19     joerg 		wfqp->hash_func = wfq_hashbysrcaddr;
    624       1.19     joerg 		wfqp->fbmask = FIMB4_DADDR;
    625       1.19     joerg #ifdef INET6
    626       1.19     joerg 		wfqp->fbmask |= FIMB6_FLABEL;	/* use flowlabel for ipv6 */
    627       1.19     joerg #endif
    628       1.19     joerg 		break;
    629        1.1   thorpej 	default:
    630        1.1   thorpej 		error = EINVAL;
    631        1.1   thorpej 		break;
    632        1.1   thorpej 	}
    633        1.1   thorpej 	return error;
    634        1.1   thorpej }
    635        1.1   thorpej 
    636        1.1   thorpej /*
    637        1.1   thorpej  * wfq device interface
    638        1.1   thorpej  */
    639        1.1   thorpej 
    640        1.1   thorpej altqdev_decl(wfq);
    641        1.1   thorpej 
    642        1.1   thorpej int
    643       1.17  christos wfqopen(dev_t dev, int flag, int fmt,
    644       1.17  christos     struct lwp *l)
    645        1.1   thorpej {
    646        1.1   thorpej 	return 0;
    647        1.1   thorpej }
    648        1.1   thorpej 
    649        1.1   thorpej int
    650       1.17  christos wfqclose(dev_t dev, int flag, int fmt,
    651       1.17  christos     struct lwp *l)
    652        1.1   thorpej {
    653        1.1   thorpej 	struct ifnet *ifp;
    654        1.1   thorpej 	struct wfq_interface iface;
    655        1.1   thorpej 	wfq_state_t *wfqp;
    656        1.1   thorpej 	int s;
    657        1.7     perry 
    658        1.3   thorpej 	s = splnet();
    659        1.1   thorpej 	while ((wfqp = wfq_list) != NULL) {
    660        1.1   thorpej 		ifp = wfqp->ifq->altq_ifp;
    661  1.19.28.1      yamt 		snprintf(iface.wfq_ifacename, sizeof(iface.wfq_ifacename),
    662  1.19.28.1      yamt 		    "%s", ifp->if_xname);
    663        1.1   thorpej 		wfq_ifdetach(&iface);
    664        1.1   thorpej 	}
    665        1.1   thorpej 	splx(s);
    666        1.1   thorpej 	return 0;
    667        1.1   thorpej }
    668        1.1   thorpej 
    669        1.1   thorpej int
    670       1.18  christos wfqioctl(dev_t dev, ioctlcmd_t cmd, void *addr, int flag,
    671       1.14  christos     struct lwp *l)
    672        1.1   thorpej {
    673        1.1   thorpej 	int	error = 0;
    674        1.1   thorpej 	int 	s;
    675        1.1   thorpej 
    676        1.1   thorpej 	/* check cmd for superuser only */
    677        1.1   thorpej 	switch (cmd) {
    678        1.1   thorpej 	case WFQ_GET_QID:
    679        1.1   thorpej 	case WFQ_GET_STATS:
    680        1.1   thorpej 		break;
    681        1.1   thorpej 	default:
    682        1.1   thorpej #if (__FreeBSD_version > 400000)
    683        1.1   thorpej 		if ((error = suser(p)) != 0)
    684        1.1   thorpej #else
    685       1.16      elad 		if ((error = kauth_authorize_network(l->l_cred,
    686       1.16      elad 		    KAUTH_NETWORK_ALTQ, KAUTH_REQ_NETWORK_ALTQ_WFQ, NULL,
    687       1.16      elad 		    NULL, NULL)) != 0)
    688        1.1   thorpej #endif
    689        1.1   thorpej 			return (error);
    690        1.1   thorpej 		break;
    691        1.1   thorpej 	}
    692        1.1   thorpej 
    693        1.3   thorpej 	s = splnet();
    694        1.1   thorpej 	switch (cmd) {
    695        1.7     perry 
    696        1.1   thorpej 	case WFQ_ENABLE:
    697        1.1   thorpej 		error = wfq_setenable((struct wfq_interface *)addr, ENABLE);
    698        1.1   thorpej 		break;
    699        1.1   thorpej 
    700        1.1   thorpej 	case WFQ_DISABLE:
    701        1.1   thorpej 		error = wfq_setenable((struct wfq_interface *)addr, DISABLE);
    702        1.1   thorpej 		break;
    703        1.1   thorpej 
    704        1.1   thorpej 	case WFQ_IF_ATTACH:
    705        1.1   thorpej 		error = wfq_ifattach((struct wfq_interface *)addr);
    706        1.1   thorpej 		break;
    707        1.1   thorpej 
    708        1.1   thorpej 	case WFQ_IF_DETACH:
    709        1.1   thorpej 		error = wfq_ifdetach((struct wfq_interface *)addr);
    710        1.1   thorpej 		break;
    711        1.1   thorpej 
    712        1.1   thorpej 	case WFQ_GET_QID:
    713        1.1   thorpej 		error = wfq_getqid((struct wfq_getqid *)addr);
    714        1.1   thorpej 		break;
    715        1.1   thorpej 
    716        1.1   thorpej 	case WFQ_SET_WEIGHT:
    717        1.1   thorpej 		error = wfq_setweight((struct wfq_setweight *)addr);
    718        1.1   thorpej 		break;
    719        1.1   thorpej 
    720        1.1   thorpej 	case WFQ_GET_STATS:
    721        1.1   thorpej 		error = wfq_getstats((struct wfq_getstats *)addr);
    722        1.1   thorpej 		break;
    723        1.1   thorpej 
    724        1.1   thorpej 	case WFQ_CONFIG:
    725        1.1   thorpej 		error = wfq_config((struct wfq_conf *)addr);
    726        1.1   thorpej 		break;
    727        1.1   thorpej 
    728        1.1   thorpej 	default:
    729        1.1   thorpej 		error = EINVAL;
    730        1.1   thorpej 		break;
    731        1.1   thorpej 	}
    732        1.1   thorpej 	splx(s);
    733        1.1   thorpej 	return error;
    734        1.1   thorpej }
    735        1.1   thorpej 
    736        1.1   thorpej #ifdef KLD_MODULE
    737        1.1   thorpej 
    738        1.1   thorpej static struct altqsw wfq_sw =
    739        1.1   thorpej 	{"wfq", wfqopen, wfqclose, wfqioctl};
    740        1.1   thorpej 
    741        1.1   thorpej ALTQ_MODULE(altq_wfq, ALTQT_WFQ, &wfq_sw);
    742        1.1   thorpej 
    743        1.1   thorpej #endif /* KLD_MODULE */
    744        1.1   thorpej 
    745       1.15     peter #endif /* ALTQ3_COMPAT */
    746        1.1   thorpej #endif /* ALTQ_WFQ */
    747