qop.c revision 1.1 1 /* $KAME: qop.c,v 1.6 2000/10/18 09:15:18 kjc Exp $ */
2 /*
3 * Copyright (C) 1999-2000
4 * Sony Computer Science Laboratories, Inc. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/param.h>
29 #include <sys/socket.h>
30 #include <sys/sockio.h>
31 #include <sys/ioctl.h>
32 #include <sys/fcntl.h>
33 #include <sys/stat.h>
34 #if defined(__FreeBSD__) && (__FreeBSD_version > 300000)
35 #include <sys/linker.h>
36 #endif
37
38 #include <net/if.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <stddef.h>
45 #include <string.h>
46 #include <ctype.h>
47 #include <errno.h>
48 #include <err.h>
49 #include <syslog.h>
50
51 #include <altq/altq.h>
52 #include <altq/altq_red.h>
53 #include <altq/altq_rio.h>
54 #include <altq/altq_cdnr.h>
55 #include "altq_qop.h"
56 #include "qop_cdnr.h"
57
58 #define ALTQ_DEVICE "/dev/altq/altq"
59 #define RED_DEVICE "/dev/altq/red"
60 #define RIO_DEVICE "/dev/altq/rio"
61 #define CDNR_DEVICE "/dev/altq/cdnr"
62
63 #ifndef LIST_HEAD_INITIALIZER
64 #define LIST_HEAD_INITIALIZER(head) { NULL }
65 #endif
66
67 /*
68 * token bucket regulator information
69 */
70 struct tbrinfo {
71 LIST_ENTRY(tbrinfo) link;
72 char ifname[IFNAMSIZ]; /* if name, e.g. "en0" */
73 struct tb_profile tb_prof, otb_prof;
74 int installed;
75 };
76
77 /*
78 * Static globals
79 */
80 /* a list of configured interfaces */
81 LIST_HEAD(qop_iflist, ifinfo) qop_iflist = LIST_HEAD_INITIALIZER(&iflist);
82 /* a list of configured token bucket regulators */
83 LIST_HEAD(tbr_list, tbrinfo) tbr_list = LIST_HEAD_INITIALIZER(&tbr_list);
84 int Debug_mode = 0; /* nosched (dummy mode) */
85
86 /*
87 * internal functions
88 */
89 static int get_ifmtu(const char *ifname);
90 static void tbr_install(const char *ifname);
91 static void tbr_deinstall(const char *ifname);
92 static int add_filter_rule(struct ifinfo *ifinfo, struct fltrinfo *fltrinfo,
93 struct fltrinfo **conflict);
94 static int remove_filter_rule(struct ifinfo *ifinfo,
95 struct fltrinfo *fltrinfo);
96 static int filt_check_relation(struct flow_filter *front,
97 struct flow_filter *back);
98 static int filt_disjoint(struct flow_filter *front, struct flow_filter *back);
99 static int filt_subset(struct flow_filter *front, struct flow_filter *back);
100
101 /*
102 * QCMD (Queue Command) API
103 */
104 int
105 qcmd_init(void)
106 {
107 int error;
108
109 /* read config file and execute commands */
110 error = qcmd_config();
111
112 if (error == 0)
113 error = qcmd_enableall();
114
115 if (error != 0)
116 LOG(LOG_ERR, errno, "%s: qcmd_init failed.\n",
117 qoperror(error));
118 return (error);
119 }
120
121 int
122 qcmd_enable(const char *ifname)
123 {
124 struct ifinfo *ifinfo;
125 int error = 0;
126
127 if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
128 error = QOPERR_BADIF;
129
130 if (error == 0)
131 error = qop_enable(ifinfo);
132
133 if (error == 0) {
134 LOG(LOG_INFO, 0, "%s enabled on interface %s (mtu:%d)\n",
135 ifinfo->qdisc->qname, ifname, ifinfo->ifmtu);
136 } else
137 LOG(LOG_ERR, errno, "%s: enable failed!\n", qoperror(error));
138 return (error);
139 }
140
141 int
142 qcmd_disable(const char *ifname)
143 {
144 struct ifinfo *ifinfo;
145 int error = 0;
146
147 if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
148 error = QOPERR_BADIF;
149
150 if (error == 0)
151 error = qop_disable(ifinfo);
152
153 if (error != 0)
154 LOG(LOG_ERR, errno, "%s: disable failed!\n", qoperror(error));
155 return (error);
156 }
157
158 int
159 qcmd_enableall()
160 {
161 struct ifinfo *ifinfo;
162 int error;
163
164 LIST_FOREACH(ifinfo, &qop_iflist, next) {
165 if ((error = qop_enable(ifinfo)) != 0)
166 return (error);
167 LOG(LOG_INFO, 0, "%s enabled on interface %s (mtu:%d)\n",
168 ifinfo->qdisc->qname, ifinfo->ifname, ifinfo->ifmtu);
169 }
170 return (0);
171 }
172
173 int
174 qcmd_disableall()
175 {
176 struct ifinfo *ifinfo;
177 int err, error = 0;
178
179 LIST_FOREACH(ifinfo, &qop_iflist, next)
180 if ((err = qop_disable(ifinfo)) != 0)
181 if (error == 0)
182 error = err;
183 return (error);
184 }
185
186 int
187 qcmd_clear(const char *ifname)
188 {
189 struct ifinfo *ifinfo;
190 int error = 0;
191
192 if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
193 error = QOPERR_BADIF;
194
195 if (error == 0)
196 error = qop_clear(ifinfo);
197 if (error != 0)
198 LOG(LOG_ERR, errno, "%s: clear failed!\n", qoperror(error));
199 return (error);
200 }
201
202 int
203 qcmd_destroyall(void)
204 {
205 while (!LIST_EMPTY(&qop_iflist))
206 (void)qop_delete_if(LIST_FIRST(&qop_iflist));
207 return (0);
208 }
209
210 int
211 qcmd_restart(void)
212 {
213 qcmd_destroyall();
214 return qcmd_init();
215 }
216
217 int
218 qcmd_delete_class(const char *ifname, const char *clname)
219 {
220 struct ifinfo *ifinfo;
221 struct classinfo *clinfo;
222 int error = 0;
223
224 if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
225 error = QOPERR_BADIF;
226
227 if (error == 0 &&
228 (clinfo = clname2clinfo(ifinfo, clname)) == NULL)
229 error = QOPERR_BADCLASS;
230
231 if (error == 0)
232 error = qop_delete_class(clinfo);
233 if (error != 0)
234 LOG(LOG_ERR, errno, "%s: delete_class failed\n",
235 qoperror(error));
236 return (error);
237 }
238
239 int
240 qcmd_add_filter(const char *ifname, const char *clname, const char *flname,
241 const struct flow_filter *fltr)
242 {
243 struct ifinfo *ifinfo;
244 struct classinfo *clinfo;
245 int error = 0;
246
247 if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
248 error = QOPERR_BADIF;
249
250 if (error == 0 &&
251 (clinfo = clname2clinfo(ifinfo, clname)) == NULL) {
252 /*
253 * there is no matching class.
254 * check if it is for a traffic conditioner
255 */
256 if ((ifinfo = input_ifname2ifinfo(ifname)) == NULL ||
257 (clinfo = clname2clinfo(ifinfo, clname)) == NULL)
258 error = QOPERR_BADCLASS;
259 }
260
261 if (error == 0)
262 error = qop_add_filter(NULL, clinfo, flname, fltr, NULL);
263
264 if (error != 0)
265 LOG(LOG_ERR, errno, "%s: add filter failed!\n",
266 qoperror(error));
267 else if (IsDebug(DEBUG_ALTQ)) {
268 LOG(LOG_DEBUG, 0, "%s: add a filter %s to class %s\n",
269 ifname, flname ? flname : "(null)",
270 clname ? clname : "(null)");
271 print_filter(fltr);
272 }
273 return (error);
274 }
275
276 int
277 qcmd_delete_filter(const char *ifname, const char *clname, const char *flname)
278 {
279 struct ifinfo *ifinfo;
280 struct classinfo *clinfo;
281 struct fltrinfo *fltrinfo;
282 int error = 0;
283
284 if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
285 error = QOPERR_BADIF;
286
287 if (error == 0 &&
288 (clinfo = clname2clinfo(ifinfo, clname)) == NULL) {
289 /*
290 * there is no matching class.
291 * check if it is for a traffic conditioner
292 */
293 if ((ifinfo = input_ifname2ifinfo(ifname)) == NULL ||
294 (clinfo = clname2clinfo(ifinfo, clname)) == NULL)
295 error = QOPERR_BADCLASS;
296 }
297
298 if (error == 0 &&
299 (fltrinfo = flname2flinfo(clinfo, flname)) == NULL)
300 error = QOPERR_BADFILTER;
301
302 if (error == 0)
303 error = qop_delete_filter(fltrinfo);
304 if (error != 0)
305 LOG(LOG_ERR, errno, "%s: delete filter failed!\n",
306 qoperror(error));
307 return (error);
308 }
309
310 int
311 qcmd_tbr_register(const char *ifname, u_int rate, u_int size)
312 {
313 struct tbrinfo *info;
314
315 if ((info = calloc(1, sizeof(struct tbrinfo))) == NULL)
316 return (QOPERR_NOMEM);
317
318 strcpy(info->ifname, ifname);
319 info->tb_prof.rate = rate;
320 info->tb_prof.depth = size;
321 info->installed = 0;
322 LIST_INSERT_HEAD(&tbr_list, info, link);
323 return (0);
324 }
325
326 /*
327 * QOP (Queue Operation) API
328 */
329
330 int
331 qop_add_if(struct ifinfo **rp, const char *ifname, u_int bandwidth,
332 struct qdisc_ops *qdisc_ops, void *if_private)
333 {
334 struct ifinfo *ifinfo;
335 int error;
336
337 if (ifname2ifinfo(ifname) != NULL) {
338 LOG(LOG_ERR, 0, "qop_add_if: %s already exists!\n", ifname);
339 return (QOPERR_BADIF);
340 }
341
342 if ((ifinfo = calloc(1, sizeof(struct ifinfo))) == NULL)
343 return (QOPERR_NOMEM);
344 ifinfo->ifname = strdup(ifname);
345 ifinfo->bandwidth = bandwidth;
346 ifinfo->enabled = 0;
347 if (ifname[0] == '_')
348 /* input interface */
349 ifname += 1;
350 ifinfo->ifindex = get_ifindex(ifname);
351 ifinfo->ifmtu = get_ifmtu(ifname);
352 if (qdisc_ops == NULL || Debug_mode)
353 ifinfo->qdisc = &nop_qdisc; /* replace syscalls by nops */
354 else
355 ifinfo->qdisc = qdisc_ops;
356 ifinfo->private = if_private;
357 LIST_INIT(&ifinfo->cllist);
358 LIST_INIT(&ifinfo->fltr_rules);
359
360 /* Link the interface info structure */
361 LIST_INSERT_HEAD(&qop_iflist, ifinfo, next);
362
363 /* install token bucket regulator, if necessary */
364 tbr_install(ifname);
365
366 /* attach the discipline to the interface */
367 if ((error = (*ifinfo->qdisc->attach)(ifinfo)) != 0)
368 goto err_ret;
369
370 /* disable and clear the interface */
371 if (ifinfo->qdisc->disable != NULL)
372 if ((error = (*ifinfo->qdisc->disable)(ifinfo)) != 0)
373 goto err_ret;
374 if (ifinfo->qdisc->clear != NULL)
375 if ((error = (*ifinfo->qdisc->clear)(ifinfo)) != 0)
376 goto err_ret;
377
378 if (rp != NULL)
379 *rp = ifinfo;
380 return (0);
381
382 err_ret:
383 if (ifinfo != NULL) {
384 LIST_REMOVE(ifinfo, next);
385 if (ifinfo->ifname != NULL)
386 free(ifinfo->ifname);
387 free(ifinfo);
388 }
389 return (error);
390 }
391
392 int
393 qop_delete_if(struct ifinfo *ifinfo)
394 {
395 (void)qop_disable(ifinfo);
396 (void)qop_clear(ifinfo);
397
398 if (ifinfo->delete_hook != NULL)
399 (*ifinfo->delete_hook)(ifinfo);
400
401 /* remove this entry from qop_iflist */
402 LIST_REMOVE(ifinfo, next);
403
404 (void)(*ifinfo->qdisc->detach)(ifinfo);
405
406 /* deinstall token bucket regulator, if necessary */
407 tbr_deinstall(ifinfo->ifname);
408
409 if (ifinfo->private != NULL)
410 free(ifinfo->private);
411 if (ifinfo->ifname != NULL)
412 free(ifinfo->ifname);
413 free(ifinfo);
414 return (0);
415 }
416
417 int
418 qop_enable(struct ifinfo *ifinfo)
419 {
420 int error;
421
422 if (ifinfo->enable_hook != NULL)
423 if ((error = (*ifinfo->enable_hook)(ifinfo)) != 0)
424 return (error);
425
426 if (ifinfo->qdisc->enable != NULL)
427 if ((error = (*ifinfo->qdisc->enable)(ifinfo)) != 0)
428 return (error);
429 ifinfo->enabled = 1;
430 return (0);
431 }
432
433 int
434 qop_disable(struct ifinfo *ifinfo)
435 {
436 int error;
437
438 if (ifinfo->qdisc->disable != NULL)
439 if ((error = (*ifinfo->qdisc->disable)(ifinfo)) != 0)
440 return (error);
441 ifinfo->enabled = 0;
442 return (0);
443 }
444
445 int
446 qop_clear(struct ifinfo *ifinfo)
447 {
448 struct classinfo *clinfo;
449
450 /* free all classes and filters */
451 if (ifinfo->ifname[0] != '_') {
452 /* output interface. delete from leaf classes */
453 while (!LIST_EMPTY(&ifinfo->cllist)) {
454 LIST_FOREACH(clinfo, &ifinfo->cllist, next) {
455 if (clinfo->child != NULL)
456 continue;
457 qop_delete_class(clinfo);
458 /*
459 * the list has been changed,
460 * restart from the head
461 */
462 break;
463 }
464 }
465 } else {
466 /* input interface. delete from parents */
467 struct classinfo *root = get_rootclass(ifinfo);
468
469 while (!LIST_EMPTY(&ifinfo->cllist)) {
470 LIST_FOREACH(clinfo, &ifinfo->cllist, next)
471 if (clinfo->parent == root) {
472 qop_delete_cdnr(clinfo);
473 break;
474 }
475 if (root->child == NULL)
476 qop_delete_class(root);
477 }
478 }
479
480 /* clear the interface */
481 if (ifinfo->qdisc->clear != NULL)
482 return (*ifinfo->qdisc->clear)(ifinfo);
483 return (0);
484 }
485
486 int
487 qop_add_class(struct classinfo **rp, const char *clname,
488 struct ifinfo *ifinfo, struct classinfo *parent,
489 void *class_private)
490 {
491 struct classinfo *clinfo;
492 int error;
493
494 if ((clinfo = calloc(1, sizeof(*clinfo))) == NULL)
495 return (QOPERR_NOMEM);
496
497 if (clname != NULL)
498 clinfo->clname = strdup(clname);
499 else
500 clinfo->clname = strdup("(null)"); /* dummy name */
501 clinfo->ifinfo = ifinfo;
502 clinfo->private = class_private;
503 clinfo->parent = parent;
504 clinfo->child = NULL;
505 LIST_INIT(&clinfo->fltrlist);
506
507 if ((error = (*ifinfo->qdisc->add_class)(clinfo)) != 0)
508 goto err_ret;
509
510 /* link classinfo in lists */
511 LIST_INSERT_HEAD(&ifinfo->cllist, clinfo, next);
512
513 if (parent != NULL) {
514 clinfo->sibling = parent->child;
515 clinfo->parent->child = clinfo;
516 }
517
518 if (rp != NULL)
519 *rp = clinfo;
520 return (0);
521
522 err_ret:
523 if (clinfo != NULL) {
524 if (clinfo->clname != NULL)
525 free(clinfo->clname);
526 free(clinfo);
527 }
528 return (error);
529 }
530
531 int
532 qop_modify_class(struct classinfo *clinfo, void *arg)
533 {
534 return (*clinfo->ifinfo->qdisc->modify_class)(clinfo, arg);
535 }
536
537 int
538 qop_delete_class(struct classinfo *clinfo)
539 {
540 struct ifinfo *ifinfo = clinfo->ifinfo;
541 struct classinfo *prev;
542 int error;
543
544 /* a class to be removed should not have a child */
545 if (clinfo->child != NULL)
546 return (QOPERR_CLASS_PERM);
547
548 /* remove filters associated to this class */
549 while (!LIST_EMPTY(&clinfo->fltrlist))
550 (void)qop_delete_filter(LIST_FIRST(&clinfo->fltrlist));
551
552 if (clinfo->delete_hook != NULL)
553 (*clinfo->delete_hook)(clinfo);
554
555 /* remove class info from the interface */
556 LIST_REMOVE(clinfo, next);
557
558 /* remove this class from the child list */
559 if (clinfo->parent != NULL) {
560 if (clinfo->parent->child == clinfo)
561 clinfo->parent->child = clinfo->sibling;
562 else for (prev = clinfo->parent->child; prev->sibling != NULL;
563 prev = prev->sibling)
564 if (prev->sibling == clinfo) {
565 prev->sibling = clinfo->sibling;
566 break;
567 }
568 }
569
570 /* delete class from kernel */
571 if ((error = (*ifinfo->qdisc->delete_class)(clinfo)) != 0)
572 return (error);
573
574 if (clinfo->private != NULL)
575 free(clinfo->private);
576 if (clinfo->clname != NULL)
577 free(clinfo->clname);
578 free(clinfo);
579 return (0);
580 }
581
582 int
583 qop_add_filter(struct fltrinfo **rp, struct classinfo *clinfo,
584 const char *flname, const struct flow_filter *fltr,
585 struct fltrinfo **conflict)
586 {
587 struct ifinfo *ifinfo;
588 struct fltrinfo *fltrinfo;
589 int error;
590
591 if ((fltrinfo = calloc(1, sizeof(*fltrinfo))) == NULL)
592 return (QOPERR_NOMEM);
593
594 fltrinfo->clinfo = clinfo;
595 fltrinfo->fltr = *fltr;
596 #if 1
597 /* fix this */
598 fltrinfo->line_no = line_no; /* XXX */
599 fltrinfo->dontwarn = filter_dontwarn; /* XXX */
600 #endif
601 if (flname != NULL)
602 fltrinfo->flname = strdup(flname);
603 else
604 fltrinfo->flname = strdup("(null)"); /* dummy name */
605
606 /* check and save the filter */
607 ifinfo = clinfo->ifinfo;
608 if ((error = add_filter_rule(ifinfo, fltrinfo, conflict)) != 0)
609 goto err_ret;
610
611 /* install the filter to the kernel */
612 if ((error = (*ifinfo->qdisc->add_filter)(fltrinfo)) != 0) {
613 remove_filter_rule(ifinfo, fltrinfo);
614 goto err_ret;
615 }
616
617 /* link fltrinfo onto fltrlist of the class */
618 LIST_INSERT_HEAD(&clinfo->fltrlist, fltrinfo, next);
619
620 if (rp != NULL)
621 *rp = fltrinfo;
622 return (0);
623
624 err_ret:
625 if (fltrinfo != NULL) {
626 if (fltrinfo->flname != NULL)
627 free(fltrinfo->flname);
628 free(fltrinfo);
629 }
630 return (error);
631 }
632
633 int
634 qop_delete_filter(struct fltrinfo *fltrinfo)
635 {
636 struct ifinfo *ifinfo;
637 struct classinfo *clinfo;
638 int error;
639
640 /* remove filter info from the class */
641 clinfo = fltrinfo->clinfo;
642 ifinfo = clinfo->ifinfo;
643
644
645 /* remove the entry from fltrlist of the class */
646 LIST_REMOVE(fltrinfo, next);
647
648 remove_filter_rule(ifinfo, fltrinfo);
649
650 /* delete filter from kernel */
651 if ((error = (*ifinfo->qdisc->delete_filter)(fltrinfo)) != 0)
652 return (error);
653
654 if (fltrinfo->flname)
655 free(fltrinfo->flname);
656 free(fltrinfo);
657 return (0);
658 }
659
660 const char *
661 qoperror(int qoperrno)
662 {
663 static char buf[64];
664
665 if (qoperrno <= QOPERR_MAX)
666 return (qop_errlist[qoperrno]);
667 sprintf(buf, "unknown error %d", qoperrno);
668 return (buf);
669 }
670
671 /*
672 * misc functions
673 */
674 struct ifinfo *
675 ifname2ifinfo(const char *ifname)
676 {
677 struct ifinfo *ifinfo;
678
679 LIST_FOREACH(ifinfo, &qop_iflist, next)
680 if (ifinfo->ifname != NULL &&
681 strcmp(ifinfo->ifname, ifname) == 0)
682 return (ifinfo);
683 return (NULL);
684 }
685
686 struct ifinfo *
687 input_ifname2ifinfo(const char *ifname)
688 {
689 struct ifinfo *ifinfo;
690
691 LIST_FOREACH(ifinfo, &qop_iflist, next)
692 if (ifinfo->ifname[0] == '_' &&
693 strcmp(ifinfo->ifname+1, ifname) == 0)
694 return (ifinfo);
695 return (NULL);
696 }
697
698 struct classinfo *
699 clname2clinfo(const struct ifinfo *ifinfo, const char *clname)
700 {
701 struct classinfo *clinfo;
702
703 LIST_FOREACH(clinfo, &ifinfo->cllist, next)
704 if (clinfo->clname != NULL &&
705 strcmp(clinfo->clname, clname) == 0)
706 return (clinfo);
707 return (NULL);
708 }
709
710 struct classinfo *
711 clhandle2clinfo(struct ifinfo *ifinfo, u_long handle)
712 {
713 struct classinfo *clinfo;
714
715 LIST_FOREACH(clinfo, &ifinfo->cllist, next)
716 if (clinfo->handle == handle)
717 return (clinfo);
718 return (NULL);
719 }
720
721 struct fltrinfo *
722 flname2flinfo(const struct classinfo *clinfo, const char *flname)
723 {
724 struct fltrinfo *fltrinfo;
725
726 LIST_FOREACH(fltrinfo, &clinfo->fltrlist, next)
727 if (fltrinfo->flname != NULL &&
728 strcmp(fltrinfo->flname, flname) == 0)
729 return (fltrinfo);
730 return (NULL);
731 }
732
733 struct fltrinfo *
734 flhandle2fltrinfo(struct ifinfo *ifinfo, u_long handle)
735 {
736 struct fltrinfo *fltrinfo;
737
738 LIST_FOREACH(fltrinfo, &ifinfo->fltr_rules, nextrule)
739 if (fltrinfo->handle == handle)
740 return (fltrinfo);
741 return (NULL);
742 }
743
744 int
745 is_q_enabled(const char *ifname)
746 {
747 struct ifinfo *ifinfo;
748
749 if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
750 return (0);
751 return (ifinfo->enabled);
752 }
753
754 /*
755 * functions to walk through a class tree:
756 *
757 * for (clinfo = get_rootclass(ifinfo);
758 * clinfo != NULL; clinfo = get_nextclass(clinfo)) {
759 * do_something;
760 * }
761 */
762 struct classinfo *get_rootclass(struct ifinfo *ifinfo)
763 {
764 struct classinfo *clinfo;
765
766 /* find a class without parent */
767 LIST_FOREACH(clinfo, &ifinfo->cllist, next)
768 if (clinfo->parent == NULL)
769 return (clinfo);
770 return (NULL);
771 }
772
773 /* return next class in the tree */
774 struct classinfo *get_nextclass(struct classinfo *clinfo)
775 {
776 struct classinfo *next;
777
778 if (clinfo->child != NULL)
779 next = clinfo->child;
780 else if (clinfo->sibling != NULL)
781 next = clinfo->sibling;
782 else {
783 next = clinfo;
784 while ((next = next->parent) != NULL)
785 if (next->sibling) {
786 next = next->sibling;
787 break;
788 }
789 }
790 return (next);
791 }
792
793 u_long
794 atobps(const char *s)
795 {
796 u_long bandwidth;
797 char *cp;
798
799 bandwidth = strtoul(s, &cp, 0);
800 if (cp != NULL) {
801 if (*cp == 'K' || *cp == 'k')
802 bandwidth *= 1000;
803 else if (*cp == 'M' || *cp == 'm')
804 bandwidth *= 1000000;
805 else if (*cp == 'G' || *cp == 'g')
806 bandwidth *= 1000000000;
807 }
808 return (bandwidth);
809 }
810
811 u_long
812 atobytes(const char *s)
813 {
814 u_long bytes;
815 char *cp;
816
817 bytes = strtoul(s, &cp, 0);
818 if (cp != NULL) {
819 if (*cp == 'K' || *cp == 'k')
820 bytes *= 1024;
821 else if (*cp == 'M' || *cp == 'm')
822 bytes *= 1024 * 1024;
823 else if (*cp == 'G' || *cp == 'g')
824 bytes *= 1024 * 1024 * 1024;
825 }
826 return (bytes);
827 }
828
829 static int
830 get_ifmtu(const char *ifname)
831 {
832 int s, mtu;
833 struct ifreq ifr;
834 #ifdef __OpenBSD__
835 struct if_data ifdata;
836 #endif
837
838 mtu = 512; /* default MTU */
839
840 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
841 return (mtu);
842 strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
843 #ifdef __OpenBSD__
844 ifr.ifr_data = (caddr_t)&ifdata;
845 if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == 0)
846 mtu = ifdata.ifi_mtu;
847 #else
848 if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0)
849 mtu = ifr.ifr_mtu;
850 #endif
851 close(s);
852 return (mtu);
853 }
854
855 static void
856 tbr_install(const char *ifname)
857 {
858 struct tbrinfo *info;
859 struct tbrreq req;
860 int fd;
861
862 LIST_FOREACH(info, &tbr_list, link)
863 if (strcmp(info->ifname, ifname) == 0)
864 break;
865 if (info == NULL)
866 return;
867 if (info->tb_prof.rate == 0 || info->installed)
868 return;
869
870 /* get the current token bucket regulator */
871 if ((fd = open(ALTQ_DEVICE, O_RDWR)) < 0)
872 err(1, "can't open altq device");
873 strncpy(req.ifname, ifname, IFNAMSIZ-1);
874 if (ioctl(fd, ALTQTBRGET, &req) < 0)
875 err(1, "ALTQTBRGET for interface %s", req.ifname);
876
877 /* save the current values */
878 info->otb_prof.rate = req.tb_prof.rate;
879 info->otb_prof.depth = req.tb_prof.depth;
880
881 /*
882 * if tbr is not specified in the config file and tbr is already
883 * configured, do not change.
884 */
885 if (req.tb_prof.rate != 0) {
886 LOG(LOG_INFO, 0,
887 "tbr is already installed on %s,\n"
888 " using the current setting (rate:%.2fM size:%.2fK).\n",
889 info->ifname,
890 (double)req.tb_prof.rate/1000000.0,
891 (double)req.tb_prof.depth/1024.0);
892 close (fd);
893 return;
894 }
895
896 /* if the new size is not specified, use heuristics */
897 if (info->tb_prof.depth == 0) {
898 u_int rate, size;
899
900 rate = info->tb_prof.rate;
901 if (rate <= 1*1000*1000)
902 size = 1;
903 else if (rate <= 10*1000*1000)
904 size = 4;
905 else if (rate <= 200*1000*1000)
906 size = 8;
907 else
908 size = 24;
909 size = size * 1500; /* assume the default mtu is 1500 */
910 info->tb_prof.depth = size;
911 }
912
913 /* install the new tbr */
914 strncpy(req.ifname, ifname, IFNAMSIZ-1);
915 req.tb_prof.rate = info->tb_prof.rate;
916 req.tb_prof.depth = info->tb_prof.depth;
917 if (ioctl(fd, ALTQTBRSET, &req) < 0)
918 err(1, "ALTQTBRSET for interface %s", req.ifname);
919 LOG(LOG_INFO, 0,
920 "tbr installed on %s (rate:%.2fM size:%.2fK)\n",
921 info->ifname,
922 (double)info->tb_prof.rate/1000000.0,
923 (double)info->tb_prof.depth/1024.0);
924 close(fd);
925 info->installed = 1;
926 }
927
928 static void
929 tbr_deinstall(const char *ifname)
930 {
931 struct tbrinfo *info;
932 struct tbrreq req;
933 int fd;
934
935 LIST_FOREACH(info, &tbr_list, link)
936 if (strcmp(info->ifname, ifname) == 0)
937 break;
938 if (info == NULL)
939 return;
940
941 /* if we installed tbr, restore the old values */
942 if (info->installed != 0) {
943 strncpy(req.ifname, ifname, IFNAMSIZ-1);
944 req.tb_prof.rate = info->otb_prof.rate;
945 req.tb_prof.depth = info->otb_prof.depth;
946 if ((fd = open(ALTQ_DEVICE, O_RDWR)) < 0)
947 err(1, "can't open altq device");
948 if (ioctl(fd, ALTQTBRSET, &req) < 0)
949 err(1, "ALTQTBRSET for interface %s", req.ifname);
950 close(fd);
951 }
952 LIST_REMOVE(info, link);
953 free(info);
954 }
955
956 void
957 print_filter(const struct flow_filter *filt)
958 {
959 if (filt->ff_flow.fi_family == AF_INET) {
960 struct in_addr in_addr;
961
962 in_addr.s_addr = filt->ff_flow.fi_dst.s_addr;
963 LOG(LOG_DEBUG, 0,
964 " Filter Dest Addr: %s (mask %#x) Port: %d\n",
965 inet_ntoa(in_addr), ntoh32(filt->ff_mask.mask_dst.s_addr),
966 ntoh16(filt->ff_flow.fi_dport));
967 in_addr.s_addr = filt->ff_flow.fi_src.s_addr;
968 LOG(LOG_DEBUG, 0,
969 " Src Addr: %s (mask %#x) Port: %d\n",
970 inet_ntoa(in_addr), ntoh32(filt->ff_mask.mask_src.s_addr),
971 ntoh16(filt->ff_flow.fi_sport));
972 LOG(LOG_DEBUG, 0, " Protocol: %d TOS %#x (mask %#x)\n",
973 filt->ff_flow.fi_proto, filt->ff_flow.fi_tos,
974 filt->ff_mask.mask_tos);
975 }
976 #ifdef INET6
977 else if (filt->ff_flow.fi_family == AF_INET6) {
978 char str1[INET6_ADDRSTRLEN], str2[INET6_ADDRSTRLEN];
979 const struct flow_filter6 *sfilt6;
980
981 sfilt6 = (const struct flow_filter6 *)filt;
982 LOG(LOG_DEBUG, 0, "Filter6 Dest Addr: %s (mask %s) Port: %d",
983 inet_ntop(AF_INET6, &sfilt6->ff_flow6.fi6_dst,
984 str1, sizeof(str1)),
985 inet_ntop(AF_INET6, &sfilt6->ff_mask6.mask6_dst,
986 str2, sizeof(str2)),
987 ntoh16(sfilt6->ff_flow6.fi6_dport));
988 LOG(LOG_DEBUG, 0, " Src Addr: %s (mask %s) Port: %d",
989 inet_ntop(AF_INET6, &sfilt6->ff_flow6.fi6_src,
990 str1, sizeof(str1)),
991 inet_ntop(AF_INET6, &sfilt6->ff_mask6.mask6_src,
992 str2, sizeof(str2)),
993 ntoh16(sfilt6->ff_flow6.fi6_sport));
994 LOG(LOG_DEBUG, 0, " Protocol: %d TCLASS %#x (mask %#x)\n",
995 sfilt6->ff_flow6.fi6_proto, sfilt6->ff_flow6.fi6_tclass,
996 sfilt6->ff_mask6.mask6_tclass);
997 }
998 #endif /* INET6 */
999 }
1000
1001 /*
1002 * functions to check the filter-rules.
1003 * when a new filter is added, we check the relation to the existing filters
1004 * and if some inconsistency is found, produce an error or a warning message.
1005 *
1006 * filter matching is performed from the head of the list.
1007 * let
1008 * S: a set of packets that filter s matches
1009 * T: a set of packets that filter t matches
1010 * filter relations are:
1011 * disjoint: S ^ T = empty
1012 * subset: S <= T
1013 * intersect: S ^ T = not empty
1014 *
1015 * a new filter is disjoint or subset of the existing filters --> ok
1016 * a new filter is superset of an existing filter --> order problem
1017 * a new filter intersect an existing filter --> warning
1018 *
1019 * port-intersect: a special case we don't make warning
1020 * - intersection is only port numbers
1021 * - one specifies src port and the other specifies dst port
1022 * there must be no packet with well-known port numbers in
1023 * both src and dst ports. so this is ok.
1024 */
1025
1026 #define FILT_DISJOINT 1
1027 #define FILT_SUBSET 2
1028 #define FILT_SUPERSET 3
1029 #define FILT_INTERSECT 4
1030 #define FILT_PORTINTERSECT 5
1031
1032 static int
1033 add_filter_rule(struct ifinfo *ifinfo, struct fltrinfo *fltrinfo,
1034 struct fltrinfo **conflict)
1035 {
1036 struct fltrinfo *fp, *front, *back, *prev = NULL;
1037 int relation;
1038
1039 LIST_FOREACH(fp, &ifinfo->fltr_rules, nextrule) {
1040 if (fp->fltr.ff_ruleno > fltrinfo->fltr.ff_ruleno) {
1041 front = fp;
1042 back = fltrinfo;
1043 prev = fp;
1044 } else {
1045 front = fltrinfo;
1046 back = fp;
1047 }
1048
1049 relation = filt_check_relation(&front->fltr, &back->fltr);
1050
1051 switch (relation) {
1052 case FILT_SUBSET:
1053 case FILT_DISJOINT:
1054 /* OK */
1055 break;
1056 case FILT_SUPERSET:
1057 if (front->dontwarn == 0 && back->dontwarn == 0)
1058 LOG(LOG_ERR, 0,
1059 "filters for \"%s\" at line %d and for \"%s\" at line %d has an order problem!\n",
1060 front->clinfo->clname, front->line_no,
1061 back->clinfo->clname, back->line_no);
1062
1063 if (conflict != NULL)
1064 *conflict = fp;
1065 return (QOPERR_FILTER_SHADOW);
1066 case FILT_PORTINTERSECT:
1067 break;
1068 case FILT_INTERSECT:
1069 /*
1070 * if the intersecting two filters beloging to the
1071 * same class, it's ok.
1072 */
1073 if (front->clinfo == back->clinfo)
1074 break;
1075 if (front->dontwarn == 0 && back->dontwarn == 0)
1076 LOG(LOG_WARNING, 0,
1077 "warning: filter for \"%s\" at line %d could override filter for \"%s\" at line %d\n",
1078 front->clinfo->clname, front->line_no,
1079 back->clinfo->clname, back->line_no);
1080 break;
1081 }
1082 }
1083
1084 if (prev == NULL)
1085 LIST_INSERT_HEAD(&ifinfo->fltr_rules, fltrinfo, nextrule);
1086 else
1087 LIST_INSERT_AFTER(prev, fltrinfo, nextrule);
1088 return (0);
1089 }
1090
1091 static int
1092 remove_filter_rule(struct ifinfo *ifinfo, struct fltrinfo *fltrinfo)
1093 {
1094 LIST_REMOVE(fltrinfo, nextrule);
1095 return (0);
1096 }
1097
1098 static int
1099 filt_check_relation(struct flow_filter *front, struct flow_filter *back)
1100 {
1101 int rval;
1102
1103 if (front->ff_flow.fi_family != back->ff_flow.fi_family)
1104 return (FILT_DISJOINT);
1105
1106 if (filt_disjoint(front, back))
1107 return (FILT_DISJOINT);
1108
1109 if ((rval = filt_subset(front, back)) == 1)
1110 return (FILT_SUBSET);
1111
1112 if (filt_subset(back, front) == 1)
1113 return (FILT_SUPERSET);
1114
1115 if (rval == 2)
1116 return (FILT_PORTINTERSECT);
1117
1118 return (FILT_INTERSECT);
1119 }
1120
1121 static int
1122 filt_disjoint(struct flow_filter *front, struct flow_filter *back)
1123 {
1124 u_int32_t mask;
1125 u_int8_t tosmask;
1126
1127 if (front->ff_flow.fi_family == AF_INET) {
1128 if (front->ff_flow.fi_proto != 0 && back->ff_flow.fi_proto != 0
1129 && front->ff_flow.fi_proto != back->ff_flow.fi_proto)
1130 return (1);
1131 if (front->ff_flow.fi_sport != 0 && back->ff_flow.fi_sport != 0
1132 && front->ff_flow.fi_sport != back->ff_flow.fi_sport)
1133 return (1);
1134 if (front->ff_flow.fi_dport != 0 && back->ff_flow.fi_dport != 0
1135 && front->ff_flow.fi_dport != back->ff_flow.fi_dport)
1136 return (1);
1137 if (front->ff_flow.fi_gpi != 0 && back->ff_flow.fi_gpi != 0
1138 && front->ff_flow.fi_gpi != back->ff_flow.fi_gpi)
1139 return (1);
1140 if (front->ff_flow.fi_src.s_addr != 0 &&
1141 back->ff_flow.fi_src.s_addr != 0) {
1142 mask = front->ff_mask.mask_src.s_addr &
1143 back->ff_mask.mask_src.s_addr;
1144 if ((front->ff_flow.fi_src.s_addr & mask) !=
1145 (back->ff_flow.fi_src.s_addr & mask))
1146 return (1);
1147 }
1148 if (front->ff_flow.fi_dst.s_addr != 0 &&
1149 back->ff_flow.fi_dst.s_addr != 0) {
1150 mask = front->ff_mask.mask_dst.s_addr &
1151 back->ff_mask.mask_dst.s_addr;
1152 if ((front->ff_flow.fi_dst.s_addr & mask) !=
1153 (back->ff_flow.fi_dst.s_addr & mask))
1154 return (1);
1155 }
1156 if (front->ff_flow.fi_tos != 0 && back->ff_flow.fi_tos != 0) {
1157 tosmask = front->ff_mask.mask_tos &
1158 back->ff_mask.mask_tos;
1159 if ((front->ff_flow.fi_tos & tosmask) !=
1160 (back->ff_flow.fi_tos & tosmask))
1161 return (1);
1162 }
1163 return (0);
1164 }
1165 #ifdef INET6
1166 else if (front->ff_flow.fi_family == AF_INET6) {
1167 struct flow_filter6 *front6, *back6;
1168 int i;
1169
1170 front6 = (struct flow_filter6 *)front;
1171 back6 = (struct flow_filter6 *)back;
1172
1173 if (front6->ff_flow6.fi6_proto != 0 &&
1174 back6->ff_flow6.fi6_proto != 0 &&
1175 front6->ff_flow6.fi6_proto != back6->ff_flow6.fi6_proto)
1176 return (1);
1177 if (front6->ff_flow6.fi6_flowlabel != 0 &&
1178 back6->ff_flow6.fi6_flowlabel != 0 &&
1179 front6->ff_flow6.fi6_flowlabel !=
1180 back6->ff_flow6.fi6_flowlabel)
1181 return (1);
1182 if (front6->ff_flow6.fi6_sport != 0 &&
1183 back6->ff_flow6.fi6_sport != 0 &&
1184 front6->ff_flow6.fi6_sport != back6->ff_flow6.fi6_sport)
1185 return (1);
1186 if (front6->ff_flow6.fi6_dport != 0 &&
1187 back6->ff_flow6.fi6_dport != 0 &&
1188 front6->ff_flow6.fi6_dport != back6->ff_flow6.fi6_dport)
1189 return (1);
1190 if (front6->ff_flow6.fi6_gpi != 0 &&
1191 back6->ff_flow6.fi6_gpi != 0 &&
1192 front6->ff_flow6.fi6_gpi != back6->ff_flow6.fi6_gpi)
1193 return (1);
1194 if (!IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_src) &&
1195 !IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src)) {
1196 for (i=0; i<4; i++) {
1197 mask = IN6ADDR32(&front6->ff_mask6.mask6_src, i)
1198 & IN6ADDR32(&back6->ff_mask6.mask6_src, i);
1199 if ((IN6ADDR32(&front6->ff_flow6.fi6_src, i) & mask) !=
1200 (IN6ADDR32(&back6->ff_flow6.fi6_src, i) & mask))
1201 return (1);
1202 }
1203 }
1204 if (!IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_dst) &&
1205 !IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst)) {
1206 for (i=0; i<4; i++) {
1207 mask = IN6ADDR32(&front6->ff_mask6.mask6_dst, i)
1208 & IN6ADDR32(&back6->ff_mask6.mask6_dst, i);
1209 if ((IN6ADDR32(&front6->ff_flow6.fi6_dst, i) & mask) !=
1210 (IN6ADDR32(&back6->ff_flow6.fi6_dst, i) & mask))
1211 return (1);
1212 }
1213 }
1214 if (front6->ff_flow6.fi6_tclass != 0 &&
1215 back6->ff_flow6.fi6_tclass != 0) {
1216 tosmask = front6->ff_mask6.mask6_tclass &
1217 back6->ff_mask6.mask6_tclass;
1218 if ((front6->ff_flow6.fi6_tclass & tosmask) !=
1219 (back6->ff_flow6.fi6_tclass & tosmask))
1220 return (1);
1221 }
1222 return (0);
1223 }
1224 #endif /* INET6 */
1225 return (0);
1226 }
1227
1228 /*
1229 * check if "front" is a subset of "back". assumes they are not disjoint
1230 * return value 0: not a subset
1231 * 1: subset
1232 * 2: subset except src & dst ports
1233 * (possible port-intersect)
1234 */
1235 static int
1236 filt_subset(struct flow_filter *front, struct flow_filter *back)
1237 {
1238 u_int16_t srcport, dstport;
1239
1240 if (front->ff_flow.fi_family == AF_INET) {
1241 if (front->ff_flow.fi_proto == 0 &&
1242 back->ff_flow.fi_proto != 0)
1243 return (0);
1244 if (front->ff_flow.fi_gpi == 0 && back->ff_flow.fi_gpi != 0)
1245 return (0);
1246 if (front->ff_flow.fi_src.s_addr == 0) {
1247 if (back->ff_flow.fi_src.s_addr != 0)
1248 return (0);
1249 } else if (back->ff_flow.fi_src.s_addr != 0 &&
1250 (~front->ff_mask.mask_src.s_addr &
1251 back->ff_mask.mask_src.s_addr))
1252 return (0);
1253 if (front->ff_flow.fi_dst.s_addr == 0) {
1254 if (back->ff_flow.fi_dst.s_addr != 0)
1255 return (0);
1256 } else if (back->ff_flow.fi_dst.s_addr != 0 &&
1257 (~front->ff_mask.mask_dst.s_addr &
1258 back->ff_mask.mask_dst.s_addr))
1259 return (0);
1260 if (~front->ff_mask.mask_tos & back->ff_mask.mask_tos)
1261 return (0);
1262
1263 if (front->ff_flow.fi_sport == 0 &&
1264 back->ff_flow.fi_sport != 0) {
1265 srcport = ntohs(back->ff_flow.fi_sport);
1266 dstport = ntohs(front->ff_flow.fi_dport);
1267 if (dstport > 0 /* && dstport < 1024 */ &&
1268 srcport > 0 /* && srcport < 1024 */)
1269 return (2);
1270 return (0);
1271 }
1272 if (front->ff_flow.fi_dport == 0 &&
1273 back->ff_flow.fi_dport != 0) {
1274 dstport = ntohs(back->ff_flow.fi_dport);
1275 srcport = ntohs(front->ff_flow.fi_sport);
1276 if (srcport > 0 /* && srcport < 1024 */ &&
1277 dstport > 0 /* && dstport < 1024 */)
1278 return (2);
1279 return (0);
1280 }
1281
1282 return (1);
1283 }
1284 #ifdef INET6
1285 else if (front->ff_flow.fi_family == AF_INET6) {
1286 struct flow_filter6 *front6, *back6;
1287 int i;
1288
1289 front6 = (struct flow_filter6 *)front;
1290 back6 = (struct flow_filter6 *)back;
1291
1292 if (front6->ff_flow6.fi6_proto == 0 &&
1293 back6->ff_flow6.fi6_proto != 0)
1294 return (0);
1295 if (front6->ff_flow6.fi6_flowlabel == 0 &&
1296 back6->ff_flow6.fi6_flowlabel != 0)
1297 return (0);
1298 if (front6->ff_flow6.fi6_gpi == 0 &&
1299 back6->ff_flow6.fi6_gpi != 0)
1300 return (0);
1301
1302 if (IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_src)) {
1303 if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src))
1304 return (0);
1305 } else if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src))
1306 for (i=0; i<4; i++)
1307 if (~IN6ADDR32(&front6->ff_mask6.mask6_src, i) &
1308 IN6ADDR32(&back6->ff_mask6.mask6_src, i))
1309 return (0);
1310 if (IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_dst)) {
1311 if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst))
1312 return (0);
1313 } else if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst))
1314 for (i=0; i<4; i++)
1315 if (~IN6ADDR32(&front6->ff_mask6.mask6_dst, i) &
1316 IN6ADDR32(&back6->ff_mask6.mask6_dst, i))
1317 return (0);
1318
1319 if (~front6->ff_mask6.mask6_tclass &
1320 back6->ff_mask6.mask6_tclass)
1321 return (0);
1322
1323 if (front6->ff_flow6.fi6_sport == 0 &&
1324 back6->ff_flow6.fi6_sport != 0) {
1325 srcport = ntohs(back6->ff_flow6.fi6_sport);
1326 dstport = ntohs(front6->ff_flow6.fi6_dport);
1327 if (dstport > 0 /* && dstport < 1024 */ &&
1328 srcport > 0 /* && srcport < 1024 */)
1329 return (2);
1330 return (0);
1331 }
1332 if (front6->ff_flow6.fi6_dport == 0 &&
1333 back6->ff_flow6.fi6_dport != 0) {
1334 dstport = ntohs(back6->ff_flow6.fi6_dport);
1335 srcport = ntohs(front6->ff_flow6.fi6_sport);
1336 if (srcport > 0 /* && srcport < 1024 */ &&
1337 dstport > 0 /* && dstport < 1024 */)
1338 return (2);
1339 return (0);
1340 }
1341 }
1342 #endif /* INET6 */
1343 return (1);
1344 }
1345
1346
1347 /*
1348 * setting RED or RIO default parameters
1349 */
1350 int
1351 qop_red_set_defaults(int th_min, int th_max, int inv_pmax)
1352 {
1353 struct redparams params;
1354 int fd;
1355
1356 if ((fd = open(RED_DEVICE, O_RDWR)) < 0) {
1357 LOG(LOG_ERR, errno, "RED open\n");
1358 return (QOPERR_SYSCALL);
1359 }
1360
1361 params.th_min = th_min;
1362 params.th_max = th_max;
1363 params.inv_pmax = inv_pmax;
1364
1365 if (ioctl(fd, RED_SETDEFAULTS, ¶ms) < 0) {
1366 LOG(LOG_ERR, errno, "RED_SETDEFAULTS\n");
1367 return (QOPERR_SYSCALL);
1368 }
1369
1370 (void)close(fd);
1371 return (0);
1372 }
1373
1374 int
1375 qop_rio_set_defaults(struct redparams *params)
1376 {
1377 int i, fd;
1378
1379 /* sanity check */
1380 for (i = 1; i < RIO_NDROPPREC; i++) {
1381 if (params[i].th_max > params[i-1].th_min)
1382 LOG(LOG_WARNING, 0,
1383 "warning: overlap found in RIO thresholds\n");
1384 }
1385
1386 if ((fd = open(RIO_DEVICE, O_RDWR)) < 0) {
1387 LOG(LOG_ERR, errno, "RIO open\n");
1388 return (QOPERR_SYSCALL);
1389 }
1390
1391 if (ioctl(fd, RIO_SETDEFAULTS, params) < 0) {
1392 LOG(LOG_ERR, errno, "RIO_SETDEFAULTS\n");
1393 return (QOPERR_SYSCALL);
1394 }
1395
1396 (void)close(fd);
1397 return (0);
1398 }
1399
1400 /*
1401 * try to load and open KLD module
1402 */
1403 int
1404 open_module(const char *devname, int flags)
1405 {
1406 #if defined(__FreeBSD__) && (__FreeBSD_version > 300000)
1407 char modname[64], filename[256], *cp;
1408 int fd;
1409 struct stat sbuf;
1410
1411 /* turn discipline name into module name */
1412 strcpy(modname, "altq_");
1413 if ((cp = strrchr(devname, '/')) == NULL)
1414 return (-1);
1415 strcat(modname, cp+1);
1416
1417 /* check if the kld module exists */
1418 sprintf(filename, "/modules/%s.ko", modname);
1419 if (stat(filename, &sbuf) < 0) {
1420 /* module file doesn't exist */
1421 return (-1);
1422 }
1423
1424 if (kldload(modname) < 0) {
1425 LOG(LOG_ERR, errno, "kldload %s failed!\n", modname);
1426 return (-1);
1427 }
1428
1429 /* successfully loaded, open the device */
1430 LOG(LOG_INFO, 0, "kld module %s loaded\n", modname);
1431 fd = open(devname, flags);
1432 return (fd);
1433 #else
1434 return (-1);
1435 #endif
1436 }
1437
1438