]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sbin/pfctl/pfctl_altq.c
Fix the build.
[FreeBSD/stable/10.git] / sbin / pfctl / pfctl_altq.c
1 /*      $OpenBSD: pfctl_altq.c,v 1.93 2007/10/15 02:16:35 deraadt Exp $ */
2
3 /*
4  * Copyright (c) 2002
5  *      Sony Computer Science Laboratories Inc.
6  * Copyright (c) 2002, 2003 Henning Brauer <henning@openbsd.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
23
24 #include <sys/types.h>
25 #include <sys/ioctl.h>
26 #include <sys/socket.h>
27
28 #include <net/if.h>
29 #include <netinet/in.h>
30 #include <net/pfvar.h>
31
32 #include <err.h>
33 #include <errno.h>
34 #include <limits.h>
35 #include <math.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include <altq/altq.h>
42 #include <altq/altq_cbq.h>
43 #include <altq/altq_priq.h>
44 #include <altq/altq_hfsc.h>
45 #include <altq/altq_fairq.h>
46
47 #include "pfctl_parser.h"
48 #include "pfctl.h"
49
50 #define is_sc_null(sc)  (((sc) == NULL) || ((sc)->m1 == 0 && (sc)->m2 == 0))
51
52 TAILQ_HEAD(altqs, pf_altq) altqs = TAILQ_HEAD_INITIALIZER(altqs);
53 LIST_HEAD(gen_sc, segment) rtsc, lssc;
54
55 struct pf_altq  *qname_to_pfaltq(const char *, const char *);
56 u_int32_t        qname_to_qid(const char *);
57
58 static int      eval_pfqueue_cbq(struct pfctl *, struct pf_altq *);
59 static int      cbq_compute_idletime(struct pfctl *, struct pf_altq *);
60 static int      check_commit_cbq(int, int, struct pf_altq *);
61 static int      print_cbq_opts(const struct pf_altq *);
62
63 static int      eval_pfqueue_priq(struct pfctl *, struct pf_altq *);
64 static int      check_commit_priq(int, int, struct pf_altq *);
65 static int      print_priq_opts(const struct pf_altq *);
66
67 static int      eval_pfqueue_hfsc(struct pfctl *, struct pf_altq *);
68 static int      check_commit_hfsc(int, int, struct pf_altq *);
69 static int      print_hfsc_opts(const struct pf_altq *,
70                     const struct node_queue_opt *);
71
72 static int      eval_pfqueue_fairq(struct pfctl *, struct pf_altq *);
73 static int      print_fairq_opts(const struct pf_altq *,
74                     const struct node_queue_opt *);
75 static int      check_commit_fairq(int, int, struct pf_altq *);
76
77 static void              gsc_add_sc(struct gen_sc *, struct service_curve *);
78 static int               is_gsc_under_sc(struct gen_sc *,
79                              struct service_curve *);
80 static void              gsc_destroy(struct gen_sc *);
81 static struct segment   *gsc_getentry(struct gen_sc *, double);
82 static int               gsc_add_seg(struct gen_sc *, double, double, double,
83                              double);
84 static double            sc_x2y(struct service_curve *, double);
85
86 #ifdef __FreeBSD__
87 u_int32_t       getifspeed(int, char *);
88 #else
89 u_int32_t        getifspeed(char *);
90 #endif
91 u_long           getifmtu(char *);
92 int              eval_queue_opts(struct pf_altq *, struct node_queue_opt *,
93                      u_int32_t);
94 u_int32_t        eval_bwspec(struct node_queue_bw *, u_int32_t);
95 void             print_hfsc_sc(const char *, u_int, u_int, u_int,
96                      const struct node_hfsc_sc *);
97 void             print_fairq_sc(const char *, u_int, u_int, u_int,
98                      const struct node_fairq_sc *);
99
100 void
101 pfaltq_store(struct pf_altq *a)
102 {
103         struct pf_altq  *altq;
104
105         if ((altq = malloc(sizeof(*altq))) == NULL)
106                 err(1, "malloc");
107         memcpy(altq, a, sizeof(struct pf_altq));
108         TAILQ_INSERT_TAIL(&altqs, altq, entries);
109 }
110
111 struct pf_altq *
112 pfaltq_lookup(const char *ifname)
113 {
114         struct pf_altq  *altq;
115
116         TAILQ_FOREACH(altq, &altqs, entries) {
117                 if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 &&
118                     altq->qname[0] == 0)
119                         return (altq);
120         }
121         return (NULL);
122 }
123
124 struct pf_altq *
125 qname_to_pfaltq(const char *qname, const char *ifname)
126 {
127         struct pf_altq  *altq;
128
129         TAILQ_FOREACH(altq, &altqs, entries) {
130                 if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 &&
131                     strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0)
132                         return (altq);
133         }
134         return (NULL);
135 }
136
137 u_int32_t
138 qname_to_qid(const char *qname)
139 {
140         struct pf_altq  *altq;
141
142         /*
143          * We guarantee that same named queues on different interfaces
144          * have the same qid, so we do NOT need to limit matching on
145          * one interface!
146          */
147
148         TAILQ_FOREACH(altq, &altqs, entries) {
149                 if (strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0)
150                         return (altq->qid);
151         }
152         return (0);
153 }
154
155 void
156 print_altq(const struct pf_altq *a, unsigned int level,
157     struct node_queue_bw *bw, struct node_queue_opt *qopts)
158 {
159         if (a->qname[0] != 0) {
160                 print_queue(a, level, bw, 1, qopts);
161                 return;
162         }
163
164 #ifdef __FreeBSD__
165         if (a->local_flags & PFALTQ_FLAG_IF_REMOVED)
166                 printf("INACTIVE ");
167 #endif
168
169         printf("altq on %s ", a->ifname);
170
171         switch (a->scheduler) {
172         case ALTQT_CBQ:
173                 if (!print_cbq_opts(a))
174                         printf("cbq ");
175                 break;
176         case ALTQT_PRIQ:
177                 if (!print_priq_opts(a))
178                         printf("priq ");
179                 break;
180         case ALTQT_HFSC:
181                 if (!print_hfsc_opts(a, qopts))
182                         printf("hfsc ");
183                 break;
184         case ALTQT_FAIRQ:
185                 if (!print_fairq_opts(a, qopts))
186                         printf("fairq ");
187                 break;
188         }
189
190         if (bw != NULL && bw->bw_percent > 0) {
191                 if (bw->bw_percent < 100)
192                         printf("bandwidth %u%% ", bw->bw_percent);
193         } else
194                 printf("bandwidth %s ", rate2str((double)a->ifbandwidth));
195
196         if (a->qlimit != DEFAULT_QLIMIT)
197                 printf("qlimit %u ", a->qlimit);
198         printf("tbrsize %u ", a->tbrsize);
199 }
200
201 void
202 print_queue(const struct pf_altq *a, unsigned int level,
203     struct node_queue_bw *bw, int print_interface,
204     struct node_queue_opt *qopts)
205 {
206         unsigned int    i;
207
208 #ifdef __FreeBSD__
209         if (a->local_flags & PFALTQ_FLAG_IF_REMOVED)
210                 printf("INACTIVE ");
211 #endif
212         printf("queue ");
213         for (i = 0; i < level; ++i)
214                 printf(" ");
215         printf("%s ", a->qname);
216         if (print_interface)
217                 printf("on %s ", a->ifname);
218         if (a->scheduler == ALTQT_CBQ || a->scheduler == ALTQT_HFSC ||
219                 a->scheduler == ALTQT_FAIRQ) {
220                 if (bw != NULL && bw->bw_percent > 0) {
221                         if (bw->bw_percent < 100)
222                                 printf("bandwidth %u%% ", bw->bw_percent);
223                 } else
224                         printf("bandwidth %s ", rate2str((double)a->bandwidth));
225         }
226         if (a->priority != DEFAULT_PRIORITY)
227                 printf("priority %u ", a->priority);
228         if (a->qlimit != DEFAULT_QLIMIT)
229                 printf("qlimit %u ", a->qlimit);
230         switch (a->scheduler) {
231         case ALTQT_CBQ:
232                 print_cbq_opts(a);
233                 break;
234         case ALTQT_PRIQ:
235                 print_priq_opts(a);
236                 break;
237         case ALTQT_HFSC:
238                 print_hfsc_opts(a, qopts);
239                 break;
240         case ALTQT_FAIRQ:
241                 print_fairq_opts(a, qopts);
242                 break;
243         }
244 }
245
246 /*
247  * eval_pfaltq computes the discipline parameters.
248  */
249 int
250 eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
251     struct node_queue_opt *opts)
252 {
253         u_int   rate, size, errors = 0;
254
255         if (bw->bw_absolute > 0)
256                 pa->ifbandwidth = bw->bw_absolute;
257         else
258 #ifdef __FreeBSD__
259                 if ((rate = getifspeed(pf->dev, pa->ifname)) == 0) {
260 #else
261                 if ((rate = getifspeed(pa->ifname)) == 0) {
262 #endif
263                         fprintf(stderr, "interface %s does not know its bandwidth, "
264                             "please specify an absolute bandwidth\n",
265                             pa->ifname);
266                         errors++;
267                 } else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0)
268                         pa->ifbandwidth = rate;
269
270         errors += eval_queue_opts(pa, opts, pa->ifbandwidth);
271
272         /* if tbrsize is not specified, use heuristics */
273         if (pa->tbrsize == 0) {
274                 rate = pa->ifbandwidth;
275                 if (rate <= 1 * 1000 * 1000)
276                         size = 1;
277                 else if (rate <= 10 * 1000 * 1000)
278                         size = 4;
279                 else if (rate <= 200 * 1000 * 1000)
280                         size = 8;
281                 else
282                         size = 24;
283                 size = size * getifmtu(pa->ifname);
284                 if (size > 0xffff)
285                         size = 0xffff;
286                 pa->tbrsize = size;
287         }
288         return (errors);
289 }
290
291 /*
292  * check_commit_altq does consistency check for each interface
293  */
294 int
295 check_commit_altq(int dev, int opts)
296 {
297         struct pf_altq  *altq;
298         int              error = 0;
299
300         /* call the discipline check for each interface. */
301         TAILQ_FOREACH(altq, &altqs, entries) {
302                 if (altq->qname[0] == 0) {
303                         switch (altq->scheduler) {
304                         case ALTQT_CBQ:
305                                 error = check_commit_cbq(dev, opts, altq);
306                                 break;
307                         case ALTQT_PRIQ:
308                                 error = check_commit_priq(dev, opts, altq);
309                                 break;
310                         case ALTQT_HFSC:
311                                 error = check_commit_hfsc(dev, opts, altq);
312                                 break;
313                         case ALTQT_FAIRQ:
314                                 error = check_commit_fairq(dev, opts, altq);
315                                 break;
316                         default:
317                                 break;
318                         }
319                 }
320         }
321         return (error);
322 }
323
324 /*
325  * eval_pfqueue computes the queue parameters.
326  */
327 int
328 eval_pfqueue(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
329     struct node_queue_opt *opts)
330 {
331         /* should be merged with expand_queue */
332         struct pf_altq  *if_pa, *parent, *altq;
333         u_int32_t        bwsum;
334         int              error = 0;
335
336         /* find the corresponding interface and copy fields used by queues */
337         if ((if_pa = pfaltq_lookup(pa->ifname)) == NULL) {
338                 fprintf(stderr, "altq not defined on %s\n", pa->ifname);
339                 return (1);
340         }
341         pa->scheduler = if_pa->scheduler;
342         pa->ifbandwidth = if_pa->ifbandwidth;
343
344         if (qname_to_pfaltq(pa->qname, pa->ifname) != NULL) {
345                 fprintf(stderr, "queue %s already exists on interface %s\n",
346                     pa->qname, pa->ifname);
347                 return (1);
348         }
349         pa->qid = qname_to_qid(pa->qname);
350
351         parent = NULL;
352         if (pa->parent[0] != 0) {
353                 parent = qname_to_pfaltq(pa->parent, pa->ifname);
354                 if (parent == NULL) {
355                         fprintf(stderr, "parent %s not found for %s\n",
356                             pa->parent, pa->qname);
357                         return (1);
358                 }
359                 pa->parent_qid = parent->qid;
360         }
361         if (pa->qlimit == 0)
362                 pa->qlimit = DEFAULT_QLIMIT;
363
364         if (pa->scheduler == ALTQT_CBQ || pa->scheduler == ALTQT_HFSC ||
365                 pa->scheduler == ALTQT_FAIRQ) {
366                 pa->bandwidth = eval_bwspec(bw,
367                     parent == NULL ? 0 : parent->bandwidth);
368
369                 if (pa->bandwidth > pa->ifbandwidth) {
370                         fprintf(stderr, "bandwidth for %s higher than "
371                             "interface\n", pa->qname);
372                         return (1);
373                 }
374                 /* check the sum of the child bandwidth is under parent's */
375                 if (parent != NULL) {
376                         if (pa->bandwidth > parent->bandwidth) {
377                                 warnx("bandwidth for %s higher than parent",
378                                     pa->qname);
379                                 return (1);
380                         }
381                         bwsum = 0;
382                         TAILQ_FOREACH(altq, &altqs, entries) {
383                                 if (strncmp(altq->ifname, pa->ifname,
384                                     IFNAMSIZ) == 0 &&
385                                     altq->qname[0] != 0 &&
386                                     strncmp(altq->parent, pa->parent,
387                                     PF_QNAME_SIZE) == 0)
388                                         bwsum += altq->bandwidth;
389                         }
390                         bwsum += pa->bandwidth;
391                         if (bwsum > parent->bandwidth) {
392                                 warnx("the sum of the child bandwidth higher"
393                                     " than parent \"%s\"", parent->qname);
394                         }
395                 }
396         }
397
398         if (eval_queue_opts(pa, opts, parent == NULL? 0 : parent->bandwidth))
399                 return (1);
400
401         switch (pa->scheduler) {
402         case ALTQT_CBQ:
403                 error = eval_pfqueue_cbq(pf, pa);
404                 break;
405         case ALTQT_PRIQ:
406                 error = eval_pfqueue_priq(pf, pa);
407                 break;
408         case ALTQT_HFSC:
409                 error = eval_pfqueue_hfsc(pf, pa);
410                 break;
411         case ALTQT_FAIRQ:
412                 error = eval_pfqueue_fairq(pf, pa);
413                 break;
414         default:
415                 break;
416         }
417         return (error);
418 }
419
420 /*
421  * CBQ support functions
422  */
423 #define RM_FILTER_GAIN  5       /* log2 of gain, e.g., 5 => 31/32 */
424 #define RM_NS_PER_SEC   (1000000000)
425
426 static int
427 eval_pfqueue_cbq(struct pfctl *pf, struct pf_altq *pa)
428 {
429         struct cbq_opts *opts;
430         u_int            ifmtu;
431
432         if (pa->priority >= CBQ_MAXPRI) {
433                 warnx("priority out of range: max %d", CBQ_MAXPRI - 1);
434                 return (-1);
435         }
436
437         ifmtu = getifmtu(pa->ifname);
438         opts = &pa->pq_u.cbq_opts;
439
440         if (opts->pktsize == 0) {       /* use default */
441                 opts->pktsize = ifmtu;
442                 if (opts->pktsize > MCLBYTES)   /* do what TCP does */
443                         opts->pktsize &= ~MCLBYTES;
444         } else if (opts->pktsize > ifmtu)
445                 opts->pktsize = ifmtu;
446         if (opts->maxpktsize == 0)      /* use default */
447                 opts->maxpktsize = ifmtu;
448         else if (opts->maxpktsize > ifmtu)
449                 opts->pktsize = ifmtu;
450
451         if (opts->pktsize > opts->maxpktsize)
452                 opts->pktsize = opts->maxpktsize;
453
454         if (pa->parent[0] == 0)
455                 opts->flags |= (CBQCLF_ROOTCLASS | CBQCLF_WRR);
456
457         cbq_compute_idletime(pf, pa);
458         return (0);
459 }
460
461 /*
462  * compute ns_per_byte, maxidle, minidle, and offtime
463  */
464 static int
465 cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa)
466 {
467         struct cbq_opts *opts;
468         double           maxidle_s, maxidle, minidle;
469         double           offtime, nsPerByte, ifnsPerByte, ptime, cptime;
470         double           z, g, f, gton, gtom;
471         u_int            minburst, maxburst;
472
473         opts = &pa->pq_u.cbq_opts;
474         ifnsPerByte = (1.0 / (double)pa->ifbandwidth) * RM_NS_PER_SEC * 8;
475         minburst = opts->minburst;
476         maxburst = opts->maxburst;
477
478         if (pa->bandwidth == 0)
479                 f = 0.0001;     /* small enough? */
480         else
481                 f = ((double) pa->bandwidth / (double) pa->ifbandwidth);
482
483         nsPerByte = ifnsPerByte / f;
484         ptime = (double)opts->pktsize * ifnsPerByte;
485         cptime = ptime * (1.0 - f) / f;
486
487         if (nsPerByte * (double)opts->maxpktsize > (double)INT_MAX) {
488                 /*
489                  * this causes integer overflow in kernel!
490                  * (bandwidth < 6Kbps when max_pkt_size=1500)
491                  */
492                 if (pa->bandwidth != 0 && (pf->opts & PF_OPT_QUIET) == 0)
493                         warnx("queue bandwidth must be larger than %s",
494                             rate2str(ifnsPerByte * (double)opts->maxpktsize /
495                             (double)INT_MAX * (double)pa->ifbandwidth));
496                         fprintf(stderr, "cbq: queue %s is too slow!\n",
497                             pa->qname);
498                 nsPerByte = (double)(INT_MAX / opts->maxpktsize);
499         }
500
501         if (maxburst == 0) {  /* use default */
502                 if (cptime > 10.0 * 1000000)
503                         maxburst = 4;
504                 else
505                         maxburst = 16;
506         }
507         if (minburst == 0)  /* use default */
508                 minburst = 2;
509         if (minburst > maxburst)
510                 minburst = maxburst;
511
512         z = (double)(1 << RM_FILTER_GAIN);
513         g = (1.0 - 1.0 / z);
514         gton = pow(g, (double)maxburst);
515         gtom = pow(g, (double)(minburst-1));
516         maxidle = ((1.0 / f - 1.0) * ((1.0 - gton) / gton));
517         maxidle_s = (1.0 - g);
518         if (maxidle > maxidle_s)
519                 maxidle = ptime * maxidle;
520         else
521                 maxidle = ptime * maxidle_s;
522         offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom);
523         minidle = -((double)opts->maxpktsize * (double)nsPerByte);
524
525         /* scale parameters */
526         maxidle = ((maxidle * 8.0) / nsPerByte) *
527             pow(2.0, (double)RM_FILTER_GAIN);
528         offtime = (offtime * 8.0) / nsPerByte *
529             pow(2.0, (double)RM_FILTER_GAIN);
530         minidle = ((minidle * 8.0) / nsPerByte) *
531             pow(2.0, (double)RM_FILTER_GAIN);
532
533         maxidle = maxidle / 1000.0;
534         offtime = offtime / 1000.0;
535         minidle = minidle / 1000.0;
536
537         opts->minburst = minburst;
538         opts->maxburst = maxburst;
539         opts->ns_per_byte = (u_int)nsPerByte;
540         opts->maxidle = (u_int)fabs(maxidle);
541         opts->minidle = (int)minidle;
542         opts->offtime = (u_int)fabs(offtime);
543
544         return (0);
545 }
546
547 static int
548 check_commit_cbq(int dev, int opts, struct pf_altq *pa)
549 {
550         struct pf_altq  *altq;
551         int              root_class, default_class;
552         int              error = 0;
553
554         /*
555          * check if cbq has one root queue and one default queue
556          * for this interface
557          */
558         root_class = default_class = 0;
559         TAILQ_FOREACH(altq, &altqs, entries) {
560                 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
561                         continue;
562                 if (altq->qname[0] == 0)  /* this is for interface */
563                         continue;
564                 if (altq->pq_u.cbq_opts.flags & CBQCLF_ROOTCLASS)
565                         root_class++;
566                 if (altq->pq_u.cbq_opts.flags & CBQCLF_DEFCLASS)
567                         default_class++;
568         }
569         if (root_class != 1) {
570                 warnx("should have one root queue on %s", pa->ifname);
571                 error++;
572         }
573         if (default_class != 1) {
574                 warnx("should have one default queue on %s", pa->ifname);
575                 error++;
576         }
577         return (error);
578 }
579
580 static int
581 print_cbq_opts(const struct pf_altq *a)
582 {
583         const struct cbq_opts   *opts;
584
585         opts = &a->pq_u.cbq_opts;
586         if (opts->flags) {
587                 printf("cbq(");
588                 if (opts->flags & CBQCLF_RED)
589                         printf(" red");
590                 if (opts->flags & CBQCLF_ECN)
591                         printf(" ecn");
592                 if (opts->flags & CBQCLF_RIO)
593                         printf(" rio");
594                 if (opts->flags & CBQCLF_CLEARDSCP)
595                         printf(" cleardscp");
596                 if (opts->flags & CBQCLF_FLOWVALVE)
597                         printf(" flowvalve");
598                 if (opts->flags & CBQCLF_BORROW)
599                         printf(" borrow");
600                 if (opts->flags & CBQCLF_WRR)
601                         printf(" wrr");
602                 if (opts->flags & CBQCLF_EFFICIENT)
603                         printf(" efficient");
604                 if (opts->flags & CBQCLF_ROOTCLASS)
605                         printf(" root");
606                 if (opts->flags & CBQCLF_DEFCLASS)
607                         printf(" default");
608                 printf(" ) ");
609
610                 return (1);
611         } else
612                 return (0);
613 }
614
615 /*
616  * PRIQ support functions
617  */
618 static int
619 eval_pfqueue_priq(struct pfctl *pf, struct pf_altq *pa)
620 {
621         struct pf_altq  *altq;
622
623         if (pa->priority >= PRIQ_MAXPRI) {
624                 warnx("priority out of range: max %d", PRIQ_MAXPRI - 1);
625                 return (-1);
626         }
627         /* the priority should be unique for the interface */
628         TAILQ_FOREACH(altq, &altqs, entries) {
629                 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) == 0 &&
630                     altq->qname[0] != 0 && altq->priority == pa->priority) {
631                         warnx("%s and %s have the same priority",
632                             altq->qname, pa->qname);
633                         return (-1);
634                 }
635         }
636
637         return (0);
638 }
639
640 static int
641 check_commit_priq(int dev, int opts, struct pf_altq *pa)
642 {
643         struct pf_altq  *altq;
644         int              default_class;
645         int              error = 0;
646
647         /*
648          * check if priq has one default class for this interface
649          */
650         default_class = 0;
651         TAILQ_FOREACH(altq, &altqs, entries) {
652                 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
653                         continue;
654                 if (altq->qname[0] == 0)  /* this is for interface */
655                         continue;
656                 if (altq->pq_u.priq_opts.flags & PRCF_DEFAULTCLASS)
657                         default_class++;
658         }
659         if (default_class != 1) {
660                 warnx("should have one default queue on %s", pa->ifname);
661                 error++;
662         }
663         return (error);
664 }
665
666 static int
667 print_priq_opts(const struct pf_altq *a)
668 {
669         const struct priq_opts  *opts;
670
671         opts = &a->pq_u.priq_opts;
672
673         if (opts->flags) {
674                 printf("priq(");
675                 if (opts->flags & PRCF_RED)
676                         printf(" red");
677                 if (opts->flags & PRCF_ECN)
678                         printf(" ecn");
679                 if (opts->flags & PRCF_RIO)
680                         printf(" rio");
681                 if (opts->flags & PRCF_CLEARDSCP)
682                         printf(" cleardscp");
683                 if (opts->flags & PRCF_DEFAULTCLASS)
684                         printf(" default");
685                 printf(" ) ");
686
687                 return (1);
688         } else
689                 return (0);
690 }
691
692 /*
693  * HFSC support functions
694  */
695 static int
696 eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa)
697 {
698         struct pf_altq          *altq, *parent;
699         struct hfsc_opts        *opts;
700         struct service_curve     sc;
701
702         opts = &pa->pq_u.hfsc_opts;
703
704         if (pa->parent[0] == 0) {
705                 /* root queue */
706                 opts->lssc_m1 = pa->ifbandwidth;
707                 opts->lssc_m2 = pa->ifbandwidth;
708                 opts->lssc_d = 0;
709                 return (0);
710         }
711
712         LIST_INIT(&rtsc);
713         LIST_INIT(&lssc);
714
715         /* if link_share is not specified, use bandwidth */
716         if (opts->lssc_m2 == 0)
717                 opts->lssc_m2 = pa->bandwidth;
718
719         if ((opts->rtsc_m1 > 0 && opts->rtsc_m2 == 0) ||
720             (opts->lssc_m1 > 0 && opts->lssc_m2 == 0) ||
721             (opts->ulsc_m1 > 0 && opts->ulsc_m2 == 0)) {
722                 warnx("m2 is zero for %s", pa->qname);
723                 return (-1);
724         }
725
726         if ((opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) ||
727             (opts->lssc_m1 < opts->lssc_m2 && opts->lssc_m1 != 0) ||
728             (opts->ulsc_m1 < opts->ulsc_m2 && opts->ulsc_m1 != 0)) {
729                 warnx("m1 must be zero for convex curve: %s", pa->qname);
730                 return (-1);
731         }
732
733         /*
734          * admission control:
735          * for the real-time service curve, the sum of the service curves
736          * should not exceed 80% of the interface bandwidth.  20% is reserved
737          * not to over-commit the actual interface bandwidth.
738          * for the linkshare service curve, the sum of the child service
739          * curve should not exceed the parent service curve.
740          * for the upper-limit service curve, the assigned bandwidth should
741          * be smaller than the interface bandwidth, and the upper-limit should
742          * be larger than the real-time service curve when both are defined.
743          */
744         parent = qname_to_pfaltq(pa->parent, pa->ifname);
745         if (parent == NULL)
746                 errx(1, "parent %s not found for %s", pa->parent, pa->qname);
747
748         TAILQ_FOREACH(altq, &altqs, entries) {
749                 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
750                         continue;
751                 if (altq->qname[0] == 0)  /* this is for interface */
752                         continue;
753
754                 /* if the class has a real-time service curve, add it. */
755                 if (opts->rtsc_m2 != 0 && altq->pq_u.hfsc_opts.rtsc_m2 != 0) {
756                         sc.m1 = altq->pq_u.hfsc_opts.rtsc_m1;
757                         sc.d = altq->pq_u.hfsc_opts.rtsc_d;
758                         sc.m2 = altq->pq_u.hfsc_opts.rtsc_m2;
759                         gsc_add_sc(&rtsc, &sc);
760                 }
761
762                 if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0)
763                         continue;
764
765                 /* if the class has a linkshare service curve, add it. */
766                 if (opts->lssc_m2 != 0 && altq->pq_u.hfsc_opts.lssc_m2 != 0) {
767                         sc.m1 = altq->pq_u.hfsc_opts.lssc_m1;
768                         sc.d = altq->pq_u.hfsc_opts.lssc_d;
769                         sc.m2 = altq->pq_u.hfsc_opts.lssc_m2;
770                         gsc_add_sc(&lssc, &sc);
771                 }
772         }
773
774         /* check the real-time service curve.  reserve 20% of interface bw */
775         if (opts->rtsc_m2 != 0) {
776                 /* add this queue to the sum */
777                 sc.m1 = opts->rtsc_m1;
778                 sc.d = opts->rtsc_d;
779                 sc.m2 = opts->rtsc_m2;
780                 gsc_add_sc(&rtsc, &sc);
781                 /* compare the sum with 80% of the interface */
782                 sc.m1 = 0;
783                 sc.d = 0;
784                 sc.m2 = pa->ifbandwidth / 100 * 80;
785                 if (!is_gsc_under_sc(&rtsc, &sc)) {
786                         warnx("real-time sc exceeds 80%% of the interface "
787                             "bandwidth (%s)", rate2str((double)sc.m2));
788                         goto err_ret;
789                 }
790         }
791
792         /* check the linkshare service curve. */
793         if (opts->lssc_m2 != 0) {
794                 /* add this queue to the child sum */
795                 sc.m1 = opts->lssc_m1;
796                 sc.d = opts->lssc_d;
797                 sc.m2 = opts->lssc_m2;
798                 gsc_add_sc(&lssc, &sc);
799                 /* compare the sum of the children with parent's sc */
800                 sc.m1 = parent->pq_u.hfsc_opts.lssc_m1;
801                 sc.d = parent->pq_u.hfsc_opts.lssc_d;
802                 sc.m2 = parent->pq_u.hfsc_opts.lssc_m2;
803                 if (!is_gsc_under_sc(&lssc, &sc)) {
804                         warnx("linkshare sc exceeds parent's sc");
805                         goto err_ret;
806                 }
807         }
808
809         /* check the upper-limit service curve. */
810         if (opts->ulsc_m2 != 0) {
811                 if (opts->ulsc_m1 > pa->ifbandwidth ||
812                     opts->ulsc_m2 > pa->ifbandwidth) {
813                         warnx("upper-limit larger than interface bandwidth");
814                         goto err_ret;
815                 }
816                 if (opts->rtsc_m2 != 0 && opts->rtsc_m2 > opts->ulsc_m2) {
817                         warnx("upper-limit sc smaller than real-time sc");
818                         goto err_ret;
819                 }
820         }
821
822         gsc_destroy(&rtsc);
823         gsc_destroy(&lssc);
824
825         return (0);
826
827 err_ret:
828         gsc_destroy(&rtsc);
829         gsc_destroy(&lssc);
830         return (-1);
831 }
832
833 /*
834  * FAIRQ support functions
835  */
836 static int
837 eval_pfqueue_fairq(struct pfctl *pf __unused, struct pf_altq *pa)
838 {
839         struct pf_altq          *altq, *parent;
840         struct fairq_opts       *opts;
841         struct service_curve     sc;
842
843         opts = &pa->pq_u.fairq_opts;
844
845         if (pa->parent[0] == 0) {
846                 /* root queue */
847                 opts->lssc_m1 = pa->ifbandwidth;
848                 opts->lssc_m2 = pa->ifbandwidth;
849                 opts->lssc_d = 0;
850                 return (0);
851         }
852
853         LIST_INIT(&lssc);
854
855         /* if link_share is not specified, use bandwidth */
856         if (opts->lssc_m2 == 0)
857                 opts->lssc_m2 = pa->bandwidth;
858
859         /*
860          * admission control:
861          * for the real-time service curve, the sum of the service curves
862          * should not exceed 80% of the interface bandwidth.  20% is reserved
863          * not to over-commit the actual interface bandwidth.
864          * for the link-sharing service curve, the sum of the child service
865          * curve should not exceed the parent service curve.
866          * for the upper-limit service curve, the assigned bandwidth should
867          * be smaller than the interface bandwidth, and the upper-limit should
868          * be larger than the real-time service curve when both are defined.
869          */
870         parent = qname_to_pfaltq(pa->parent, pa->ifname);
871         if (parent == NULL)
872                 errx(1, "parent %s not found for %s", pa->parent, pa->qname);
873
874         TAILQ_FOREACH(altq, &altqs, entries) {
875                 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
876                         continue;
877                 if (altq->qname[0] == 0)  /* this is for interface */
878                         continue;
879
880                 if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0)
881                         continue;
882
883                 /* if the class has a link-sharing service curve, add it. */
884                 if (opts->lssc_m2 != 0 && altq->pq_u.fairq_opts.lssc_m2 != 0) {
885                         sc.m1 = altq->pq_u.fairq_opts.lssc_m1;
886                         sc.d = altq->pq_u.fairq_opts.lssc_d;
887                         sc.m2 = altq->pq_u.fairq_opts.lssc_m2;
888                         gsc_add_sc(&lssc, &sc);
889                 }
890         }
891
892         /* check the link-sharing service curve. */
893         if (opts->lssc_m2 != 0) {
894                 sc.m1 = parent->pq_u.fairq_opts.lssc_m1;
895                 sc.d = parent->pq_u.fairq_opts.lssc_d;
896                 sc.m2 = parent->pq_u.fairq_opts.lssc_m2;
897                 if (!is_gsc_under_sc(&lssc, &sc)) {
898                         warnx("link-sharing sc exceeds parent's sc");
899                         goto err_ret;
900                 }
901         }
902
903         gsc_destroy(&lssc);
904
905         return (0);
906
907 err_ret:
908         gsc_destroy(&lssc);
909         return (-1);
910 }
911
912 static int
913 check_commit_hfsc(int dev, int opts, struct pf_altq *pa)
914 {
915         struct pf_altq  *altq, *def = NULL;
916         int              default_class;
917         int              error = 0;
918
919         /* check if hfsc has one default queue for this interface */
920         default_class = 0;
921         TAILQ_FOREACH(altq, &altqs, entries) {
922                 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
923                         continue;
924                 if (altq->qname[0] == 0)  /* this is for interface */
925                         continue;
926                 if (altq->parent[0] == 0)  /* dummy root */
927                         continue;
928                 if (altq->pq_u.hfsc_opts.flags & HFCF_DEFAULTCLASS) {
929                         default_class++;
930                         def = altq;
931                 }
932         }
933         if (default_class != 1) {
934                 warnx("should have one default queue on %s", pa->ifname);
935                 return (1);
936         }
937         /* make sure the default queue is a leaf */
938         TAILQ_FOREACH(altq, &altqs, entries) {
939                 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
940                         continue;
941                 if (altq->qname[0] == 0)  /* this is for interface */
942                         continue;
943                 if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) {
944                         warnx("default queue is not a leaf");
945                         error++;
946                 }
947         }
948         return (error);
949 }
950
951 static int
952 check_commit_fairq(int dev __unused, int opts __unused, struct pf_altq *pa)
953 {
954         struct pf_altq  *altq, *def = NULL;
955         int              default_class;
956         int              error = 0;
957
958         /* check if fairq has one default queue for this interface */
959         default_class = 0;
960         TAILQ_FOREACH(altq, &altqs, entries) {
961                 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
962                         continue;
963                 if (altq->qname[0] == 0)  /* this is for interface */
964                         continue;
965                 if (altq->pq_u.fairq_opts.flags & FARF_DEFAULTCLASS) {
966                         default_class++;
967                         def = altq;
968                 }
969         }
970         if (default_class != 1) {
971                 warnx("should have one default queue on %s", pa->ifname);
972                 return (1);
973         }
974         /* make sure the default queue is a leaf */
975         TAILQ_FOREACH(altq, &altqs, entries) {
976                 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
977                         continue;
978                 if (altq->qname[0] == 0)  /* this is for interface */
979                         continue;
980                 if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) {
981                         warnx("default queue is not a leaf");
982                         error++;
983                 }
984         }
985         return (error);
986 }
987
988 static int
989 print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
990 {
991         const struct hfsc_opts          *opts;
992         const struct node_hfsc_sc       *rtsc, *lssc, *ulsc;
993
994         opts = &a->pq_u.hfsc_opts;
995         if (qopts == NULL)
996                 rtsc = lssc = ulsc = NULL;
997         else {
998                 rtsc = &qopts->data.hfsc_opts.realtime;
999                 lssc = &qopts->data.hfsc_opts.linkshare;
1000                 ulsc = &qopts->data.hfsc_opts.upperlimit;
1001         }
1002
1003         if (opts->flags || opts->rtsc_m2 != 0 || opts->ulsc_m2 != 0 ||
1004             (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
1005             opts->lssc_d != 0))) {
1006                 printf("hfsc(");
1007                 if (opts->flags & HFCF_RED)
1008                         printf(" red");
1009                 if (opts->flags & HFCF_ECN)
1010                         printf(" ecn");
1011                 if (opts->flags & HFCF_RIO)
1012                         printf(" rio");
1013                 if (opts->flags & HFCF_CLEARDSCP)
1014                         printf(" cleardscp");
1015                 if (opts->flags & HFCF_DEFAULTCLASS)
1016                         printf(" default");
1017                 if (opts->rtsc_m2 != 0)
1018                         print_hfsc_sc("realtime", opts->rtsc_m1, opts->rtsc_d,
1019                             opts->rtsc_m2, rtsc);
1020                 if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
1021                     opts->lssc_d != 0))
1022                         print_hfsc_sc("linkshare", opts->lssc_m1, opts->lssc_d,
1023                             opts->lssc_m2, lssc);
1024                 if (opts->ulsc_m2 != 0)
1025                         print_hfsc_sc("upperlimit", opts->ulsc_m1, opts->ulsc_d,
1026                             opts->ulsc_m2, ulsc);
1027                 printf(" ) ");
1028
1029                 return (1);
1030         } else
1031                 return (0);
1032 }
1033
1034 static int
1035 print_fairq_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
1036 {
1037         const struct fairq_opts         *opts;
1038         const struct node_fairq_sc      *loc_lssc;
1039
1040         opts = &a->pq_u.fairq_opts;
1041         if (qopts == NULL)
1042                 loc_lssc = NULL;
1043         else
1044                 loc_lssc = &qopts->data.fairq_opts.linkshare;
1045
1046         if (opts->flags ||
1047             (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
1048             opts->lssc_d != 0))) {
1049                 printf("fairq(");
1050                 if (opts->flags & FARF_RED)
1051                         printf(" red");
1052                 if (opts->flags & FARF_ECN)
1053                         printf(" ecn");
1054                 if (opts->flags & FARF_RIO)
1055                         printf(" rio");
1056                 if (opts->flags & FARF_CLEARDSCP)
1057                         printf(" cleardscp");
1058                 if (opts->flags & FARF_DEFAULTCLASS)
1059                         printf(" default");
1060                 if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
1061                     opts->lssc_d != 0))
1062                         print_fairq_sc("linkshare", opts->lssc_m1, opts->lssc_d,
1063                             opts->lssc_m2, loc_lssc);
1064                 printf(" ) ");
1065
1066                 return (1);
1067         } else
1068                 return (0);
1069 }
1070
1071 /*
1072  * admission control using generalized service curve
1073  */
1074
1075 /* add a new service curve to a generalized service curve */
1076 static void
1077 gsc_add_sc(struct gen_sc *gsc, struct service_curve *sc)
1078 {
1079         if (is_sc_null(sc))
1080                 return;
1081         if (sc->d != 0)
1082                 gsc_add_seg(gsc, 0.0, 0.0, (double)sc->d, (double)sc->m1);
1083         gsc_add_seg(gsc, (double)sc->d, 0.0, INFINITY, (double)sc->m2);
1084 }
1085
1086 /*
1087  * check whether all points of a generalized service curve have
1088  * their y-coordinates no larger than a given two-piece linear
1089  * service curve.
1090  */
1091 static int
1092 is_gsc_under_sc(struct gen_sc *gsc, struct service_curve *sc)
1093 {
1094         struct segment  *s, *last, *end;
1095         double           y;
1096
1097         if (is_sc_null(sc)) {
1098                 if (LIST_EMPTY(gsc))
1099                         return (1);
1100                 LIST_FOREACH(s, gsc, _next) {
1101                         if (s->m != 0)
1102                                 return (0);
1103                 }
1104                 return (1);
1105         }
1106         /*
1107          * gsc has a dummy entry at the end with x = INFINITY.
1108          * loop through up to this dummy entry.
1109          */
1110         end = gsc_getentry(gsc, INFINITY);
1111         if (end == NULL)
1112                 return (1);
1113         last = NULL;
1114         for (s = LIST_FIRST(gsc); s != end; s = LIST_NEXT(s, _next)) {
1115                 if (s->y > sc_x2y(sc, s->x))
1116                         return (0);
1117                 last = s;
1118         }
1119         /* last now holds the real last segment */
1120         if (last == NULL)
1121                 return (1);
1122         if (last->m > sc->m2)
1123                 return (0);
1124         if (last->x < sc->d && last->m > sc->m1) {
1125                 y = last->y + (sc->d - last->x) * last->m;
1126                 if (y > sc_x2y(sc, sc->d))
1127                         return (0);
1128         }
1129         return (1);
1130 }
1131
1132 static void
1133 gsc_destroy(struct gen_sc *gsc)
1134 {
1135         struct segment  *s;
1136
1137         while ((s = LIST_FIRST(gsc)) != NULL) {
1138                 LIST_REMOVE(s, _next);
1139                 free(s);
1140         }
1141 }
1142
1143 /*
1144  * return a segment entry starting at x.
1145  * if gsc has no entry starting at x, a new entry is created at x.
1146  */
1147 static struct segment *
1148 gsc_getentry(struct gen_sc *gsc, double x)
1149 {
1150         struct segment  *new, *prev, *s;
1151
1152         prev = NULL;
1153         LIST_FOREACH(s, gsc, _next) {
1154                 if (s->x == x)
1155                         return (s);     /* matching entry found */
1156                 else if (s->x < x)
1157                         prev = s;
1158                 else
1159                         break;
1160         }
1161
1162         /* we have to create a new entry */
1163         if ((new = calloc(1, sizeof(struct segment))) == NULL)
1164                 return (NULL);
1165
1166         new->x = x;
1167         if (x == INFINITY || s == NULL)
1168                 new->d = 0;
1169         else if (s->x == INFINITY)
1170                 new->d = INFINITY;
1171         else
1172                 new->d = s->x - x;
1173         if (prev == NULL) {
1174                 /* insert the new entry at the head of the list */
1175                 new->y = 0;
1176                 new->m = 0;
1177                 LIST_INSERT_HEAD(gsc, new, _next);
1178         } else {
1179                 /*
1180                  * the start point intersects with the segment pointed by
1181                  * prev.  divide prev into 2 segments
1182                  */
1183                 if (x == INFINITY) {
1184                         prev->d = INFINITY;
1185                         if (prev->m == 0)
1186                                 new->y = prev->y;
1187                         else
1188                                 new->y = INFINITY;
1189                 } else {
1190                         prev->d = x - prev->x;
1191                         new->y = prev->d * prev->m + prev->y;
1192                 }
1193                 new->m = prev->m;
1194                 LIST_INSERT_AFTER(prev, new, _next);
1195         }
1196         return (new);
1197 }
1198
1199 /* add a segment to a generalized service curve */
1200 static int
1201 gsc_add_seg(struct gen_sc *gsc, double x, double y, double d, double m)
1202 {
1203         struct segment  *start, *end, *s;
1204         double           x2;
1205
1206         if (d == INFINITY)
1207                 x2 = INFINITY;
1208         else
1209                 x2 = x + d;
1210         start = gsc_getentry(gsc, x);
1211         end = gsc_getentry(gsc, x2);
1212         if (start == NULL || end == NULL)
1213                 return (-1);
1214
1215         for (s = start; s != end; s = LIST_NEXT(s, _next)) {
1216                 s->m += m;
1217                 s->y += y + (s->x - x) * m;
1218         }
1219
1220         end = gsc_getentry(gsc, INFINITY);
1221         for (; s != end; s = LIST_NEXT(s, _next)) {
1222                 s->y += m * d;
1223         }
1224
1225         return (0);
1226 }
1227
1228 /* get y-projection of a service curve */
1229 static double
1230 sc_x2y(struct service_curve *sc, double x)
1231 {
1232         double  y;
1233
1234         if (x <= (double)sc->d)
1235                 /* y belongs to the 1st segment */
1236                 y = x * (double)sc->m1;
1237         else
1238                 /* y belongs to the 2nd segment */
1239                 y = (double)sc->d * (double)sc->m1
1240                         + (x - (double)sc->d) * (double)sc->m2;
1241         return (y);
1242 }
1243
1244 /*
1245  * misc utilities
1246  */
1247 #define R2S_BUFS        8
1248 #define RATESTR_MAX     16
1249
1250 char *
1251 rate2str(double rate)
1252 {
1253         char            *buf;
1254         static char      r2sbuf[R2S_BUFS][RATESTR_MAX];  /* ring bufer */
1255         static int       idx = 0;
1256         int              i;
1257         static const char unit[] = " KMG";
1258
1259         buf = r2sbuf[idx++];
1260         if (idx == R2S_BUFS)
1261                 idx = 0;
1262
1263         for (i = 0; rate >= 1000 && i <= 3; i++)
1264                 rate /= 1000;
1265
1266         if ((int)(rate * 100) % 100)
1267                 snprintf(buf, RATESTR_MAX, "%.2f%cb", rate, unit[i]);
1268         else
1269                 snprintf(buf, RATESTR_MAX, "%d%cb", (int)rate, unit[i]);
1270
1271         return (buf);
1272 }
1273
1274 #ifdef __FreeBSD__
1275 /*
1276  * XXX
1277  * FreeBSD does not have SIOCGIFDATA.
1278  * To emulate this, DIOCGIFSPEED ioctl added to pf.
1279  */
1280 u_int32_t
1281 getifspeed(int pfdev, char *ifname)
1282 {
1283         struct pf_ifspeed io;
1284
1285         bzero(&io, sizeof io);
1286         if (strlcpy(io.ifname, ifname, IFNAMSIZ) >=
1287             sizeof(io.ifname)) 
1288                 errx(1, "getifspeed: strlcpy");
1289         if (ioctl(pfdev, DIOCGIFSPEED, &io) == -1)
1290                 err(1, "DIOCGIFSPEED");
1291         return ((u_int32_t)io.baudrate);
1292 }
1293 #else
1294 u_int32_t
1295 getifspeed(char *ifname)
1296 {
1297         int             s;
1298         struct ifreq    ifr;
1299         struct if_data  ifrdat;
1300
1301         if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0)
1302                 err(1, "socket");
1303         bzero(&ifr, sizeof(ifr));
1304         if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
1305             sizeof(ifr.ifr_name))
1306                 errx(1, "getifspeed: strlcpy");
1307         ifr.ifr_data = (caddr_t)&ifrdat;
1308         if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
1309                 err(1, "SIOCGIFDATA");
1310         if (close(s))
1311                 err(1, "close");
1312         return ((u_int32_t)ifrdat.ifi_baudrate);
1313 }
1314 #endif
1315
1316 u_long
1317 getifmtu(char *ifname)
1318 {
1319         int             s;
1320         struct ifreq    ifr;
1321
1322         if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0)
1323                 err(1, "socket");
1324         bzero(&ifr, sizeof(ifr));
1325         if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
1326             sizeof(ifr.ifr_name))
1327                 errx(1, "getifmtu: strlcpy");
1328         if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == -1)
1329 #ifdef __FreeBSD__
1330                 ifr.ifr_mtu = 1500;
1331 #else
1332                 err(1, "SIOCGIFMTU");
1333 #endif
1334         if (close(s))
1335                 err(1, "close");
1336         if (ifr.ifr_mtu > 0)
1337                 return (ifr.ifr_mtu);
1338         else {
1339                 warnx("could not get mtu for %s, assuming 1500", ifname);
1340                 return (1500);
1341         }
1342 }
1343
1344 int
1345 eval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts,
1346     u_int32_t ref_bw)
1347 {
1348         int     errors = 0;
1349
1350         switch (pa->scheduler) {
1351         case ALTQT_CBQ:
1352                 pa->pq_u.cbq_opts = opts->data.cbq_opts;
1353                 break;
1354         case ALTQT_PRIQ:
1355                 pa->pq_u.priq_opts = opts->data.priq_opts;
1356                 break;
1357         case ALTQT_HFSC:
1358                 pa->pq_u.hfsc_opts.flags = opts->data.hfsc_opts.flags;
1359                 if (opts->data.hfsc_opts.linkshare.used) {
1360                         pa->pq_u.hfsc_opts.lssc_m1 =
1361                             eval_bwspec(&opts->data.hfsc_opts.linkshare.m1,
1362                             ref_bw);
1363                         pa->pq_u.hfsc_opts.lssc_m2 =
1364                             eval_bwspec(&opts->data.hfsc_opts.linkshare.m2,
1365                             ref_bw);
1366                         pa->pq_u.hfsc_opts.lssc_d =
1367                             opts->data.hfsc_opts.linkshare.d;
1368                 }
1369                 if (opts->data.hfsc_opts.realtime.used) {
1370                         pa->pq_u.hfsc_opts.rtsc_m1 =
1371                             eval_bwspec(&opts->data.hfsc_opts.realtime.m1,
1372                             ref_bw);
1373                         pa->pq_u.hfsc_opts.rtsc_m2 =
1374                             eval_bwspec(&opts->data.hfsc_opts.realtime.m2,
1375                             ref_bw);
1376                         pa->pq_u.hfsc_opts.rtsc_d =
1377                             opts->data.hfsc_opts.realtime.d;
1378                 }
1379                 if (opts->data.hfsc_opts.upperlimit.used) {
1380                         pa->pq_u.hfsc_opts.ulsc_m1 =
1381                             eval_bwspec(&opts->data.hfsc_opts.upperlimit.m1,
1382                             ref_bw);
1383                         pa->pq_u.hfsc_opts.ulsc_m2 =
1384                             eval_bwspec(&opts->data.hfsc_opts.upperlimit.m2,
1385                             ref_bw);
1386                         pa->pq_u.hfsc_opts.ulsc_d =
1387                             opts->data.hfsc_opts.upperlimit.d;
1388                 }
1389                 break;
1390         case ALTQT_FAIRQ:
1391                 pa->pq_u.fairq_opts.flags = opts->data.fairq_opts.flags;
1392                 pa->pq_u.fairq_opts.nbuckets = opts->data.fairq_opts.nbuckets;
1393                 pa->pq_u.fairq_opts.hogs_m1 =
1394                         eval_bwspec(&opts->data.fairq_opts.hogs_bw, ref_bw);
1395
1396                 if (opts->data.fairq_opts.linkshare.used) {
1397                         pa->pq_u.fairq_opts.lssc_m1 =
1398                             eval_bwspec(&opts->data.fairq_opts.linkshare.m1,
1399                             ref_bw);
1400                         pa->pq_u.fairq_opts.lssc_m2 =
1401                             eval_bwspec(&opts->data.fairq_opts.linkshare.m2,
1402                             ref_bw);
1403                         pa->pq_u.fairq_opts.lssc_d =
1404                             opts->data.fairq_opts.linkshare.d;
1405                 }
1406                 break;
1407         default:
1408                 warnx("eval_queue_opts: unknown scheduler type %u",
1409                     opts->qtype);
1410                 errors++;
1411                 break;
1412         }
1413
1414         return (errors);
1415 }
1416
1417 u_int32_t
1418 eval_bwspec(struct node_queue_bw *bw, u_int32_t ref_bw)
1419 {
1420         if (bw->bw_absolute > 0)
1421                 return (bw->bw_absolute);
1422
1423         if (bw->bw_percent > 0)
1424                 return (ref_bw / 100 * bw->bw_percent);
1425
1426         return (0);
1427 }
1428
1429 void
1430 print_hfsc_sc(const char *scname, u_int m1, u_int d, u_int m2,
1431     const struct node_hfsc_sc *sc)
1432 {
1433         printf(" %s", scname);
1434
1435         if (d != 0) {
1436                 printf("(");
1437                 if (sc != NULL && sc->m1.bw_percent > 0)
1438                         printf("%u%%", sc->m1.bw_percent);
1439                 else
1440                         printf("%s", rate2str((double)m1));
1441                 printf(" %u", d);
1442         }
1443
1444         if (sc != NULL && sc->m2.bw_percent > 0)
1445                 printf(" %u%%", sc->m2.bw_percent);
1446         else
1447                 printf(" %s", rate2str((double)m2));
1448
1449         if (d != 0)
1450                 printf(")");
1451 }
1452
1453 void
1454 print_fairq_sc(const char *scname, u_int m1, u_int d, u_int m2,
1455     const struct node_fairq_sc *sc)
1456 {
1457         printf(" %s", scname);
1458
1459         if (d != 0) {
1460                 printf("(");
1461                 if (sc != NULL && sc->m1.bw_percent > 0)
1462                         printf("%u%%", sc->m1.bw_percent);
1463                 else
1464                         printf("%s", rate2str((double)m1));
1465                 printf(" %u", d);
1466         }
1467
1468         if (sc != NULL && sc->m2.bw_percent > 0)
1469                 printf(" %u%%", sc->m2.bw_percent);
1470         else
1471                 printf(" %s", rate2str((double)m2));
1472
1473         if (d != 0)
1474                 printf(")");
1475 }