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