The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/altq/altq_subr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: altq_subr.c,v 1.25.8.2 2008/12/01 00:57:03 snj Exp $   */
    2 /*      $KAME: altq_subr.c,v 1.24 2005/04/13 03:44:25 suz Exp $ */
    3 
    4 /*
    5  * Copyright (C) 1997-2003
    6  *      Sony Computer Science Laboratories Inc.  All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __KERNEL_RCSID(0, "$NetBSD: altq_subr.c,v 1.25.8.2 2008/12/01 00:57:03 snj Exp $");
   32 
   33 #ifdef _KERNEL_OPT
   34 #include "opt_altq.h"
   35 #include "opt_inet.h"
   36 #include "pf.h"
   37 #endif
   38 
   39 #include <sys/param.h>
   40 #include <sys/malloc.h>
   41 #include <sys/mbuf.h>
   42 #include <sys/systm.h>
   43 #include <sys/proc.h>
   44 #include <sys/socket.h>
   45 #include <sys/socketvar.h>
   46 #include <sys/kernel.h>
   47 #include <sys/errno.h>
   48 #include <sys/syslog.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/queue.h>
   51 
   52 #include <net/if.h>
   53 #include <net/if_dl.h>
   54 #include <net/if_types.h>
   55 
   56 #include <netinet/in.h>
   57 #include <netinet/in_systm.h>
   58 #include <netinet/ip.h>
   59 #ifdef INET6
   60 #include <netinet/ip6.h>
   61 #endif
   62 #include <netinet/tcp.h>
   63 #include <netinet/udp.h>
   64 
   65 #if NPF > 0
   66 #include <net/pfvar.h>
   67 #endif
   68 #include <altq/altq.h>
   69 #ifdef ALTQ3_COMPAT
   70 #include <altq/altq_conf.h>
   71 #endif
   72 
   73 /*
   74  * internal function prototypes
   75  */
   76 static void     tbr_timeout(void *);
   77 int (*altq_input)(struct mbuf *, int) = NULL;
   78 static int tbr_timer = 0;       /* token bucket regulator timer */
   79 static struct callout tbr_callout;
   80 
   81 #ifdef ALTQ3_CLFIER_COMPAT
   82 static int      extract_ports4(struct mbuf *, struct ip *, struct flowinfo_in *);
   83 #ifdef INET6
   84 static int      extract_ports6(struct mbuf *, struct ip6_hdr *,
   85                                struct flowinfo_in6 *);
   86 #endif
   87 static int      apply_filter4(u_int32_t, struct flow_filter *,
   88                               struct flowinfo_in *);
   89 static int      apply_ppfilter4(u_int32_t, struct flow_filter *,
   90                                 struct flowinfo_in *);
   91 #ifdef INET6
   92 static int      apply_filter6(u_int32_t, struct flow_filter6 *,
   93                               struct flowinfo_in6 *);
   94 #endif
   95 static int      apply_tosfilter4(u_int32_t, struct flow_filter *,
   96                                  struct flowinfo_in *);
   97 static u_long   get_filt_handle(struct acc_classifier *, int);
   98 static struct acc_filter *filth_to_filtp(struct acc_classifier *, u_long);
   99 static u_int32_t filt2fibmask(struct flow_filter *);
  100 
  101 static void     ip4f_cache(struct ip *, struct flowinfo_in *);
  102 static int      ip4f_lookup(struct ip *, struct flowinfo_in *);
  103 static int      ip4f_init(void);
  104 static struct ip4_frag  *ip4f_alloc(void);
  105 static void     ip4f_free(struct ip4_frag *);
  106 #endif /* ALTQ3_CLFIER_COMPAT */
  107 
  108 /*
  109  * alternate queueing support routines
  110  */
  111 
  112 /* look up the queue state by the interface name and the queueing type. */
  113 void *
  114 altq_lookup(char *name, int type)
  115 {
  116         struct ifnet *ifp;
  117 
  118         if ((ifp = ifunit(name)) != NULL) {
  119                 if (type != ALTQT_NONE && ifp->if_snd.altq_type == type)
  120                         return (ifp->if_snd.altq_disc);
  121         }
  122 
  123         return NULL;
  124 }
  125 
  126 int
  127 altq_attach(struct ifaltq *ifq, int type, void *discipline,
  128     int (*enqueue)(struct ifaltq *, struct mbuf *, struct altq_pktattr *),
  129     struct mbuf *(*dequeue)(struct ifaltq *, int),
  130     int (*request)(struct ifaltq *, int, void *),
  131     void *clfier, void *(*classify)(void *, struct mbuf *, int))
  132 {
  133         if (!ALTQ_IS_READY(ifq))
  134                 return ENXIO;
  135 
  136 #ifdef ALTQ3_COMPAT
  137         /*
  138          * pfaltq can override the existing discipline, but altq3 cannot.
  139          * check these if clfier is not NULL (which implies altq3).
  140          */
  141         if (clfier != NULL) {
  142                 if (ALTQ_IS_ENABLED(ifq))
  143                         return EBUSY;
  144                 if (ALTQ_IS_ATTACHED(ifq))
  145                         return EEXIST;
  146         }
  147 #endif
  148         ifq->altq_type     = type;
  149         ifq->altq_disc     = discipline;
  150         ifq->altq_enqueue  = enqueue;
  151         ifq->altq_dequeue  = dequeue;
  152         ifq->altq_request  = request;
  153         ifq->altq_clfier   = clfier;
  154         ifq->altq_classify = classify;
  155         ifq->altq_flags &= (ALTQF_CANTCHANGE|ALTQF_ENABLED);
  156 #ifdef ALTQ3_COMPAT
  157 #ifdef ALTQ_KLD
  158         altq_module_incref(type);
  159 #endif
  160 #endif
  161         return 0;
  162 }
  163 
  164 int
  165 altq_detach(struct ifaltq *ifq)
  166 {
  167         if (!ALTQ_IS_READY(ifq))
  168                 return ENXIO;
  169         if (ALTQ_IS_ENABLED(ifq))
  170                 return EBUSY;
  171         if (!ALTQ_IS_ATTACHED(ifq))
  172                 return (0);
  173 #ifdef ALTQ3_COMPAT
  174 #ifdef ALTQ_KLD
  175         altq_module_declref(ifq->altq_type);
  176 #endif
  177 #endif
  178 
  179         ifq->altq_type     = ALTQT_NONE;
  180         ifq->altq_disc     = NULL;
  181         ifq->altq_enqueue  = NULL;
  182         ifq->altq_dequeue  = NULL;
  183         ifq->altq_request  = NULL;
  184         ifq->altq_clfier   = NULL;
  185         ifq->altq_classify = NULL;
  186         ifq->altq_flags &= ALTQF_CANTCHANGE;
  187         return 0;
  188 }
  189 
  190 int
  191 altq_enable(struct ifaltq *ifq)
  192 {
  193         int s;
  194 
  195         if (!ALTQ_IS_READY(ifq))
  196                 return ENXIO;
  197         if (ALTQ_IS_ENABLED(ifq))
  198                 return 0;
  199 
  200         s = splnet();
  201         IFQ_PURGE(ifq);
  202         ASSERT(ifq->ifq_len == 0);
  203         ifq->altq_flags |= ALTQF_ENABLED;
  204         if (ifq->altq_clfier != NULL)
  205                 ifq->altq_flags |= ALTQF_CLASSIFY;
  206         splx(s);
  207 
  208         return 0;
  209 }
  210 
  211 int
  212 altq_disable(struct ifaltq *ifq)
  213 {
  214         int s;
  215 
  216         if (!ALTQ_IS_ENABLED(ifq))
  217                 return 0;
  218 
  219         s = splnet();
  220         IFQ_PURGE(ifq);
  221         ASSERT(ifq->ifq_len == 0);
  222         ifq->altq_flags &= ~(ALTQF_ENABLED|ALTQF_CLASSIFY);
  223         splx(s);
  224         return 0;
  225 }
  226 
  227 #ifdef ALTQ_DEBUG
  228 void
  229 altq_assert(const char *file, int line, const char *failedexpr)
  230 {
  231         (void)printf("altq assertion \"%s\" failed: file \"%s\", line %d\n",
  232                      failedexpr, file, line);
  233         panic("altq assertion");
  234         /* NOTREACHED */
  235 }
  236 #endif
  237 
  238 /*
  239  * internal representation of token bucket parameters
  240  *      rate:   byte_per_unittime << 32
  241  *              (((bits_per_sec) / 8) << 32) / machclk_freq
  242  *      depth:  byte << 32
  243  *
  244  */
  245 #define TBR_SHIFT       32
  246 #define TBR_SCALE(x)    ((int64_t)(x) << TBR_SHIFT)
  247 #define TBR_UNSCALE(x)  ((x) >> TBR_SHIFT)
  248 
  249 struct mbuf *
  250 tbr_dequeue(struct ifaltq *ifq, int op)
  251 {
  252         struct tb_regulator *tbr;
  253         struct mbuf *m;
  254         int64_t interval;
  255         u_int64_t now;
  256 
  257         tbr = ifq->altq_tbr;
  258         if (op == ALTDQ_REMOVE && tbr->tbr_lastop == ALTDQ_POLL) {
  259                 /* if this is a remove after poll, bypass tbr check */
  260         } else {
  261                 /* update token only when it is negative */
  262                 if (tbr->tbr_token <= 0) {
  263                         now = read_machclk();
  264                         interval = now - tbr->tbr_last;
  265                         if (interval >= tbr->tbr_filluptime)
  266                                 tbr->tbr_token = tbr->tbr_depth;
  267                         else {
  268                                 tbr->tbr_token += interval * tbr->tbr_rate;
  269                                 if (tbr->tbr_token > tbr->tbr_depth)
  270                                         tbr->tbr_token = tbr->tbr_depth;
  271                         }
  272                         tbr->tbr_last = now;
  273                 }
  274                 /* if token is still negative, don't allow dequeue */
  275                 if (tbr->tbr_token <= 0)
  276                         return (NULL);
  277         }
  278 
  279         if (ALTQ_IS_ENABLED(ifq))
  280                 m = (*ifq->altq_dequeue)(ifq, op);
  281         else {
  282                 if (op == ALTDQ_POLL)
  283                         IF_POLL(ifq, m);
  284                 else
  285                         IF_DEQUEUE(ifq, m);
  286         }
  287 
  288         if (m != NULL && op == ALTDQ_REMOVE)
  289                 tbr->tbr_token -= TBR_SCALE(m_pktlen(m));
  290         tbr->tbr_lastop = op;
  291         return (m);
  292 }
  293 
  294 /*
  295  * set a token bucket regulator.
  296  * if the specified rate is zero, the token bucket regulator is deleted.
  297  */
  298 int
  299 tbr_set(struct ifaltq *ifq, struct tb_profile *profile)
  300 {
  301         struct tb_regulator *tbr, *otbr;
  302 
  303         if (machclk_freq == 0)
  304                 init_machclk();
  305         if (machclk_freq == 0) {
  306                 printf("tbr_set: no CPU clock available!\n");
  307                 return (ENXIO);
  308         }
  309 
  310         if (profile->rate == 0) {
  311                 /* delete this tbr */
  312                 if ((tbr = ifq->altq_tbr) == NULL)
  313                         return (ENOENT);
  314                 ifq->altq_tbr = NULL;
  315                 free(tbr, M_DEVBUF);
  316                 return (0);
  317         }
  318 
  319         tbr = malloc(sizeof(struct tb_regulator), M_DEVBUF, M_WAITOK|M_ZERO);
  320         if (tbr == NULL)
  321                 return (ENOMEM);
  322 
  323         tbr->tbr_rate = TBR_SCALE(profile->rate / 8) / machclk_freq;
  324         tbr->tbr_depth = TBR_SCALE(profile->depth);
  325         if (tbr->tbr_rate > 0)
  326                 tbr->tbr_filluptime = tbr->tbr_depth / tbr->tbr_rate;
  327         else
  328                 tbr->tbr_filluptime = 0xffffffffffffffffLL;
  329         tbr->tbr_token = tbr->tbr_depth;
  330         tbr->tbr_last = read_machclk();
  331         tbr->tbr_lastop = ALTDQ_REMOVE;
  332 
  333         otbr = ifq->altq_tbr;
  334         ifq->altq_tbr = tbr;    /* set the new tbr */
  335 
  336         if (otbr != NULL)
  337                 free(otbr, M_DEVBUF);
  338         else {
  339                 if (tbr_timer == 0) {
  340                         CALLOUT_RESET(&tbr_callout, 1, tbr_timeout, (void *)0);
  341                         tbr_timer = 1;
  342                 }
  343         }
  344         return (0);
  345 }
  346 
  347 /*
  348  * tbr_timeout goes through the interface list, and kicks the drivers
  349  * if necessary.
  350  */
  351 static void
  352 tbr_timeout(void *arg)
  353 {
  354         struct ifnet *ifp;
  355         int active, s;
  356 
  357         active = 0;
  358         s = splnet();
  359         for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
  360                 if (!TBR_IS_ENABLED(&ifp->if_snd))
  361                         continue;
  362                 active++;
  363                 if (!IFQ_IS_EMPTY(&ifp->if_snd) && ifp->if_start != NULL)
  364                         (*ifp->if_start)(ifp);
  365         }
  366         splx(s);
  367         if (active > 0)
  368                 CALLOUT_RESET(&tbr_callout, 1, tbr_timeout, (void *)0);
  369         else
  370                 tbr_timer = 0;  /* don't need tbr_timer anymore */
  371 }
  372 
  373 /*
  374  * get token bucket regulator profile
  375  */
  376 int
  377 tbr_get(struct ifaltq *ifq, struct tb_profile *profile)
  378 {
  379         struct tb_regulator *tbr;
  380 
  381         if ((tbr = ifq->altq_tbr) == NULL) {
  382                 profile->rate = 0;
  383                 profile->depth = 0;
  384         } else {
  385                 profile->rate =
  386                     (u_int)TBR_UNSCALE(tbr->tbr_rate * 8 * machclk_freq);
  387                 profile->depth = (u_int)TBR_UNSCALE(tbr->tbr_depth);
  388         }
  389         return (0);
  390 }
  391 
  392 #if NPF > 0
  393 /*
  394  * attach a discipline to the interface.  if one already exists, it is
  395  * overridden.
  396  */
  397 int
  398 altq_pfattach(struct pf_altq *a)
  399 {
  400         int error = 0;
  401 
  402         switch (a->scheduler) {
  403         case ALTQT_NONE:
  404                 break;
  405 #ifdef ALTQ_CBQ
  406         case ALTQT_CBQ:
  407                 error = cbq_pfattach(a);
  408                 break;
  409 #endif
  410 #ifdef ALTQ_PRIQ
  411         case ALTQT_PRIQ:
  412                 error = priq_pfattach(a);
  413                 break;
  414 #endif
  415 #ifdef ALTQ_HFSC
  416         case ALTQT_HFSC:
  417                 error = hfsc_pfattach(a);
  418                 break;
  419 #endif
  420         default:
  421                 error = ENXIO;
  422         }
  423 
  424         return (error);
  425 }
  426 
  427 /*
  428  * detach a discipline from the interface.
  429  * it is possible that the discipline was already overridden by another
  430  * discipline.
  431  */
  432 int
  433 altq_pfdetach(struct pf_altq *a)
  434 {
  435         struct ifnet *ifp;
  436         int s, error = 0;
  437 
  438         if ((ifp = ifunit(a->ifname)) == NULL)
  439                 return (EINVAL);
  440 
  441         /* if this discipline is no longer referenced, just return */
  442         if (a->altq_disc == NULL || a->altq_disc != ifp->if_snd.altq_disc)
  443                 return (0);
  444 
  445         s = splnet();
  446         if (ALTQ_IS_ENABLED(&ifp->if_snd))
  447                 error = altq_disable(&ifp->if_snd);
  448         if (error == 0)
  449                 error = altq_detach(&ifp->if_snd);
  450         splx(s);
  451 
  452         return (error);
  453 }
  454 
  455 /*
  456  * add a discipline or a queue
  457  */
  458 int
  459 altq_add(struct pf_altq *a)
  460 {
  461         int error = 0;
  462 
  463         if (a->qname[0] != 0)
  464                 return (altq_add_queue(a));
  465 
  466         if (machclk_freq == 0)
  467                 init_machclk();
  468         if (machclk_freq == 0)
  469                 panic("altq_add: no CPU clock");
  470 
  471         switch (a->scheduler) {
  472 #ifdef ALTQ_CBQ
  473         case ALTQT_CBQ:
  474                 error = cbq_add_altq(a);
  475                 break;
  476 #endif
  477 #ifdef ALTQ_PRIQ
  478         case ALTQT_PRIQ:
  479                 error = priq_add_altq(a);
  480                 break;
  481 #endif
  482 #ifdef ALTQ_HFSC
  483         case ALTQT_HFSC:
  484                 error = hfsc_add_altq(a);
  485                 break;
  486 #endif
  487         default:
  488                 error = ENXIO;
  489         }
  490 
  491         return (error);
  492 }
  493 
  494 /*
  495  * remove a discipline or a queue
  496  */
  497 int
  498 altq_remove(struct pf_altq *a)
  499 {
  500         int error = 0;
  501 
  502         if (a->qname[0] != 0)
  503                 return (altq_remove_queue(a));
  504 
  505         switch (a->scheduler) {
  506 #ifdef ALTQ_CBQ
  507         case ALTQT_CBQ:
  508                 error = cbq_remove_altq(a);
  509                 break;
  510 #endif
  511 #ifdef ALTQ_PRIQ
  512         case ALTQT_PRIQ:
  513                 error = priq_remove_altq(a);
  514                 break;
  515 #endif
  516 #ifdef ALTQ_HFSC
  517         case ALTQT_HFSC:
  518                 error = hfsc_remove_altq(a);
  519                 break;
  520 #endif
  521         default:
  522                 error = ENXIO;
  523         }
  524 
  525         return (error);
  526 }
  527 
  528 /*
  529  * add a queue to the discipline
  530  */
  531 int
  532 altq_add_queue(struct pf_altq *a)
  533 {
  534         int error = 0;
  535 
  536         switch (a->scheduler) {
  537 #ifdef ALTQ_CBQ
  538         case ALTQT_CBQ:
  539                 error = cbq_add_queue(a);
  540                 break;
  541 #endif
  542 #ifdef ALTQ_PRIQ
  543         case ALTQT_PRIQ:
  544                 error = priq_add_queue(a);
  545                 break;
  546 #endif
  547 #ifdef ALTQ_HFSC
  548         case ALTQT_HFSC:
  549                 error = hfsc_add_queue(a);
  550                 break;
  551 #endif
  552         default:
  553                 error = ENXIO;
  554         }
  555 
  556         return (error);
  557 }
  558 
  559 /*
  560  * remove a queue from the discipline
  561  */
  562 int
  563 altq_remove_queue(struct pf_altq *a)
  564 {
  565         int error = 0;
  566 
  567         switch (a->scheduler) {
  568 #ifdef ALTQ_CBQ
  569         case ALTQT_CBQ:
  570                 error = cbq_remove_queue(a);
  571                 break;
  572 #endif
  573 #ifdef ALTQ_PRIQ
  574         case ALTQT_PRIQ:
  575                 error = priq_remove_queue(a);
  576                 break;
  577 #endif
  578 #ifdef ALTQ_HFSC
  579         case ALTQT_HFSC:
  580                 error = hfsc_remove_queue(a);
  581                 break;
  582 #endif
  583         default:
  584                 error = ENXIO;
  585         }
  586 
  587         return (error);
  588 }
  589 
  590 /*
  591  * get queue statistics
  592  */
  593 int
  594 altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
  595 {
  596         int error = 0;
  597 
  598         switch (a->scheduler) {
  599 #ifdef ALTQ_CBQ
  600         case ALTQT_CBQ:
  601                 error = cbq_getqstats(a, ubuf, nbytes);
  602                 break;
  603 #endif
  604 #ifdef ALTQ_PRIQ
  605         case ALTQT_PRIQ:
  606                 error = priq_getqstats(a, ubuf, nbytes);
  607                 break;
  608 #endif
  609 #ifdef ALTQ_HFSC
  610         case ALTQT_HFSC:
  611                 error = hfsc_getqstats(a, ubuf, nbytes);
  612                 break;
  613 #endif
  614         default:
  615                 error = ENXIO;
  616         }
  617 
  618         return (error);
  619 }
  620 #endif /* NPF > 0 */
  621 
  622 /*
  623  * read and write diffserv field in IPv4 or IPv6 header
  624  */
  625 u_int8_t
  626 read_dsfield(struct mbuf *m, struct altq_pktattr *pktattr)
  627 {
  628         struct mbuf *m0;
  629         u_int8_t ds_field = 0;
  630 
  631         if (pktattr == NULL ||
  632             (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6))
  633                 return ((u_int8_t)0);
  634 
  635         /* verify that pattr_hdr is within the mbuf data */
  636         for (m0 = m; m0 != NULL; m0 = m0->m_next)
  637                 if (((char *)pktattr->pattr_hdr >= m0->m_data) &&
  638                     ((char *)pktattr->pattr_hdr < m0->m_data + m0->m_len))
  639                         break;
  640         if (m0 == NULL) {
  641                 /* ick, pattr_hdr is stale */
  642                 pktattr->pattr_af = AF_UNSPEC;
  643 #ifdef ALTQ_DEBUG
  644                 printf("read_dsfield: can't locate header!\n");
  645 #endif
  646                 return ((u_int8_t)0);
  647         }
  648 
  649         if (pktattr->pattr_af == AF_INET) {
  650                 struct ip *ip = (struct ip *)pktattr->pattr_hdr;
  651 
  652                 if (ip->ip_v != 4)
  653                         return ((u_int8_t)0);   /* version mismatch! */
  654                 ds_field = ip->ip_tos;
  655         }
  656 #ifdef INET6
  657         else if (pktattr->pattr_af == AF_INET6) {
  658                 struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
  659                 u_int32_t flowlabel;
  660 
  661                 flowlabel = ntohl(ip6->ip6_flow);
  662                 if ((flowlabel >> 28) != 6)
  663                         return ((u_int8_t)0);   /* version mismatch! */
  664                 ds_field = (flowlabel >> 20) & 0xff;
  665         }
  666 #endif
  667         return (ds_field);
  668 }
  669 
  670 void
  671 write_dsfield(struct mbuf *m, struct altq_pktattr *pktattr, u_int8_t dsfield)
  672 {
  673         struct mbuf *m0;
  674 
  675         if (pktattr == NULL ||
  676             (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6))
  677                 return;
  678 
  679         /* verify that pattr_hdr is within the mbuf data */
  680         for (m0 = m; m0 != NULL; m0 = m0->m_next)
  681                 if (((char *)pktattr->pattr_hdr >= m0->m_data) &&
  682                     ((char *)pktattr->pattr_hdr < m0->m_data + m0->m_len))
  683                         break;
  684         if (m0 == NULL) {
  685                 /* ick, pattr_hdr is stale */
  686                 pktattr->pattr_af = AF_UNSPEC;
  687 #ifdef ALTQ_DEBUG
  688                 printf("write_dsfield: can't locate header!\n");
  689 #endif
  690                 return;
  691         }
  692 
  693         if (pktattr->pattr_af == AF_INET) {
  694                 struct ip *ip = (struct ip *)pktattr->pattr_hdr;
  695                 u_int8_t old;
  696                 int32_t sum;
  697 
  698                 if (ip->ip_v != 4)
  699                         return;         /* version mismatch! */
  700                 old = ip->ip_tos;
  701                 dsfield |= old & 3;     /* leave CU bits */
  702                 if (old == dsfield)
  703                         return;
  704                 ip->ip_tos = dsfield;
  705                 /*
  706                  * update checksum (from RFC1624)
  707                  *         HC' = ~(~HC + ~m + m')
  708                  */
  709                 sum = ~ntohs(ip->ip_sum) & 0xffff;
  710                 sum += 0xff00 + (~old & 0xff) + dsfield;
  711                 sum = (sum >> 16) + (sum & 0xffff);
  712                 sum += (sum >> 16);  /* add carry */
  713 
  714                 ip->ip_sum = htons(~sum & 0xffff);
  715         }
  716 #ifdef INET6
  717         else if (pktattr->pattr_af == AF_INET6) {
  718                 struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
  719                 u_int32_t flowlabel;
  720 
  721                 flowlabel = ntohl(ip6->ip6_flow);
  722                 if ((flowlabel >> 28) != 6)
  723                         return;         /* version mismatch! */
  724                 flowlabel = (flowlabel & 0xf03fffff) | (dsfield << 20);
  725                 ip6->ip6_flow = htonl(flowlabel);
  726         }
  727 #endif
  728         return;
  729 }
  730 
  731 #define BINTIME_SHIFT   2
  732 
  733 u_int32_t machclk_freq = 0;
  734 u_int32_t machclk_per_tick = 0;
  735 
  736 void
  737 init_machclk(void)
  738 {
  739 
  740         callout_init(&tbr_callout, 0);
  741 
  742         /*
  743          * Always emulate 1GiHz counter using bintime(9)
  744          * since it has enough resolution via timecounter(9).
  745          * Using machine dependent cpu_counter() is not MP safe
  746          * and it won't work even on UP with Speedstep etc.
  747          */
  748         machclk_freq = 1024 * 1024 * 1024;      /* 2^30 to emulate ~1GHz */
  749         machclk_per_tick = machclk_freq / hz;
  750 #ifdef ALTQ_DEBUG
  751         printf("altq: emulate %uHz CPU clock\n", machclk_freq);
  752 #endif
  753 }
  754 
  755 u_int64_t
  756 read_machclk(void)
  757 {
  758         struct bintime bt;
  759         u_int64_t val;
  760 
  761         binuptime(&bt);
  762         val = (((u_int64_t)bt.sec << 32) + (bt.frac >> 32)) >> BINTIME_SHIFT;
  763         return (val);
  764 }
  765 
  766 #ifdef ALTQ3_CLFIER_COMPAT
  767 
  768 #ifndef IPPROTO_ESP
  769 #define IPPROTO_ESP     50              /* encapsulating security payload */
  770 #endif
  771 #ifndef IPPROTO_AH
  772 #define IPPROTO_AH      51              /* authentication header */
  773 #endif
  774 
  775 /*
  776  * extract flow information from a given packet.
  777  * filt_mask shows flowinfo fields required.
  778  * we assume the ip header is in one mbuf, and addresses and ports are
  779  * in network byte order.
  780  */
  781 int
  782 altq_extractflow(struct mbuf *m, int af, struct flowinfo *flow,
  783     u_int32_t filt_bmask)
  784 {
  785 
  786         switch (af) {
  787         case PF_INET: {
  788                 struct flowinfo_in *fin;
  789                 struct ip *ip;
  790 
  791                 ip = mtod(m, struct ip *);
  792 
  793                 if (ip->ip_v != 4)
  794                         break;
  795 
  796                 fin = (struct flowinfo_in *)flow;
  797                 fin->fi_len = sizeof(struct flowinfo_in);
  798                 fin->fi_family = AF_INET;
  799 
  800                 fin->fi_proto = ip->ip_p;
  801                 fin->fi_tos = ip->ip_tos;
  802 
  803                 fin->fi_src.s_addr = ip->ip_src.s_addr;
  804                 fin->fi_dst.s_addr = ip->ip_dst.s_addr;
  805 
  806                 if (filt_bmask & FIMB4_PORTS)
  807                         /* if port info is required, extract port numbers */
  808                         extract_ports4(m, ip, fin);
  809                 else {
  810                         fin->fi_sport = 0;
  811                         fin->fi_dport = 0;
  812                         fin->fi_gpi = 0;
  813                 }
  814                 return (1);
  815         }
  816 
  817 #ifdef INET6
  818         case PF_INET6: {
  819                 struct flowinfo_in6 *fin6;
  820                 struct ip6_hdr *ip6;
  821 
  822                 ip6 = mtod(m, struct ip6_hdr *);
  823                 /* should we check the ip version? */
  824 
  825                 fin6 = (struct flowinfo_in6 *)flow;
  826                 fin6->fi6_len = sizeof(struct flowinfo_in6);
  827                 fin6->fi6_family = AF_INET6;
  828 
  829                 fin6->fi6_proto = ip6->ip6_nxt;
  830                 fin6->fi6_tclass   = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
  831 
  832                 fin6->fi6_flowlabel = ip6->ip6_flow & htonl(0x000fffff);
  833                 fin6->fi6_src = ip6->ip6_src;
  834                 fin6->fi6_dst = ip6->ip6_dst;
  835 
  836                 if ((filt_bmask & FIMB6_PORTS) ||
  837                     ((filt_bmask & FIMB6_PROTO)
  838                      && ip6->ip6_nxt > IPPROTO_IPV6))
  839                         /*
  840                          * if port info is required, or proto is required
  841                          * but there are option headers, extract port
  842                          * and protocol numbers.
  843                          */
  844                         extract_ports6(m, ip6, fin6);
  845                 else {
  846                         fin6->fi6_sport = 0;
  847                         fin6->fi6_dport = 0;
  848                         fin6->fi6_gpi = 0;
  849                 }
  850                 return (1);
  851         }
  852 #endif /* INET6 */
  853 
  854         default:
  855                 break;
  856         }
  857 
  858         /* failed */
  859         flow->fi_len = sizeof(struct flowinfo);
  860         flow->fi_family = AF_UNSPEC;
  861         return (0);
  862 }
  863 
  864 /*
  865  * helper routine to extract port numbers
  866  */
  867 /* structure for ipsec and ipv6 option header template */
  868 struct _opt6 {
  869         u_int8_t        opt6_nxt;       /* next header */
  870         u_int8_t        opt6_hlen;      /* header extension length */
  871         u_int16_t       _pad;
  872         u_int32_t       ah_spi;         /* security parameter index
  873                                            for authentication header */
  874 };
  875 
  876 /*
  877  * extract port numbers from a ipv4 packet.
  878  */
  879 static int
  880 extract_ports4(struct mbuf *m, struct ip *ip, struct flowinfo_in *fin)
  881 {
  882         struct mbuf *m0;
  883         u_short ip_off;
  884         u_int8_t proto;
  885         int     off;
  886 
  887         fin->fi_sport = 0;
  888         fin->fi_dport = 0;
  889         fin->fi_gpi = 0;
  890 
  891         ip_off = ntohs(ip->ip_off);
  892         /* if it is a fragment, try cached fragment info */
  893         if (ip_off & IP_OFFMASK) {
  894                 ip4f_lookup(ip, fin);
  895                 return (1);
  896         }
  897 
  898         /* locate the mbuf containing the protocol header */
  899         for (m0 = m; m0 != NULL; m0 = m0->m_next)
  900                 if (((char *)ip >= m0->m_data) &&
  901                     ((char *)ip < m0->m_data + m0->m_len))
  902                         break;
  903         if (m0 == NULL) {
  904 #ifdef ALTQ_DEBUG
  905                 printf("extract_ports4: can't locate header! ip=%p\n", ip);
  906 #endif
  907                 return (0);
  908         }
  909         off = ((char *)ip - m0->m_data) + (ip->ip_hl << 2);
  910         proto = ip->ip_p;
  911 
  912 #ifdef ALTQ_IPSEC
  913  again:
  914 #endif
  915         while (off >= m0->m_len) {
  916                 off -= m0->m_len;
  917                 m0 = m0->m_next;
  918                 if (m0 == NULL)
  919                         return (0);  /* bogus ip_hl! */
  920         }
  921         if (m0->m_len < off + 4)
  922                 return (0);
  923 
  924         switch (proto) {
  925         case IPPROTO_TCP:
  926         case IPPROTO_UDP: {
  927                 struct udphdr *udp;
  928 
  929                 udp = (struct udphdr *)(mtod(m0, char *) + off);
  930                 fin->fi_sport = udp->uh_sport;
  931                 fin->fi_dport = udp->uh_dport;
  932                 fin->fi_proto = proto;
  933                 }
  934                 break;
  935 
  936 #ifdef ALTQ_IPSEC
  937         case IPPROTO_ESP:
  938                 if (fin->fi_gpi == 0){
  939                         u_int32_t *gpi;
  940 
  941                         gpi = (u_int32_t *)(mtod(m0, char *) + off);
  942                         fin->fi_gpi   = *gpi;
  943                 }
  944                 fin->fi_proto = proto;
  945                 break;
  946 
  947         case IPPROTO_AH: {
  948                         /* get next header and header length */
  949                         struct _opt6 *opt6;
  950 
  951                         opt6 = (struct _opt6 *)(mtod(m0, char *) + off);
  952                         proto = opt6->opt6_nxt;
  953                         off += 8 + (opt6->opt6_hlen * 4);
  954                         if (fin->fi_gpi == 0 && m0->m_len >= off + 8)
  955                                 fin->fi_gpi = opt6->ah_spi;
  956                 }
  957                 /* goto the next header */
  958                 goto again;
  959 #endif  /* ALTQ_IPSEC */
  960 
  961         default:
  962                 fin->fi_proto = proto;
  963                 return (0);
  964         }
  965 
  966         /* if this is a first fragment, cache it. */
  967         if (ip_off & IP_MF)
  968                 ip4f_cache(ip, fin);
  969 
  970         return (1);
  971 }
  972 
  973 #ifdef INET6
  974 static int
  975 extract_ports6(struct mbuf *m, struct ip6_hdr *ip6, struct flowinfo_in6 *fin6)
  976 {
  977         struct mbuf *m0;
  978         int     off;
  979         u_int8_t proto;
  980 
  981         fin6->fi6_gpi   = 0;
  982         fin6->fi6_sport = 0;
  983         fin6->fi6_dport = 0;
  984 
  985         /* locate the mbuf containing the protocol header */
  986         for (m0 = m; m0 != NULL; m0 = m0->m_next)
  987                 if (((char *)ip6 >= m0->m_data) &&
  988                     ((char *)ip6 < m0->m_data + m0->m_len))
  989                         break;
  990         if (m0 == NULL) {
  991 #ifdef ALTQ_DEBUG
  992                 printf("extract_ports6: can't locate header! ip6=%p\n", ip6);
  993 #endif
  994                 return (0);
  995         }
  996         off = ((char *)ip6 - m0->m_data) + sizeof(struct ip6_hdr);
  997 
  998         proto = ip6->ip6_nxt;
  999         do {
 1000                 while (off >= m0->m_len) {
 1001                         off -= m0->m_len;
 1002                         m0 = m0->m_next;
 1003                         if (m0 == NULL)
 1004                                 return (0);
 1005                 }
 1006                 if (m0->m_len < off + 4)
 1007                         return (0);
 1008 
 1009                 switch (proto) {
 1010                 case IPPROTO_TCP:
 1011                 case IPPROTO_UDP: {
 1012                         struct udphdr *udp;
 1013 
 1014                         udp = (struct udphdr *)(mtod(m0, char *) + off);
 1015                         fin6->fi6_sport = udp->uh_sport;
 1016                         fin6->fi6_dport = udp->uh_dport;
 1017                         fin6->fi6_proto = proto;
 1018                         }
 1019                         return (1);
 1020 
 1021                 case IPPROTO_ESP:
 1022                         if (fin6->fi6_gpi == 0) {
 1023                                 u_int32_t *gpi;
 1024 
 1025                                 gpi = (u_int32_t *)(mtod(m0, char *) + off);
 1026                                 fin6->fi6_gpi   = *gpi;
 1027                         }
 1028                         fin6->fi6_proto = proto;
 1029                         return (1);
 1030 
 1031                 case IPPROTO_AH: {
 1032                         /* get next header and header length */
 1033                         struct _opt6 *opt6;
 1034 
 1035                         opt6 = (struct _opt6 *)(mtod(m0, char *) + off);
 1036                         if (fin6->fi6_gpi == 0 && m0->m_len >= off + 8)
 1037                                 fin6->fi6_gpi = opt6->ah_spi;
 1038                         proto = opt6->opt6_nxt;
 1039                         off += 8 + (opt6->opt6_hlen * 4);
 1040                         /* goto the next header */
 1041                         break;
 1042                         }
 1043 
 1044                 case IPPROTO_HOPOPTS:
 1045                 case IPPROTO_ROUTING:
 1046                 case IPPROTO_DSTOPTS: {
 1047                         /* get next header and header length */
 1048                         struct _opt6 *opt6;
 1049 
 1050                         opt6 = (struct _opt6 *)(mtod(m0, char *) + off);
 1051                         proto = opt6->opt6_nxt;
 1052                         off += (opt6->opt6_hlen + 1) * 8;
 1053                         /* goto the next header */
 1054                         break;
 1055                         }
 1056 
 1057                 case IPPROTO_FRAGMENT:
 1058                         /* ipv6 fragmentations are not supported yet */
 1059                 default:
 1060                         fin6->fi6_proto = proto;
 1061                         return (0);
 1062                 }
 1063         } while (1);
 1064         /*NOTREACHED*/
 1065 }
 1066 #endif /* INET6 */
 1067 
 1068 /*
 1069  * altq common classifier
 1070  */
 1071 int
 1072 acc_add_filter(struct acc_classifier *classifier, struct flow_filter *filter,
 1073     void *class, u_long *phandle)
 1074 {
 1075         struct acc_filter *afp, *prev, *tmp;
 1076         int     i, s;
 1077 
 1078 #ifdef INET6
 1079         if (filter->ff_flow.fi_family != AF_INET &&
 1080             filter->ff_flow.fi_family != AF_INET6)
 1081                 return (EINVAL);
 1082 #else
 1083         if (filter->ff_flow.fi_family != AF_INET)
 1084                 return (EINVAL);
 1085 #endif
 1086 
 1087         afp = malloc(sizeof(struct acc_filter), M_DEVBUF, M_WAITOK|M_ZERO);
 1088         if (afp == NULL)
 1089                 return (ENOMEM);
 1090 
 1091         afp->f_filter = *filter;
 1092         afp->f_class = class;
 1093 
 1094         i = ACC_WILDCARD_INDEX;
 1095         if (filter->ff_flow.fi_family == AF_INET) {
 1096                 struct flow_filter *filter4 = &afp->f_filter;
 1097 
 1098                 /*
 1099                  * if address is 0, it's a wildcard.  if address mask
 1100                  * isn't set, use full mask.
 1101                  */
 1102                 if (filter4->ff_flow.fi_dst.s_addr == 0)
 1103                         filter4->ff_mask.mask_dst.s_addr = 0;
 1104                 else if (filter4->ff_mask.mask_dst.s_addr == 0)
 1105                         filter4->ff_mask.mask_dst.s_addr = 0xffffffff;
 1106                 if (filter4->ff_flow.fi_src.s_addr == 0)
 1107                         filter4->ff_mask.mask_src.s_addr = 0;
 1108                 else if (filter4->ff_mask.mask_src.s_addr == 0)
 1109                         filter4->ff_mask.mask_src.s_addr = 0xffffffff;
 1110 
 1111                 /* clear extra bits in addresses  */
 1112                    filter4->ff_flow.fi_dst.s_addr &=
 1113                        filter4->ff_mask.mask_dst.s_addr;
 1114                    filter4->ff_flow.fi_src.s_addr &=
 1115                        filter4->ff_mask.mask_src.s_addr;
 1116 
 1117                 /*
 1118                  * if dst address is a wildcard, use hash-entry
 1119                  * ACC_WILDCARD_INDEX.
 1120                  */
 1121                 if (filter4->ff_mask.mask_dst.s_addr != 0xffffffff)
 1122                         i = ACC_WILDCARD_INDEX;
 1123                 else
 1124                         i = ACC_GET_HASH_INDEX(filter4->ff_flow.fi_dst.s_addr);
 1125         }
 1126 #ifdef INET6
 1127         else if (filter->ff_flow.fi_family == AF_INET6) {
 1128                 struct flow_filter6 *filter6 =
 1129                         (struct flow_filter6 *)&afp->f_filter;
 1130 #ifndef IN6MASK0 /* taken from kame ipv6 */
 1131 #define IN6MASK0        {{{ 0, 0, 0, 0 }}}
 1132 #define IN6MASK128      {{{ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }}}
 1133                 const struct in6_addr in6mask0 = IN6MASK0;
 1134                 const struct in6_addr in6mask128 = IN6MASK128;
 1135 #endif
 1136 
 1137                 if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_flow6.fi6_dst))
 1138                         filter6->ff_mask6.mask6_dst = in6mask0;
 1139                 else if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_mask6.mask6_dst))
 1140                         filter6->ff_mask6.mask6_dst = in6mask128;
 1141                 if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_flow6.fi6_src))
 1142                         filter6->ff_mask6.mask6_src = in6mask0;
 1143                 else if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_mask6.mask6_src))
 1144                         filter6->ff_mask6.mask6_src = in6mask128;
 1145 
 1146                 /* clear extra bits in addresses  */
 1147                 for (i = 0; i < 16; i++)
 1148                         filter6->ff_flow6.fi6_dst.s6_addr[i] &=
 1149                             filter6->ff_mask6.mask6_dst.s6_addr[i];
 1150                 for (i = 0; i < 16; i++)
 1151                         filter6->ff_flow6.fi6_src.s6_addr[i] &=
 1152                             filter6->ff_mask6.mask6_src.s6_addr[i];
 1153 
 1154                 if (filter6->ff_flow6.fi6_flowlabel == 0)
 1155                         i = ACC_WILDCARD_INDEX;
 1156                 else
 1157                         i = ACC_GET_HASH_INDEX(filter6->ff_flow6.fi6_flowlabel);
 1158         }
 1159 #endif /* INET6 */
 1160 
 1161         afp->f_handle = get_filt_handle(classifier, i);
 1162 
 1163         /* update filter bitmask */
 1164         afp->f_fbmask = filt2fibmask(filter);
 1165         classifier->acc_fbmask |= afp->f_fbmask;
 1166 
 1167         /*
 1168          * add this filter to the filter list.
 1169          * filters are ordered from the highest rule number.
 1170          */
 1171         s = splnet();
 1172         prev = NULL;
 1173         LIST_FOREACH(tmp, &classifier->acc_filters[i], f_chain) {
 1174                 if (tmp->f_filter.ff_ruleno > afp->f_filter.ff_ruleno)
 1175                         prev = tmp;
 1176                 else
 1177                         break;
 1178         }
 1179         if (prev == NULL)
 1180                 LIST_INSERT_HEAD(&classifier->acc_filters[i], afp, f_chain);
 1181         else
 1182                 LIST_INSERT_AFTER(prev, afp, f_chain);
 1183         splx(s);
 1184 
 1185         *phandle = afp->f_handle;
 1186         return (0);
 1187 }
 1188 
 1189 int
 1190 acc_delete_filter(struct acc_classifier *classifier, u_long handle)
 1191 {
 1192         struct acc_filter *afp;
 1193         int     s;
 1194 
 1195         if ((afp = filth_to_filtp(classifier, handle)) == NULL)
 1196                 return (EINVAL);
 1197 
 1198         s = splnet();
 1199         LIST_REMOVE(afp, f_chain);
 1200         splx(s);
 1201 
 1202         free(afp, M_DEVBUF);
 1203 
 1204         /* todo: update filt_bmask */
 1205 
 1206         return (0);
 1207 }
 1208 
 1209 /*
 1210  * delete filters referencing to the specified class.
 1211  * if the all flag is not 0, delete all the filters.
 1212  */
 1213 int
 1214 acc_discard_filters(struct acc_classifier *classifier, void *class, int all)
 1215 {
 1216         struct acc_filter *afp;
 1217         int     i, s;
 1218 
 1219         s = splnet();
 1220         for (i = 0; i < ACC_FILTER_TABLESIZE; i++) {
 1221                 do {
 1222                         LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain)
 1223                                 if (all || afp->f_class == class) {
 1224                                         LIST_REMOVE(afp, f_chain);
 1225                                         free(afp, M_DEVBUF);
 1226                                         /* start again from the head */
 1227                                         break;
 1228                                 }
 1229                 } while (afp != NULL);
 1230         }
 1231         splx(s);
 1232 
 1233         if (all)
 1234                 classifier->acc_fbmask = 0;
 1235 
 1236         return (0);
 1237 }
 1238 
 1239 void *
 1240 acc_classify(void *clfier, struct mbuf *m, int af)
 1241 {
 1242         struct acc_classifier *classifier;
 1243         struct flowinfo flow;
 1244         struct acc_filter *afp;
 1245         int     i;
 1246 
 1247         classifier = (struct acc_classifier *)clfier;
 1248         altq_extractflow(m, af, &flow, classifier->acc_fbmask);
 1249 
 1250         if (flow.fi_family == AF_INET) {
 1251                 struct flowinfo_in *fp = (struct flowinfo_in *)&flow;
 1252 
 1253                 if ((classifier->acc_fbmask & FIMB4_ALL) == FIMB4_TOS) {
 1254                         /* only tos is used */
 1255                         LIST_FOREACH(afp,
 1256                                  &classifier->acc_filters[ACC_WILDCARD_INDEX],
 1257                                  f_chain)
 1258                                 if (apply_tosfilter4(afp->f_fbmask,
 1259                                                      &afp->f_filter, fp))
 1260                                         /* filter matched */
 1261                                         return (afp->f_class);
 1262                 } else if ((classifier->acc_fbmask &
 1263                         (~(FIMB4_PROTO|FIMB4_SPORT|FIMB4_DPORT) & FIMB4_ALL))
 1264                     == 0) {
 1265                         /* only proto and ports are used */
 1266                         LIST_FOREACH(afp,
 1267                                  &classifier->acc_filters[ACC_WILDCARD_INDEX],
 1268                                  f_chain)
 1269                                 if (apply_ppfilter4(afp->f_fbmask,
 1270                                                     &afp->f_filter, fp))
 1271                                         /* filter matched */
 1272                                         return (afp->f_class);
 1273                 } else {
 1274                         /* get the filter hash entry from its dest address */
 1275                         i = ACC_GET_HASH_INDEX(fp->fi_dst.s_addr);
 1276                         do {
 1277                                 /*
 1278                                  * go through this loop twice.  first for dst
 1279                                  * hash, second for wildcards.
 1280                                  */
 1281                                 LIST_FOREACH(afp, &classifier->acc_filters[i],
 1282                                              f_chain)
 1283                                         if (apply_filter4(afp->f_fbmask,
 1284                                                           &afp->f_filter, fp))
 1285                                                 /* filter matched */
 1286                                                 return (afp->f_class);
 1287 
 1288                                 /*
 1289                                  * check again for filters with a dst addr
 1290                                  * wildcard.
 1291                                  * (daddr == 0 || dmask != 0xffffffff).
 1292                                  */
 1293                                 if (i != ACC_WILDCARD_INDEX)
 1294                                         i = ACC_WILDCARD_INDEX;
 1295                                 else
 1296                                         break;
 1297                         } while (1);
 1298                 }
 1299         }
 1300 #ifdef INET6
 1301         else if (flow.fi_family == AF_INET6) {
 1302                 struct flowinfo_in6 *fp6 = (struct flowinfo_in6 *)&flow;
 1303 
 1304                 /* get the filter hash entry from its flow ID */
 1305                 if (fp6->fi6_flowlabel != 0)
 1306                         i = ACC_GET_HASH_INDEX(fp6->fi6_flowlabel);
 1307                 else
 1308                         /* flowlable can be zero */
 1309                         i = ACC_WILDCARD_INDEX;
 1310 
 1311                 /* go through this loop twice.  first for flow hash, second
 1312                    for wildcards. */
 1313                 do {
 1314                         LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain)
 1315                                 if (apply_filter6(afp->f_fbmask,
 1316                                         (struct flow_filter6 *)&afp->f_filter,
 1317                                         fp6))
 1318                                         /* filter matched */
 1319                                         return (afp->f_class);
 1320 
 1321                         /*
 1322                          * check again for filters with a wildcard.
 1323                          */
 1324                         if (i != ACC_WILDCARD_INDEX)
 1325                                 i = ACC_WILDCARD_INDEX;
 1326                         else
 1327                                 break;
 1328                 } while (1);
 1329         }
 1330 #endif /* INET6 */
 1331 
 1332         /* no filter matched */
 1333         return (NULL);
 1334 }
 1335 
 1336 static int
 1337 apply_filter4(u_int32_t fbmask, struct flow_filter *filt,
 1338     struct flowinfo_in *pkt)
 1339 {
 1340         if (filt->ff_flow.fi_family != AF_INET)
 1341                 return (0);
 1342         if ((fbmask & FIMB4_SPORT) && filt->ff_flow.fi_sport != pkt->fi_sport)
 1343                 return (0);
 1344         if ((fbmask & FIMB4_DPORT) && filt->ff_flow.fi_dport != pkt->fi_dport)
 1345                 return (0);
 1346         if ((fbmask & FIMB4_DADDR) &&
 1347             filt->ff_flow.fi_dst.s_addr !=
 1348             (pkt->fi_dst.s_addr & filt->ff_mask.mask_dst.s_addr))
 1349                 return (0);
 1350         if ((fbmask & FIMB4_SADDR) &&
 1351             filt->ff_flow.fi_src.s_addr !=
 1352             (pkt->fi_src.s_addr & filt->ff_mask.mask_src.s_addr))
 1353                 return (0);
 1354         if ((fbmask & FIMB4_PROTO) && filt->ff_flow.fi_proto != pkt->fi_proto)
 1355                 return (0);
 1356         if ((fbmask & FIMB4_TOS) && filt->ff_flow.fi_tos !=
 1357             (pkt->fi_tos & filt->ff_mask.mask_tos))
 1358                 return (0);
 1359         if ((fbmask & FIMB4_GPI) && filt->ff_flow.fi_gpi != (pkt->fi_gpi))
 1360                 return (0);
 1361         /* match */
 1362         return (1);
 1363 }
 1364 
 1365 /*
 1366  * filter matching function optimized for a common case that checks
 1367  * only protocol and port numbers
 1368  */
 1369 static int
 1370 apply_ppfilter4(u_int32_t fbmask, struct flow_filter *filt,
 1371     struct flowinfo_in *pkt)
 1372 {
 1373         if (filt->ff_flow.fi_family != AF_INET)
 1374                 return (0);
 1375         if ((fbmask & FIMB4_SPORT) && filt->ff_flow.fi_sport != pkt->fi_sport)
 1376                 return (0);
 1377         if ((fbmask & FIMB4_DPORT) && filt->ff_flow.fi_dport != pkt->fi_dport)
 1378                 return (0);
 1379         if ((fbmask & FIMB4_PROTO) && filt->ff_flow.fi_proto != pkt->fi_proto)
 1380                 return (0);
 1381         /* match */
 1382         return (1);
 1383 }
 1384 
 1385 /*
 1386  * filter matching function only for tos field.
 1387  */
 1388 static int
 1389 apply_tosfilter4(u_int32_t fbmask, struct flow_filter *filt,
 1390     struct flowinfo_in *pkt)
 1391 {
 1392         if (filt->ff_flow.fi_family != AF_INET)
 1393                 return (0);
 1394         if ((fbmask & FIMB4_TOS) && filt->ff_flow.fi_tos !=
 1395             (pkt->fi_tos & filt->ff_mask.mask_tos))
 1396                 return (0);
 1397         /* match */
 1398         return (1);
 1399 }
 1400 
 1401 #ifdef INET6
 1402 static int
 1403 apply_filter6(u_int32_t fbmask, struct flow_filter6 *filt,
 1404     struct flowinfo_in6 *pkt)
 1405 {
 1406         int i;
 1407 
 1408         if (filt->ff_flow6.fi6_family != AF_INET6)
 1409                 return (0);
 1410         if ((fbmask & FIMB6_FLABEL) &&
 1411             filt->ff_flow6.fi6_flowlabel != pkt->fi6_flowlabel)
 1412                 return (0);
 1413         if ((fbmask & FIMB6_PROTO) &&
 1414             filt->ff_flow6.fi6_proto != pkt->fi6_proto)
 1415                 return (0);
 1416         if ((fbmask & FIMB6_SPORT) &&
 1417             filt->ff_flow6.fi6_sport != pkt->fi6_sport)
 1418                 return (0);
 1419         if ((fbmask & FIMB6_DPORT) &&
 1420             filt->ff_flow6.fi6_dport != pkt->fi6_dport)
 1421                 return (0);
 1422         if (fbmask & FIMB6_SADDR) {
 1423                 for (i = 0; i < 4; i++)
 1424                         if (filt->ff_flow6.fi6_src.s6_addr32[i] !=
 1425                             (pkt->fi6_src.s6_addr32[i] &
 1426                              filt->ff_mask6.mask6_src.s6_addr32[i]))
 1427                                 return (0);
 1428         }
 1429         if (fbmask & FIMB6_DADDR) {
 1430                 for (i = 0; i < 4; i++)
 1431                         if (filt->ff_flow6.fi6_dst.s6_addr32[i] !=
 1432                             (pkt->fi6_dst.s6_addr32[i] &
 1433                              filt->ff_mask6.mask6_dst.s6_addr32[i]))
 1434                                 return (0);
 1435         }
 1436         if ((fbmask & FIMB6_TCLASS) &&
 1437             filt->ff_flow6.fi6_tclass !=
 1438             (pkt->fi6_tclass & filt->ff_mask6.mask6_tclass))
 1439                 return (0);
 1440         if ((fbmask & FIMB6_GPI) &&
 1441             filt->ff_flow6.fi6_gpi != pkt->fi6_gpi)
 1442                 return (0);
 1443         /* match */
 1444         return (1);
 1445 }
 1446 #endif /* INET6 */
 1447 
 1448 /*
 1449  *  filter handle:
 1450  *      bit 20-28: index to the filter hash table
 1451  *      bit  0-19: unique id in the hash bucket.
 1452  */
 1453 static u_long
 1454 get_filt_handle(struct acc_classifier *classifier, int i)
 1455 {
 1456         static u_long handle_number = 1;
 1457         u_long  handle;
 1458         struct acc_filter *afp;
 1459 
 1460         while (1) {
 1461                 handle = handle_number++ & 0x000fffff;
 1462 
 1463                 if (LIST_EMPTY(&classifier->acc_filters[i]))
 1464                         break;
 1465 
 1466                 LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain)
 1467                         if ((afp->f_handle & 0x000fffff) == handle)
 1468                                 break;
 1469                 if (afp == NULL)
 1470                         break;
 1471                 /* this handle is already used, try again */
 1472         }
 1473 
 1474         return ((i << 20) | handle);
 1475 }
 1476 
 1477 /* convert filter handle to filter pointer */
 1478 static struct acc_filter *
 1479 filth_to_filtp(struct acc_classifier *classifier, u_long handle)
 1480 {
 1481         struct acc_filter *afp;
 1482         int     i;
 1483 
 1484         i = ACC_GET_HINDEX(handle);
 1485 
 1486         LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain)
 1487                 if (afp->f_handle == handle)
 1488                         return (afp);
 1489 
 1490         return (NULL);
 1491 }
 1492 
 1493 /* create flowinfo bitmask */
 1494 static u_int32_t
 1495 filt2fibmask(struct flow_filter *filt)
 1496 {
 1497         u_int32_t mask = 0;
 1498 #ifdef INET6
 1499         struct flow_filter6 *filt6;
 1500 #endif
 1501 
 1502         switch (filt->ff_flow.fi_family) {
 1503         case AF_INET:
 1504                 if (filt->ff_flow.fi_proto != 0)
 1505                         mask |= FIMB4_PROTO;
 1506                 if (filt->ff_flow.fi_tos != 0)
 1507                         mask |= FIMB4_TOS;
 1508                 if (filt->ff_flow.fi_dst.s_addr != 0)
 1509                         mask |= FIMB4_DADDR;
 1510                 if (filt->ff_flow.fi_src.s_addr != 0)
 1511                         mask |= FIMB4_SADDR;
 1512                 if (filt->ff_flow.fi_sport != 0)
 1513                         mask |= FIMB4_SPORT;
 1514                 if (filt->ff_flow.fi_dport != 0)
 1515                         mask |= FIMB4_DPORT;
 1516                 if (filt->ff_flow.fi_gpi != 0)
 1517                         mask |= FIMB4_GPI;
 1518                 break;
 1519 #ifdef INET6
 1520         case AF_INET6:
 1521                 filt6 = (struct flow_filter6 *)filt;
 1522 
 1523                 if (filt6->ff_flow6.fi6_proto != 0)
 1524                         mask |= FIMB6_PROTO;
 1525                 if (filt6->ff_flow6.fi6_tclass != 0)
 1526                         mask |= FIMB6_TCLASS;
 1527                 if (!IN6_IS_ADDR_UNSPECIFIED(&filt6->ff_flow6.fi6_dst))
 1528                         mask |= FIMB6_DADDR;
 1529                 if (!IN6_IS_ADDR_UNSPECIFIED(&filt6->ff_flow6.fi6_src))
 1530                         mask |= FIMB6_SADDR;
 1531                 if (filt6->ff_flow6.fi6_sport != 0)
 1532                         mask |= FIMB6_SPORT;
 1533                 if (filt6->ff_flow6.fi6_dport != 0)
 1534                         mask |= FIMB6_DPORT;
 1535                 if (filt6->ff_flow6.fi6_gpi != 0)
 1536                         mask |= FIMB6_GPI;
 1537                 if (filt6->ff_flow6.fi6_flowlabel != 0)
 1538                         mask |= FIMB6_FLABEL;
 1539                 break;
 1540 #endif /* INET6 */
 1541         }
 1542         return (mask);
 1543 }
 1544 
 1545 
 1546 /*
 1547  * helper functions to handle IPv4 fragments.
 1548  * currently only in-sequence fragments are handled.
 1549  *      - fragment info is cached in a LRU list.
 1550  *      - when a first fragment is found, cache its flow info.
 1551  *      - when a non-first fragment is found, lookup the cache.
 1552  */
 1553 
 1554 struct ip4_frag {
 1555     TAILQ_ENTRY(ip4_frag) ip4f_chain;
 1556     char    ip4f_valid;
 1557     u_short ip4f_id;
 1558     struct flowinfo_in ip4f_info;
 1559 };
 1560 
 1561 static TAILQ_HEAD(ip4f_list, ip4_frag) ip4f_list; /* IPv4 fragment cache */
 1562 
 1563 #define IP4F_TABSIZE            16      /* IPv4 fragment cache size */
 1564 
 1565 
 1566 static void
 1567 ip4f_cache(struct ip *ip, struct flowinfo_in *fin)
 1568 {
 1569         struct ip4_frag *fp;
 1570 
 1571         if (TAILQ_EMPTY(&ip4f_list)) {
 1572                 /* first time call, allocate fragment cache entries. */
 1573                 if (ip4f_init() < 0)
 1574                         /* allocation failed! */
 1575                         return;
 1576         }
 1577 
 1578         fp = ip4f_alloc();
 1579         fp->ip4f_id = ip->ip_id;
 1580         fp->ip4f_info.fi_proto = ip->ip_p;
 1581         fp->ip4f_info.fi_src.s_addr = ip->ip_src.s_addr;
 1582         fp->ip4f_info.fi_dst.s_addr = ip->ip_dst.s_addr;
 1583 
 1584         /* save port numbers */
 1585         fp->ip4f_info.fi_sport = fin->fi_sport;
 1586         fp->ip4f_info.fi_dport = fin->fi_dport;
 1587         fp->ip4f_info.fi_gpi   = fin->fi_gpi;
 1588 }
 1589 
 1590 static int
 1591 ip4f_lookup(struct ip *ip, struct flowinfo_in *fin)
 1592 {
 1593         struct ip4_frag *fp;
 1594 
 1595         for (fp = TAILQ_FIRST(&ip4f_list); fp != NULL && fp->ip4f_valid;
 1596              fp = TAILQ_NEXT(fp, ip4f_chain))
 1597                 if (ip->ip_id == fp->ip4f_id &&
 1598                     ip->ip_src.s_addr == fp->ip4f_info.fi_src.s_addr &&
 1599                     ip->ip_dst.s_addr == fp->ip4f_info.fi_dst.s_addr &&
 1600                     ip->ip_p == fp->ip4f_info.fi_proto) {
 1601 
 1602                         /* found the matching entry */
 1603                         fin->fi_sport = fp->ip4f_info.fi_sport;
 1604                         fin->fi_dport = fp->ip4f_info.fi_dport;
 1605                         fin->fi_gpi   = fp->ip4f_info.fi_gpi;
 1606 
 1607                         if ((ntohs(ip->ip_off) & IP_MF) == 0)
 1608                                 /* this is the last fragment,
 1609                                    release the entry. */
 1610                                 ip4f_free(fp);
 1611 
 1612                         return (1);
 1613                 }
 1614 
 1615         /* no matching entry found */
 1616         return (0);
 1617 }
 1618 
 1619 static int
 1620 ip4f_init(void)
 1621 {
 1622         struct ip4_frag *fp;
 1623         int i;
 1624 
 1625         TAILQ_INIT(&ip4f_list);
 1626         for (i=0; i<IP4F_TABSIZE; i++) {
 1627                 fp = malloc(sizeof(struct ip4_frag), M_DEVBUF, M_NOWAIT);
 1628                 if (fp == NULL) {
 1629                         printf("ip4f_init: can't alloc %dth entry!\n", i);
 1630                         if (i == 0)
 1631                                 return (-1);
 1632                         return (0);
 1633                 }
 1634                 fp->ip4f_valid = 0;
 1635                 TAILQ_INSERT_TAIL(&ip4f_list, fp, ip4f_chain);
 1636         }
 1637         return (0);
 1638 }
 1639 
 1640 static struct ip4_frag *
 1641 ip4f_alloc(void)
 1642 {
 1643         struct ip4_frag *fp;
 1644 
 1645         /* reclaim an entry at the tail, put it at the head */
 1646         fp = TAILQ_LAST(&ip4f_list, ip4f_list);
 1647         TAILQ_REMOVE(&ip4f_list, fp, ip4f_chain);
 1648         fp->ip4f_valid = 1;
 1649         TAILQ_INSERT_HEAD(&ip4f_list, fp, ip4f_chain);
 1650         return (fp);
 1651 }
 1652 
 1653 static void
 1654 ip4f_free(struct ip4_frag *fp)
 1655 {
 1656         TAILQ_REMOVE(&ip4f_list, fp, ip4f_chain);
 1657         fp->ip4f_valid = 0;
 1658         TAILQ_INSERT_TAIL(&ip4f_list, fp, ip4f_chain);
 1659 }
 1660 
 1661 #endif /* ALTQ3_CLFIER_COMPAT */

Cache object: aef607d7e17a517c950431d52884be85


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.