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.33 2017/03/14 09:03:08 ozaki-r 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.33 2017/03/14 09:03:08 ozaki-r 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 *),
  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 = pserialize_read_enter();
  359         IFNET_READER_FOREACH(ifp) {
  360                 struct psref psref;
  361                 if (!TBR_IS_ENABLED(&ifp->if_snd))
  362                         continue;
  363                 if_acquire(ifp, &psref);
  364                 pserialize_read_exit(s);
  365 
  366                 active++;
  367                 if (!IFQ_IS_EMPTY(&ifp->if_snd) && ifp->if_start != NULL) {
  368                         int _s = splnet();
  369                         if_start_lock(ifp);
  370                         splx(_s);
  371                 }
  372 
  373                 s = pserialize_read_enter();
  374                 if_release(ifp, &psref);
  375         }
  376         pserialize_read_exit(s);
  377 
  378         if (active > 0)
  379                 CALLOUT_RESET(&tbr_callout, 1, tbr_timeout, (void *)0);
  380         else
  381                 tbr_timer = 0;  /* don't need tbr_timer anymore */
  382 }
  383 
  384 /*
  385  * get token bucket regulator profile
  386  */
  387 int
  388 tbr_get(struct ifaltq *ifq, struct tb_profile *profile)
  389 {
  390         struct tb_regulator *tbr;
  391 
  392         if ((tbr = ifq->altq_tbr) == NULL) {
  393                 profile->rate = 0;
  394                 profile->depth = 0;
  395         } else {
  396                 profile->rate =
  397                     (u_int)TBR_UNSCALE(tbr->tbr_rate * 8 * machclk_freq);
  398                 profile->depth = (u_int)TBR_UNSCALE(tbr->tbr_depth);
  399         }
  400         return (0);
  401 }
  402 
  403 #if NPF > 0
  404 /*
  405  * attach a discipline to the interface.  if one already exists, it is
  406  * overridden.
  407  */
  408 int
  409 altq_pfattach(struct pf_altq *a)
  410 {
  411         int error = 0;
  412 
  413         switch (a->scheduler) {
  414         case ALTQT_NONE:
  415                 break;
  416 #ifdef ALTQ_CBQ
  417         case ALTQT_CBQ:
  418                 error = cbq_pfattach(a);
  419                 break;
  420 #endif
  421 #ifdef ALTQ_PRIQ
  422         case ALTQT_PRIQ:
  423                 error = priq_pfattach(a);
  424                 break;
  425 #endif
  426 #ifdef ALTQ_HFSC
  427         case ALTQT_HFSC:
  428                 error = hfsc_pfattach(a);
  429                 break;
  430 #endif
  431         default:
  432                 error = ENXIO;
  433         }
  434 
  435         return (error);
  436 }
  437 
  438 /*
  439  * detach a discipline from the interface.
  440  * it is possible that the discipline was already overridden by another
  441  * discipline.
  442  */
  443 int
  444 altq_pfdetach(struct pf_altq *a)
  445 {
  446         struct ifnet *ifp;
  447         int s, error = 0;
  448 
  449         if ((ifp = ifunit(a->ifname)) == NULL)
  450                 return (EINVAL);
  451 
  452         /* if this discipline is no longer referenced, just return */
  453         if (a->altq_disc == NULL || a->altq_disc != ifp->if_snd.altq_disc)
  454                 return (0);
  455 
  456         s = splnet();
  457         if (ALTQ_IS_ENABLED(&ifp->if_snd))
  458                 error = altq_disable(&ifp->if_snd);
  459         if (error == 0)
  460                 error = altq_detach(&ifp->if_snd);
  461         splx(s);
  462 
  463         return (error);
  464 }
  465 
  466 /*
  467  * add a discipline or a queue
  468  */
  469 int
  470 altq_add(struct pf_altq *a)
  471 {
  472         int error = 0;
  473 
  474         if (a->qname[0] != 0)
  475                 return (altq_add_queue(a));
  476 
  477         if (machclk_freq == 0)
  478                 init_machclk();
  479         if (machclk_freq == 0)
  480                 panic("altq_add: no CPU clock");
  481 
  482         switch (a->scheduler) {
  483 #ifdef ALTQ_CBQ
  484         case ALTQT_CBQ:
  485                 error = cbq_add_altq(a);
  486                 break;
  487 #endif
  488 #ifdef ALTQ_PRIQ
  489         case ALTQT_PRIQ:
  490                 error = priq_add_altq(a);
  491                 break;
  492 #endif
  493 #ifdef ALTQ_HFSC
  494         case ALTQT_HFSC:
  495                 error = hfsc_add_altq(a);
  496                 break;
  497 #endif
  498         default:
  499                 error = ENXIO;
  500         }
  501 
  502         return (error);
  503 }
  504 
  505 /*
  506  * remove a discipline or a queue
  507  */
  508 int
  509 altq_remove(struct pf_altq *a)
  510 {
  511         int error = 0;
  512 
  513         if (a->qname[0] != 0)
  514                 return (altq_remove_queue(a));
  515 
  516         switch (a->scheduler) {
  517 #ifdef ALTQ_CBQ
  518         case ALTQT_CBQ:
  519                 error = cbq_remove_altq(a);
  520                 break;
  521 #endif
  522 #ifdef ALTQ_PRIQ
  523         case ALTQT_PRIQ:
  524                 error = priq_remove_altq(a);
  525                 break;
  526 #endif
  527 #ifdef ALTQ_HFSC
  528         case ALTQT_HFSC:
  529                 error = hfsc_remove_altq(a);
  530                 break;
  531 #endif
  532         default:
  533                 error = ENXIO;
  534         }
  535 
  536         return (error);
  537 }
  538 
  539 /*
  540  * add a queue to the discipline
  541  */
  542 int
  543 altq_add_queue(struct pf_altq *a)
  544 {
  545         int error = 0;
  546 
  547         switch (a->scheduler) {
  548 #ifdef ALTQ_CBQ
  549         case ALTQT_CBQ:
  550                 error = cbq_add_queue(a);
  551                 break;
  552 #endif
  553 #ifdef ALTQ_PRIQ
  554         case ALTQT_PRIQ:
  555                 error = priq_add_queue(a);
  556                 break;
  557 #endif
  558 #ifdef ALTQ_HFSC
  559         case ALTQT_HFSC:
  560                 error = hfsc_add_queue(a);
  561                 break;
  562 #endif
  563         default:
  564                 error = ENXIO;
  565         }
  566 
  567         return (error);
  568 }
  569 
  570 /*
  571  * remove a queue from the discipline
  572  */
  573 int
  574 altq_remove_queue(struct pf_altq *a)
  575 {
  576         int error = 0;
  577 
  578         switch (a->scheduler) {
  579 #ifdef ALTQ_CBQ
  580         case ALTQT_CBQ:
  581                 error = cbq_remove_queue(a);
  582                 break;
  583 #endif
  584 #ifdef ALTQ_PRIQ
  585         case ALTQT_PRIQ:
  586                 error = priq_remove_queue(a);
  587                 break;
  588 #endif
  589 #ifdef ALTQ_HFSC
  590         case ALTQT_HFSC:
  591                 error = hfsc_remove_queue(a);
  592                 break;
  593 #endif
  594         default:
  595                 error = ENXIO;
  596         }
  597 
  598         return (error);
  599 }
  600 
  601 /*
  602  * get queue statistics
  603  */
  604 int
  605 altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
  606 {
  607         int error = 0;
  608 
  609         switch (a->scheduler) {
  610 #ifdef ALTQ_CBQ
  611         case ALTQT_CBQ:
  612                 error = cbq_getqstats(a, ubuf, nbytes);
  613                 break;
  614 #endif
  615 #ifdef ALTQ_PRIQ
  616         case ALTQT_PRIQ:
  617                 error = priq_getqstats(a, ubuf, nbytes);
  618                 break;
  619 #endif
  620 #ifdef ALTQ_HFSC
  621         case ALTQT_HFSC:
  622                 error = hfsc_getqstats(a, ubuf, nbytes);
  623                 break;
  624 #endif
  625         default:
  626                 error = ENXIO;
  627         }
  628 
  629         return (error);
  630 }
  631 #endif /* NPF > 0 */
  632 
  633 /*
  634  * read and write diffserv field in IPv4 or IPv6 header
  635  */
  636 u_int8_t
  637 read_dsfield(struct mbuf *m, struct altq_pktattr *pktattr)
  638 {
  639         struct mbuf *m0;
  640         u_int8_t ds_field = 0;
  641 
  642         if (pktattr == NULL ||
  643             (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6))
  644                 return ((u_int8_t)0);
  645 
  646         /* verify that pattr_hdr is within the mbuf data */
  647         for (m0 = m; m0 != NULL; m0 = m0->m_next)
  648                 if (((char *)pktattr->pattr_hdr >= m0->m_data) &&
  649                     ((char *)pktattr->pattr_hdr < m0->m_data + m0->m_len))
  650                         break;
  651         if (m0 == NULL) {
  652                 /* ick, pattr_hdr is stale */
  653                 pktattr->pattr_af = AF_UNSPEC;
  654 #ifdef ALTQ_DEBUG
  655                 printf("read_dsfield: can't locate header!\n");
  656 #endif
  657                 return ((u_int8_t)0);
  658         }
  659 
  660         if (pktattr->pattr_af == AF_INET) {
  661                 struct ip *ip = (struct ip *)pktattr->pattr_hdr;
  662 
  663                 if (ip->ip_v != 4)
  664                         return ((u_int8_t)0);   /* version mismatch! */
  665                 ds_field = ip->ip_tos;
  666         }
  667 #ifdef INET6
  668         else if (pktattr->pattr_af == AF_INET6) {
  669                 struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
  670                 u_int32_t flowlabel;
  671 
  672                 flowlabel = ntohl(ip6->ip6_flow);
  673                 if ((flowlabel >> 28) != 6)
  674                         return ((u_int8_t)0);   /* version mismatch! */
  675                 ds_field = (flowlabel >> 20) & 0xff;
  676         }
  677 #endif
  678         return (ds_field);
  679 }
  680 
  681 void
  682 write_dsfield(struct mbuf *m, struct altq_pktattr *pktattr, u_int8_t dsfield)
  683 {
  684         struct mbuf *m0;
  685 
  686         if (pktattr == NULL ||
  687             (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6))
  688                 return;
  689 
  690         /* verify that pattr_hdr is within the mbuf data */
  691         for (m0 = m; m0 != NULL; m0 = m0->m_next)
  692                 if (((char *)pktattr->pattr_hdr >= m0->m_data) &&
  693                     ((char *)pktattr->pattr_hdr < m0->m_data + m0->m_len))
  694                         break;
  695         if (m0 == NULL) {
  696                 /* ick, pattr_hdr is stale */
  697                 pktattr->pattr_af = AF_UNSPEC;
  698 #ifdef ALTQ_DEBUG
  699                 printf("write_dsfield: can't locate header!\n");
  700 #endif
  701                 return;
  702         }
  703 
  704         if (pktattr->pattr_af == AF_INET) {
  705                 struct ip *ip = (struct ip *)pktattr->pattr_hdr;
  706                 u_int8_t old;
  707                 int32_t sum;
  708 
  709                 if (ip->ip_v != 4)
  710                         return;         /* version mismatch! */
  711                 old = ip->ip_tos;
  712                 dsfield |= old & 3;     /* leave CU bits */
  713                 if (old == dsfield)
  714                         return;
  715                 ip->ip_tos = dsfield;
  716                 /*
  717                  * update checksum (from RFC1624)
  718                  *         HC' = ~(~HC + ~m + m')
  719                  */
  720                 sum = ~ntohs(ip->ip_sum) & 0xffff;
  721                 sum += 0xff00 + (~old & 0xff) + dsfield;
  722                 sum = (sum >> 16) + (sum & 0xffff);
  723                 sum += (sum >> 16);  /* add carry */
  724 
  725                 ip->ip_sum = htons(~sum & 0xffff);
  726         }
  727 #ifdef INET6
  728         else if (pktattr->pattr_af == AF_INET6) {
  729                 struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
  730                 u_int32_t flowlabel;
  731 
  732                 flowlabel = ntohl(ip6->ip6_flow);
  733                 if ((flowlabel >> 28) != 6)
  734                         return;         /* version mismatch! */
  735                 flowlabel = (flowlabel & 0xf03fffff) | (dsfield << 20);
  736                 ip6->ip6_flow = htonl(flowlabel);
  737         }
  738 #endif
  739         return;
  740 }
  741 
  742 #define BINTIME_SHIFT   2
  743 
  744 u_int32_t machclk_freq = 0;
  745 u_int32_t machclk_per_tick = 0;
  746 
  747 void
  748 init_machclk(void)
  749 {
  750 
  751         callout_init(&tbr_callout, 0);
  752 
  753         /*
  754          * Always emulate 1GiHz counter using bintime(9)
  755          * since it has enough resolution via timecounter(9).
  756          * Using machine dependent cpu_counter() is not MP safe
  757          * and it won't work even on UP with Speedstep etc.
  758          */
  759         machclk_freq = 1024 * 1024 * 1024;      /* 2^30 to emulate ~1GHz */
  760         machclk_per_tick = machclk_freq / hz;
  761 #ifdef ALTQ_DEBUG
  762         printf("altq: emulate %uHz CPU clock\n", machclk_freq);
  763 #endif
  764 }
  765 
  766 u_int64_t
  767 read_machclk(void)
  768 {
  769         struct bintime bt;
  770         u_int64_t val;
  771 
  772         binuptime(&bt);
  773         val = (((u_int64_t)bt.sec << 32) + (bt.frac >> 32)) >> BINTIME_SHIFT;
  774         return (val);
  775 }
  776 
  777 #ifdef ALTQ3_CLFIER_COMPAT
  778 
  779 #ifndef IPPROTO_ESP
  780 #define IPPROTO_ESP     50              /* encapsulating security payload */
  781 #endif
  782 #ifndef IPPROTO_AH
  783 #define IPPROTO_AH      51              /* authentication header */
  784 #endif
  785 
  786 /*
  787  * extract flow information from a given packet.
  788  * filt_mask shows flowinfo fields required.
  789  * we assume the ip header is in one mbuf, and addresses and ports are
  790  * in network byte order.
  791  */
  792 int
  793 altq_extractflow(struct mbuf *m, int af, struct flowinfo *flow,
  794     u_int32_t filt_bmask)
  795 {
  796 
  797         switch (af) {
  798         case PF_INET: {
  799                 struct flowinfo_in *fin;
  800                 struct ip *ip;
  801 
  802                 ip = mtod(m, struct ip *);
  803 
  804                 if (ip->ip_v != 4)
  805                         break;
  806 
  807                 fin = (struct flowinfo_in *)flow;
  808                 fin->fi_len = sizeof(struct flowinfo_in);
  809                 fin->fi_family = AF_INET;
  810 
  811                 fin->fi_proto = ip->ip_p;
  812                 fin->fi_tos = ip->ip_tos;
  813 
  814                 fin->fi_src.s_addr = ip->ip_src.s_addr;
  815                 fin->fi_dst.s_addr = ip->ip_dst.s_addr;
  816 
  817                 if (filt_bmask & FIMB4_PORTS)
  818                         /* if port info is required, extract port numbers */
  819                         extract_ports4(m, ip, fin);
  820                 else {
  821                         fin->fi_sport = 0;
  822                         fin->fi_dport = 0;
  823                         fin->fi_gpi = 0;
  824                 }
  825                 return (1);
  826         }
  827 
  828 #ifdef INET6
  829         case PF_INET6: {
  830                 struct flowinfo_in6 *fin6;
  831                 struct ip6_hdr *ip6;
  832 
  833                 ip6 = mtod(m, struct ip6_hdr *);
  834                 /* should we check the ip version? */
  835 
  836                 fin6 = (struct flowinfo_in6 *)flow;
  837                 fin6->fi6_len = sizeof(struct flowinfo_in6);
  838                 fin6->fi6_family = AF_INET6;
  839 
  840                 fin6->fi6_proto = ip6->ip6_nxt;
  841                 fin6->fi6_tclass   = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
  842 
  843                 fin6->fi6_flowlabel = ip6->ip6_flow & htonl(0x000fffff);
  844                 fin6->fi6_src = ip6->ip6_src;
  845                 fin6->fi6_dst = ip6->ip6_dst;
  846 
  847                 if ((filt_bmask & FIMB6_PORTS) ||
  848                     ((filt_bmask & FIMB6_PROTO)
  849                      && ip6->ip6_nxt > IPPROTO_IPV6))
  850                         /*
  851                          * if port info is required, or proto is required
  852                          * but there are option headers, extract port
  853                          * and protocol numbers.
  854                          */
  855                         extract_ports6(m, ip6, fin6);
  856                 else {
  857                         fin6->fi6_sport = 0;
  858                         fin6->fi6_dport = 0;
  859                         fin6->fi6_gpi = 0;
  860                 }
  861                 return (1);
  862         }
  863 #endif /* INET6 */
  864 
  865         default:
  866                 break;
  867         }
  868 
  869         /* failed */
  870         flow->fi_len = sizeof(struct flowinfo);
  871         flow->fi_family = AF_UNSPEC;
  872         return (0);
  873 }
  874 
  875 /*
  876  * helper routine to extract port numbers
  877  */
  878 /* structure for ipsec and ipv6 option header template */
  879 struct _opt6 {
  880         u_int8_t        opt6_nxt;       /* next header */
  881         u_int8_t        opt6_hlen;      /* header extension length */
  882         u_int16_t       _pad;
  883         u_int32_t       ah_spi;         /* security parameter index
  884                                            for authentication header */
  885 };
  886 
  887 /*
  888  * extract port numbers from a ipv4 packet.
  889  */
  890 static int
  891 extract_ports4(struct mbuf *m, struct ip *ip, struct flowinfo_in *fin)
  892 {
  893         struct mbuf *m0;
  894         u_short ip_off;
  895         u_int8_t proto;
  896         int     off;
  897 
  898         fin->fi_sport = 0;
  899         fin->fi_dport = 0;
  900         fin->fi_gpi = 0;
  901 
  902         ip_off = ntohs(ip->ip_off);
  903         /* if it is a fragment, try cached fragment info */
  904         if (ip_off & IP_OFFMASK) {
  905                 ip4f_lookup(ip, fin);
  906                 return (1);
  907         }
  908 
  909         /* locate the mbuf containing the protocol header */
  910         for (m0 = m; m0 != NULL; m0 = m0->m_next)
  911                 if (((char *)ip >= m0->m_data) &&
  912                     ((char *)ip < m0->m_data + m0->m_len))
  913                         break;
  914         if (m0 == NULL) {
  915 #ifdef ALTQ_DEBUG
  916                 printf("extract_ports4: can't locate header! ip=%p\n", ip);
  917 #endif
  918                 return (0);
  919         }
  920         off = ((char *)ip - m0->m_data) + (ip->ip_hl << 2);
  921         proto = ip->ip_p;
  922 
  923 #ifdef ALTQ_IPSEC
  924  again:
  925 #endif
  926         while (off >= m0->m_len) {
  927                 off -= m0->m_len;
  928                 m0 = m0->m_next;
  929                 if (m0 == NULL)
  930                         return (0);  /* bogus ip_hl! */
  931         }
  932         if (m0->m_len < off + 4)
  933                 return (0);
  934 
  935         switch (proto) {
  936         case IPPROTO_TCP:
  937         case IPPROTO_UDP: {
  938                 struct udphdr *udp;
  939 
  940                 udp = (struct udphdr *)(mtod(m0, char *) + off);
  941                 fin->fi_sport = udp->uh_sport;
  942                 fin->fi_dport = udp->uh_dport;
  943                 fin->fi_proto = proto;
  944                 }
  945                 break;
  946 
  947 #ifdef ALTQ_IPSEC
  948         case IPPROTO_ESP:
  949                 if (fin->fi_gpi == 0){
  950                         u_int32_t *gpi;
  951 
  952                         gpi = (u_int32_t *)(mtod(m0, char *) + off);
  953                         fin->fi_gpi   = *gpi;
  954                 }
  955                 fin->fi_proto = proto;
  956                 break;
  957 
  958         case IPPROTO_AH: {
  959                         /* get next header and header length */
  960                         struct _opt6 *opt6;
  961 
  962                         opt6 = (struct _opt6 *)(mtod(m0, char *) + off);
  963                         proto = opt6->opt6_nxt;
  964                         off += 8 + (opt6->opt6_hlen * 4);
  965                         if (fin->fi_gpi == 0 && m0->m_len >= off + 8)
  966                                 fin->fi_gpi = opt6->ah_spi;
  967                 }
  968                 /* goto the next header */
  969                 goto again;
  970 #endif  /* ALTQ_IPSEC */
  971 
  972         default:
  973                 fin->fi_proto = proto;
  974                 return (0);
  975         }
  976 
  977         /* if this is a first fragment, cache it. */
  978         if (ip_off & IP_MF)
  979                 ip4f_cache(ip, fin);
  980 
  981         return (1);
  982 }
  983 
  984 #ifdef INET6
  985 static int
  986 extract_ports6(struct mbuf *m, struct ip6_hdr *ip6, struct flowinfo_in6 *fin6)
  987 {
  988         struct mbuf *m0;
  989         int     off;
  990         u_int8_t proto;
  991 
  992         fin6->fi6_gpi   = 0;
  993         fin6->fi6_sport = 0;
  994         fin6->fi6_dport = 0;
  995 
  996         /* locate the mbuf containing the protocol header */
  997         for (m0 = m; m0 != NULL; m0 = m0->m_next)
  998                 if (((char *)ip6 >= m0->m_data) &&
  999                     ((char *)ip6 < m0->m_data + m0->m_len))
 1000                         break;
 1001         if (m0 == NULL) {
 1002 #ifdef ALTQ_DEBUG
 1003                 printf("extract_ports6: can't locate header! ip6=%p\n", ip6);
 1004 #endif
 1005                 return (0);
 1006         }
 1007         off = ((char *)ip6 - m0->m_data) + sizeof(struct ip6_hdr);
 1008 
 1009         proto = ip6->ip6_nxt;
 1010         do {
 1011                 while (off >= m0->m_len) {
 1012                         off -= m0->m_len;
 1013                         m0 = m0->m_next;
 1014                         if (m0 == NULL)
 1015                                 return (0);
 1016                 }
 1017                 if (m0->m_len < off + 4)
 1018                         return (0);
 1019 
 1020                 switch (proto) {
 1021                 case IPPROTO_TCP:
 1022                 case IPPROTO_UDP: {
 1023                         struct udphdr *udp;
 1024 
 1025                         udp = (struct udphdr *)(mtod(m0, char *) + off);
 1026                         fin6->fi6_sport = udp->uh_sport;
 1027                         fin6->fi6_dport = udp->uh_dport;
 1028                         fin6->fi6_proto = proto;
 1029                         }
 1030                         return (1);
 1031 
 1032                 case IPPROTO_ESP:
 1033                         if (fin6->fi6_gpi == 0) {
 1034                                 u_int32_t *gpi;
 1035 
 1036                                 gpi = (u_int32_t *)(mtod(m0, char *) + off);
 1037                                 fin6->fi6_gpi   = *gpi;
 1038                         }
 1039                         fin6->fi6_proto = proto;
 1040                         return (1);
 1041 
 1042                 case IPPROTO_AH: {
 1043                         /* get next header and header length */
 1044                         struct _opt6 *opt6;
 1045 
 1046                         opt6 = (struct _opt6 *)(mtod(m0, char *) + off);
 1047                         if (fin6->fi6_gpi == 0 && m0->m_len >= off + 8)
 1048                                 fin6->fi6_gpi = opt6->ah_spi;
 1049                         proto = opt6->opt6_nxt;
 1050                         off += 8 + (opt6->opt6_hlen * 4);
 1051                         /* goto the next header */
 1052                         break;
 1053                         }
 1054 
 1055                 case IPPROTO_HOPOPTS:
 1056                 case IPPROTO_ROUTING:
 1057                 case IPPROTO_DSTOPTS: {
 1058                         /* get next header and header length */
 1059                         struct _opt6 *opt6;
 1060 
 1061                         opt6 = (struct _opt6 *)(mtod(m0, char *) + off);
 1062                         proto = opt6->opt6_nxt;
 1063                         off += (opt6->opt6_hlen + 1) * 8;
 1064                         /* goto the next header */
 1065                         break;
 1066                         }
 1067 
 1068                 case IPPROTO_FRAGMENT:
 1069                         /* ipv6 fragmentations are not supported yet */
 1070                 default:
 1071                         fin6->fi6_proto = proto;
 1072                         return (0);
 1073                 }
 1074         } while (1);
 1075         /*NOTREACHED*/
 1076 }
 1077 #endif /* INET6 */
 1078 
 1079 /*
 1080  * altq common classifier
 1081  */
 1082 int
 1083 acc_add_filter(struct acc_classifier *classifier, struct flow_filter *filter,
 1084     void *class, u_long *phandle)
 1085 {
 1086         struct acc_filter *afp, *prev, *tmp;
 1087         int     i, s;
 1088 
 1089 #ifdef INET6
 1090         if (filter->ff_flow.fi_family != AF_INET &&
 1091             filter->ff_flow.fi_family != AF_INET6)
 1092                 return (EINVAL);
 1093 #else
 1094         if (filter->ff_flow.fi_family != AF_INET)
 1095                 return (EINVAL);
 1096 #endif
 1097 
 1098         afp = malloc(sizeof(struct acc_filter), M_DEVBUF, M_WAITOK|M_ZERO);
 1099         if (afp == NULL)
 1100                 return (ENOMEM);
 1101 
 1102         afp->f_filter = *filter;
 1103         afp->f_class = class;
 1104 
 1105         i = ACC_WILDCARD_INDEX;
 1106         if (filter->ff_flow.fi_family == AF_INET) {
 1107                 struct flow_filter *filter4 = &afp->f_filter;
 1108 
 1109                 /*
 1110                  * if address is 0, it's a wildcard.  if address mask
 1111                  * isn't set, use full mask.
 1112                  */
 1113                 if (filter4->ff_flow.fi_dst.s_addr == 0)
 1114                         filter4->ff_mask.mask_dst.s_addr = 0;
 1115                 else if (filter4->ff_mask.mask_dst.s_addr == 0)
 1116                         filter4->ff_mask.mask_dst.s_addr = 0xffffffff;
 1117                 if (filter4->ff_flow.fi_src.s_addr == 0)
 1118                         filter4->ff_mask.mask_src.s_addr = 0;
 1119                 else if (filter4->ff_mask.mask_src.s_addr == 0)
 1120                         filter4->ff_mask.mask_src.s_addr = 0xffffffff;
 1121 
 1122                 /* clear extra bits in addresses  */
 1123                    filter4->ff_flow.fi_dst.s_addr &=
 1124                        filter4->ff_mask.mask_dst.s_addr;
 1125                    filter4->ff_flow.fi_src.s_addr &=
 1126                        filter4->ff_mask.mask_src.s_addr;
 1127 
 1128                 /*
 1129                  * if dst address is a wildcard, use hash-entry
 1130                  * ACC_WILDCARD_INDEX.
 1131                  */
 1132                 if (filter4->ff_mask.mask_dst.s_addr != 0xffffffff)
 1133                         i = ACC_WILDCARD_INDEX;
 1134                 else
 1135                         i = ACC_GET_HASH_INDEX(filter4->ff_flow.fi_dst.s_addr);
 1136         }
 1137 #ifdef INET6
 1138         else if (filter->ff_flow.fi_family == AF_INET6) {
 1139                 struct flow_filter6 *filter6 =
 1140                         (struct flow_filter6 *)&afp->f_filter;
 1141 #ifndef IN6MASK0 /* taken from kame ipv6 */
 1142 #define IN6MASK0        {{{ 0, 0, 0, 0 }}}
 1143 #define IN6MASK128      {{{ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }}}
 1144                 const struct in6_addr in6mask0 = IN6MASK0;
 1145                 const struct in6_addr in6mask128 = IN6MASK128;
 1146 #endif
 1147 
 1148                 if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_flow6.fi6_dst))
 1149                         filter6->ff_mask6.mask6_dst = in6mask0;
 1150                 else if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_mask6.mask6_dst))
 1151                         filter6->ff_mask6.mask6_dst = in6mask128;
 1152                 if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_flow6.fi6_src))
 1153                         filter6->ff_mask6.mask6_src = in6mask0;
 1154                 else if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_mask6.mask6_src))
 1155                         filter6->ff_mask6.mask6_src = in6mask128;
 1156 
 1157                 /* clear extra bits in addresses  */
 1158                 for (i = 0; i < 16; i++)
 1159                         filter6->ff_flow6.fi6_dst.s6_addr[i] &=
 1160                             filter6->ff_mask6.mask6_dst.s6_addr[i];
 1161                 for (i = 0; i < 16; i++)
 1162                         filter6->ff_flow6.fi6_src.s6_addr[i] &=
 1163                             filter6->ff_mask6.mask6_src.s6_addr[i];
 1164 
 1165                 if (filter6->ff_flow6.fi6_flowlabel == 0)
 1166                         i = ACC_WILDCARD_INDEX;
 1167                 else
 1168                         i = ACC_GET_HASH_INDEX(filter6->ff_flow6.fi6_flowlabel);
 1169         }
 1170 #endif /* INET6 */
 1171 
 1172         afp->f_handle = get_filt_handle(classifier, i);
 1173 
 1174         /* update filter bitmask */
 1175         afp->f_fbmask = filt2fibmask(filter);
 1176         classifier->acc_fbmask |= afp->f_fbmask;
 1177 
 1178         /*
 1179          * add this filter to the filter list.
 1180          * filters are ordered from the highest rule number.
 1181          */
 1182         s = splnet();
 1183         prev = NULL;
 1184         LIST_FOREACH(tmp, &classifier->acc_filters[i], f_chain) {
 1185                 if (tmp->f_filter.ff_ruleno > afp->f_filter.ff_ruleno)
 1186                         prev = tmp;
 1187                 else
 1188                         break;
 1189         }
 1190         if (prev == NULL)
 1191                 LIST_INSERT_HEAD(&classifier->acc_filters[i], afp, f_chain);
 1192         else
 1193                 LIST_INSERT_AFTER(prev, afp, f_chain);
 1194         splx(s);
 1195 
 1196         *phandle = afp->f_handle;
 1197         return (0);
 1198 }
 1199 
 1200 int
 1201 acc_delete_filter(struct acc_classifier *classifier, u_long handle)
 1202 {
 1203         struct acc_filter *afp;
 1204         int     s;
 1205 
 1206         if ((afp = filth_to_filtp(classifier, handle)) == NULL)
 1207                 return (EINVAL);
 1208 
 1209         s = splnet();
 1210         LIST_REMOVE(afp, f_chain);
 1211         splx(s);
 1212 
 1213         free(afp, M_DEVBUF);
 1214 
 1215         /* todo: update filt_bmask */
 1216 
 1217         return (0);
 1218 }
 1219 
 1220 /*
 1221  * delete filters referencing to the specified class.
 1222  * if the all flag is not 0, delete all the filters.
 1223  */
 1224 int
 1225 acc_discard_filters(struct acc_classifier *classifier, void *class, int all)
 1226 {
 1227         struct acc_filter *afp;
 1228         int     i, s;
 1229 
 1230         s = splnet();
 1231         for (i = 0; i < ACC_FILTER_TABLESIZE; i++) {
 1232                 do {
 1233                         LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain)
 1234                                 if (all || afp->f_class == class) {
 1235                                         LIST_REMOVE(afp, f_chain);
 1236                                         free(afp, M_DEVBUF);
 1237                                         /* start again from the head */
 1238                                         break;
 1239                                 }
 1240                 } while (afp != NULL);
 1241         }
 1242         splx(s);
 1243 
 1244         if (all)
 1245                 classifier->acc_fbmask = 0;
 1246 
 1247         return (0);
 1248 }
 1249 
 1250 void *
 1251 acc_classify(void *clfier, struct mbuf *m, int af)
 1252 {
 1253         struct acc_classifier *classifier;
 1254         struct flowinfo flow;
 1255         struct acc_filter *afp;
 1256         int     i;
 1257 
 1258         classifier = (struct acc_classifier *)clfier;
 1259         altq_extractflow(m, af, &flow, classifier->acc_fbmask);
 1260 
 1261         if (flow.fi_family == AF_INET) {
 1262                 struct flowinfo_in *fp = (struct flowinfo_in *)&flow;
 1263 
 1264                 if ((classifier->acc_fbmask & FIMB4_ALL) == FIMB4_TOS) {
 1265                         /* only tos is used */
 1266                         LIST_FOREACH(afp,
 1267                                  &classifier->acc_filters[ACC_WILDCARD_INDEX],
 1268                                  f_chain)
 1269                                 if (apply_tosfilter4(afp->f_fbmask,
 1270                                                      &afp->f_filter, fp))
 1271                                         /* filter matched */
 1272                                         return (afp->f_class);
 1273                 } else if ((classifier->acc_fbmask &
 1274                         (~(FIMB4_PROTO|FIMB4_SPORT|FIMB4_DPORT) & FIMB4_ALL))
 1275                     == 0) {
 1276                         /* only proto and ports are used */
 1277                         LIST_FOREACH(afp,
 1278                                  &classifier->acc_filters[ACC_WILDCARD_INDEX],
 1279                                  f_chain)
 1280                                 if (apply_ppfilter4(afp->f_fbmask,
 1281                                                     &afp->f_filter, fp))
 1282                                         /* filter matched */
 1283                                         return (afp->f_class);
 1284                 } else {
 1285                         /* get the filter hash entry from its dest address */
 1286                         i = ACC_GET_HASH_INDEX(fp->fi_dst.s_addr);
 1287                         do {
 1288                                 /*
 1289                                  * go through this loop twice.  first for dst
 1290                                  * hash, second for wildcards.
 1291                                  */
 1292                                 LIST_FOREACH(afp, &classifier->acc_filters[i],
 1293                                              f_chain)
 1294                                         if (apply_filter4(afp->f_fbmask,
 1295                                                           &afp->f_filter, fp))
 1296                                                 /* filter matched */
 1297                                                 return (afp->f_class);
 1298 
 1299                                 /*
 1300                                  * check again for filters with a dst addr
 1301                                  * wildcard.
 1302                                  * (daddr == 0 || dmask != 0xffffffff).
 1303                                  */
 1304                                 if (i != ACC_WILDCARD_INDEX)
 1305                                         i = ACC_WILDCARD_INDEX;
 1306                                 else
 1307                                         break;
 1308                         } while (1);
 1309                 }
 1310         }
 1311 #ifdef INET6
 1312         else if (flow.fi_family == AF_INET6) {
 1313                 struct flowinfo_in6 *fp6 = (struct flowinfo_in6 *)&flow;
 1314 
 1315                 /* get the filter hash entry from its flow ID */
 1316                 if (fp6->fi6_flowlabel != 0)
 1317                         i = ACC_GET_HASH_INDEX(fp6->fi6_flowlabel);
 1318                 else
 1319                         /* flowlable can be zero */
 1320                         i = ACC_WILDCARD_INDEX;
 1321 
 1322                 /* go through this loop twice.  first for flow hash, second
 1323                    for wildcards. */
 1324                 do {
 1325                         LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain)
 1326                                 if (apply_filter6(afp->f_fbmask,
 1327                                         (struct flow_filter6 *)&afp->f_filter,
 1328                                         fp6))
 1329                                         /* filter matched */
 1330                                         return (afp->f_class);
 1331 
 1332                         /*
 1333                          * check again for filters with a wildcard.
 1334                          */
 1335                         if (i != ACC_WILDCARD_INDEX)
 1336                                 i = ACC_WILDCARD_INDEX;
 1337                         else
 1338                                 break;
 1339                 } while (1);
 1340         }
 1341 #endif /* INET6 */
 1342 
 1343         /* no filter matched */
 1344         return (NULL);
 1345 }
 1346 
 1347 static int
 1348 apply_filter4(u_int32_t fbmask, struct flow_filter *filt,
 1349     struct flowinfo_in *pkt)
 1350 {
 1351         if (filt->ff_flow.fi_family != AF_INET)
 1352                 return (0);
 1353         if ((fbmask & FIMB4_SPORT) && filt->ff_flow.fi_sport != pkt->fi_sport)
 1354                 return (0);
 1355         if ((fbmask & FIMB4_DPORT) && filt->ff_flow.fi_dport != pkt->fi_dport)
 1356                 return (0);
 1357         if ((fbmask & FIMB4_DADDR) &&
 1358             filt->ff_flow.fi_dst.s_addr !=
 1359             (pkt->fi_dst.s_addr & filt->ff_mask.mask_dst.s_addr))
 1360                 return (0);
 1361         if ((fbmask & FIMB4_SADDR) &&
 1362             filt->ff_flow.fi_src.s_addr !=
 1363             (pkt->fi_src.s_addr & filt->ff_mask.mask_src.s_addr))
 1364                 return (0);
 1365         if ((fbmask & FIMB4_PROTO) && filt->ff_flow.fi_proto != pkt->fi_proto)
 1366                 return (0);
 1367         if ((fbmask & FIMB4_TOS) && filt->ff_flow.fi_tos !=
 1368             (pkt->fi_tos & filt->ff_mask.mask_tos))
 1369                 return (0);
 1370         if ((fbmask & FIMB4_GPI) && filt->ff_flow.fi_gpi != (pkt->fi_gpi))
 1371                 return (0);
 1372         /* match */
 1373         return (1);
 1374 }
 1375 
 1376 /*
 1377  * filter matching function optimized for a common case that checks
 1378  * only protocol and port numbers
 1379  */
 1380 static int
 1381 apply_ppfilter4(u_int32_t fbmask, struct flow_filter *filt,
 1382     struct flowinfo_in *pkt)
 1383 {
 1384         if (filt->ff_flow.fi_family != AF_INET)
 1385                 return (0);
 1386         if ((fbmask & FIMB4_SPORT) && filt->ff_flow.fi_sport != pkt->fi_sport)
 1387                 return (0);
 1388         if ((fbmask & FIMB4_DPORT) && filt->ff_flow.fi_dport != pkt->fi_dport)
 1389                 return (0);
 1390         if ((fbmask & FIMB4_PROTO) && filt->ff_flow.fi_proto != pkt->fi_proto)
 1391                 return (0);
 1392         /* match */
 1393         return (1);
 1394 }
 1395 
 1396 /*
 1397  * filter matching function only for tos field.
 1398  */
 1399 static int
 1400 apply_tosfilter4(u_int32_t fbmask, struct flow_filter *filt,
 1401     struct flowinfo_in *pkt)
 1402 {
 1403         if (filt->ff_flow.fi_family != AF_INET)
 1404                 return (0);
 1405         if ((fbmask & FIMB4_TOS) && filt->ff_flow.fi_tos !=
 1406             (pkt->fi_tos & filt->ff_mask.mask_tos))
 1407                 return (0);
 1408         /* match */
 1409         return (1);
 1410 }
 1411 
 1412 #ifdef INET6
 1413 static int
 1414 apply_filter6(u_int32_t fbmask, struct flow_filter6 *filt,
 1415     struct flowinfo_in6 *pkt)
 1416 {
 1417         int i;
 1418 
 1419         if (filt->ff_flow6.fi6_family != AF_INET6)
 1420                 return (0);
 1421         if ((fbmask & FIMB6_FLABEL) &&
 1422             filt->ff_flow6.fi6_flowlabel != pkt->fi6_flowlabel)
 1423                 return (0);
 1424         if ((fbmask & FIMB6_PROTO) &&
 1425             filt->ff_flow6.fi6_proto != pkt->fi6_proto)
 1426                 return (0);
 1427         if ((fbmask & FIMB6_SPORT) &&
 1428             filt->ff_flow6.fi6_sport != pkt->fi6_sport)
 1429                 return (0);
 1430         if ((fbmask & FIMB6_DPORT) &&
 1431             filt->ff_flow6.fi6_dport != pkt->fi6_dport)
 1432                 return (0);
 1433         if (fbmask & FIMB6_SADDR) {
 1434                 for (i = 0; i < 4; i++)
 1435                         if (filt->ff_flow6.fi6_src.s6_addr32[i] !=
 1436                             (pkt->fi6_src.s6_addr32[i] &
 1437                              filt->ff_mask6.mask6_src.s6_addr32[i]))
 1438                                 return (0);
 1439         }
 1440         if (fbmask & FIMB6_DADDR) {
 1441                 for (i = 0; i < 4; i++)
 1442                         if (filt->ff_flow6.fi6_dst.s6_addr32[i] !=
 1443                             (pkt->fi6_dst.s6_addr32[i] &
 1444                              filt->ff_mask6.mask6_dst.s6_addr32[i]))
 1445                                 return (0);
 1446         }
 1447         if ((fbmask & FIMB6_TCLASS) &&
 1448             filt->ff_flow6.fi6_tclass !=
 1449             (pkt->fi6_tclass & filt->ff_mask6.mask6_tclass))
 1450                 return (0);
 1451         if ((fbmask & FIMB6_GPI) &&
 1452             filt->ff_flow6.fi6_gpi != pkt->fi6_gpi)
 1453                 return (0);
 1454         /* match */
 1455         return (1);
 1456 }
 1457 #endif /* INET6 */
 1458 
 1459 /*
 1460  *  filter handle:
 1461  *      bit 20-28: index to the filter hash table
 1462  *      bit  0-19: unique id in the hash bucket.
 1463  */
 1464 static u_long
 1465 get_filt_handle(struct acc_classifier *classifier, int i)
 1466 {
 1467         static u_long handle_number = 1;
 1468         u_long  handle;
 1469         struct acc_filter *afp;
 1470 
 1471         while (1) {
 1472                 handle = handle_number++ & 0x000fffff;
 1473 
 1474                 if (LIST_EMPTY(&classifier->acc_filters[i]))
 1475                         break;
 1476 
 1477                 LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain)
 1478                         if ((afp->f_handle & 0x000fffff) == handle)
 1479                                 break;
 1480                 if (afp == NULL)
 1481                         break;
 1482                 /* this handle is already used, try again */
 1483         }
 1484 
 1485         return ((i << 20) | handle);
 1486 }
 1487 
 1488 /* convert filter handle to filter pointer */
 1489 static struct acc_filter *
 1490 filth_to_filtp(struct acc_classifier *classifier, u_long handle)
 1491 {
 1492         struct acc_filter *afp;
 1493         int     i;
 1494 
 1495         i = ACC_GET_HINDEX(handle);
 1496 
 1497         LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain)
 1498                 if (afp->f_handle == handle)
 1499                         return (afp);
 1500 
 1501         return (NULL);
 1502 }
 1503 
 1504 /* create flowinfo bitmask */
 1505 static u_int32_t
 1506 filt2fibmask(struct flow_filter *filt)
 1507 {
 1508         u_int32_t mask = 0;
 1509 #ifdef INET6
 1510         struct flow_filter6 *filt6;
 1511 #endif
 1512 
 1513         switch (filt->ff_flow.fi_family) {
 1514         case AF_INET:
 1515                 if (filt->ff_flow.fi_proto != 0)
 1516                         mask |= FIMB4_PROTO;
 1517                 if (filt->ff_flow.fi_tos != 0)
 1518                         mask |= FIMB4_TOS;
 1519                 if (filt->ff_flow.fi_dst.s_addr != 0)
 1520                         mask |= FIMB4_DADDR;
 1521                 if (filt->ff_flow.fi_src.s_addr != 0)
 1522                         mask |= FIMB4_SADDR;
 1523                 if (filt->ff_flow.fi_sport != 0)
 1524                         mask |= FIMB4_SPORT;
 1525                 if (filt->ff_flow.fi_dport != 0)
 1526                         mask |= FIMB4_DPORT;
 1527                 if (filt->ff_flow.fi_gpi != 0)
 1528                         mask |= FIMB4_GPI;
 1529                 break;
 1530 #ifdef INET6
 1531         case AF_INET6:
 1532                 filt6 = (struct flow_filter6 *)filt;
 1533 
 1534                 if (filt6->ff_flow6.fi6_proto != 0)
 1535                         mask |= FIMB6_PROTO;
 1536                 if (filt6->ff_flow6.fi6_tclass != 0)
 1537                         mask |= FIMB6_TCLASS;
 1538                 if (!IN6_IS_ADDR_UNSPECIFIED(&filt6->ff_flow6.fi6_dst))
 1539                         mask |= FIMB6_DADDR;
 1540                 if (!IN6_IS_ADDR_UNSPECIFIED(&filt6->ff_flow6.fi6_src))
 1541                         mask |= FIMB6_SADDR;
 1542                 if (filt6->ff_flow6.fi6_sport != 0)
 1543                         mask |= FIMB6_SPORT;
 1544                 if (filt6->ff_flow6.fi6_dport != 0)
 1545                         mask |= FIMB6_DPORT;
 1546                 if (filt6->ff_flow6.fi6_gpi != 0)
 1547                         mask |= FIMB6_GPI;
 1548                 if (filt6->ff_flow6.fi6_flowlabel != 0)
 1549                         mask |= FIMB6_FLABEL;
 1550                 break;
 1551 #endif /* INET6 */
 1552         }
 1553         return (mask);
 1554 }
 1555 
 1556 
 1557 /*
 1558  * helper functions to handle IPv4 fragments.
 1559  * currently only in-sequence fragments are handled.
 1560  *      - fragment info is cached in a LRU list.
 1561  *      - when a first fragment is found, cache its flow info.
 1562  *      - when a non-first fragment is found, lookup the cache.
 1563  */
 1564 
 1565 struct ip4_frag {
 1566     TAILQ_ENTRY(ip4_frag) ip4f_chain;
 1567     char    ip4f_valid;
 1568     u_short ip4f_id;
 1569     struct flowinfo_in ip4f_info;
 1570 };
 1571 
 1572 static TAILQ_HEAD(ip4f_list, ip4_frag) ip4f_list; /* IPv4 fragment cache */
 1573 
 1574 #define IP4F_TABSIZE            16      /* IPv4 fragment cache size */
 1575 
 1576 
 1577 static void
 1578 ip4f_cache(struct ip *ip, struct flowinfo_in *fin)
 1579 {
 1580         struct ip4_frag *fp;
 1581 
 1582         if (TAILQ_EMPTY(&ip4f_list)) {
 1583                 /* first time call, allocate fragment cache entries. */
 1584                 if (ip4f_init() < 0)
 1585                         /* allocation failed! */
 1586                         return;
 1587         }
 1588 
 1589         fp = ip4f_alloc();
 1590         fp->ip4f_id = ip->ip_id;
 1591         fp->ip4f_info.fi_proto = ip->ip_p;
 1592         fp->ip4f_info.fi_src.s_addr = ip->ip_src.s_addr;
 1593         fp->ip4f_info.fi_dst.s_addr = ip->ip_dst.s_addr;
 1594 
 1595         /* save port numbers */
 1596         fp->ip4f_info.fi_sport = fin->fi_sport;
 1597         fp->ip4f_info.fi_dport = fin->fi_dport;
 1598         fp->ip4f_info.fi_gpi   = fin->fi_gpi;
 1599 }
 1600 
 1601 static int
 1602 ip4f_lookup(struct ip *ip, struct flowinfo_in *fin)
 1603 {
 1604         struct ip4_frag *fp;
 1605 
 1606         for (fp = TAILQ_FIRST(&ip4f_list); fp != NULL && fp->ip4f_valid;
 1607              fp = TAILQ_NEXT(fp, ip4f_chain))
 1608                 if (ip->ip_id == fp->ip4f_id &&
 1609                     ip->ip_src.s_addr == fp->ip4f_info.fi_src.s_addr &&
 1610                     ip->ip_dst.s_addr == fp->ip4f_info.fi_dst.s_addr &&
 1611                     ip->ip_p == fp->ip4f_info.fi_proto) {
 1612 
 1613                         /* found the matching entry */
 1614                         fin->fi_sport = fp->ip4f_info.fi_sport;
 1615                         fin->fi_dport = fp->ip4f_info.fi_dport;
 1616                         fin->fi_gpi   = fp->ip4f_info.fi_gpi;
 1617 
 1618                         if ((ntohs(ip->ip_off) & IP_MF) == 0)
 1619                                 /* this is the last fragment,
 1620                                    release the entry. */
 1621                                 ip4f_free(fp);
 1622 
 1623                         return (1);
 1624                 }
 1625 
 1626         /* no matching entry found */
 1627         return (0);
 1628 }
 1629 
 1630 static int
 1631 ip4f_init(void)
 1632 {
 1633         struct ip4_frag *fp;
 1634         int i;
 1635 
 1636         TAILQ_INIT(&ip4f_list);
 1637         for (i=0; i<IP4F_TABSIZE; i++) {
 1638                 fp = malloc(sizeof(struct ip4_frag), M_DEVBUF, M_NOWAIT);
 1639                 if (fp == NULL) {
 1640                         printf("ip4f_init: can't alloc %dth entry!\n", i);
 1641                         if (i == 0)
 1642                                 return (-1);
 1643                         return (0);
 1644                 }
 1645                 fp->ip4f_valid = 0;
 1646                 TAILQ_INSERT_TAIL(&ip4f_list, fp, ip4f_chain);
 1647         }
 1648         return (0);
 1649 }
 1650 
 1651 static struct ip4_frag *
 1652 ip4f_alloc(void)
 1653 {
 1654         struct ip4_frag *fp;
 1655 
 1656         /* reclaim an entry at the tail, put it at the head */
 1657         fp = TAILQ_LAST(&ip4f_list, ip4f_list);
 1658         TAILQ_REMOVE(&ip4f_list, fp, ip4f_chain);
 1659         fp->ip4f_valid = 1;
 1660         TAILQ_INSERT_HEAD(&ip4f_list, fp, ip4f_chain);
 1661         return (fp);
 1662 }
 1663 
 1664 static void
 1665 ip4f_free(struct ip4_frag *fp)
 1666 {
 1667         TAILQ_REMOVE(&ip4f_list, fp, ip4f_chain);
 1668         fp->ip4f_valid = 0;
 1669         TAILQ_INSERT_TAIL(&ip4f_list, fp, ip4f_chain);
 1670 }
 1671 
 1672 #endif /* ALTQ3_CLFIER_COMPAT */

Cache object: 6794af3924451dd911d7b370070fc0c7


[ 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.