qop.c revision 1.2 1 /* $KAME: qop.c,v 1.8 2001/08/16 04:31:41 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 *);
90 static void tbr_install(const char *);
91 static void tbr_deinstall(const char *);
92 static int add_filter_rule(struct ifinfo *, struct fltrinfo *,
93 struct fltrinfo **);
94 static int remove_filter_rule(struct ifinfo *,
95 struct fltrinfo *);
96 static int filt_check_relation(struct flow_filter *, struct flow_filter *);
97 static int filt_disjoint(struct flow_filter *, struct flow_filter *);
98 static int filt_subset(struct flow_filter *, struct flow_filter *);
99
100 /*
101 * QCMD (Queue Command) API
102 */
103 int
104 qcmd_init(void)
105 {
106 int error;
107
108 /* read config file and execute commands */
109 error = qcmd_config();
110
111 if (error == 0)
112 error = qcmd_enableall();
113
114 if (error != 0)
115 LOG(LOG_ERR, errno, "%s: qcmd_init failed.\n",
116 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)\n",
134 ifinfo->qdisc->qname, ifname, ifinfo->ifmtu);
135 } else
136 LOG(LOG_ERR, errno, "%s: enable failed!\n", 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!\n", 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)\n",
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!\n", 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;
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\n",
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;
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!\n",
265 qoperror(error));
266 else if (IsDebug(DEBUG_ALTQ)) {
267 LOG(LOG_DEBUG, 0, "%s: add a filter %s to class %s\n",
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;
280 struct fltrinfo *fltrinfo;
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!\n",
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!\n", 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 u_long bandwidth;
796 char *cp;
797
798 bandwidth = strtoul(s, &cp, 0);
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 return (bandwidth);
808 }
809
810 u_long
811 atobytes(const char *s)
812 {
813 u_long bytes;
814 char *cp;
815
816 bytes = strtoul(s, &cp, 0);
817 if (cp != NULL) {
818 if (*cp == 'K' || *cp == 'k')
819 bytes *= 1024;
820 else if (*cp == 'M' || *cp == 'm')
821 bytes *= 1024 * 1024;
822 else if (*cp == 'G' || *cp == 'g')
823 bytes *= 1024 * 1024 * 1024;
824 }
825 return (bytes);
826 }
827
828 static int
829 get_ifmtu(const char *ifname)
830 {
831 int s, mtu;
832 struct ifreq ifr;
833 #ifdef __OpenBSD__
834 struct if_data ifdata;
835 #endif
836
837 mtu = 512; /* default MTU */
838
839 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
840 return (mtu);
841 strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
842 #ifdef __OpenBSD__
843 ifr.ifr_data = (caddr_t)&ifdata;
844 if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == 0)
845 mtu = ifdata.ifi_mtu;
846 #else
847 if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0)
848 mtu = ifr.ifr_mtu;
849 #endif
850 close(s);
851 return (mtu);
852 }
853
854 static void
855 tbr_install(const char *ifname)
856 {
857 struct tbrinfo *info;
858 struct tbrreq req;
859 int fd;
860
861 LIST_FOREACH(info, &tbr_list, link)
862 if (strcmp(info->ifname, ifname) == 0)
863 break;
864 if (info == NULL)
865 return;
866 if (info->tb_prof.rate == 0 || info->installed)
867 return;
868
869 /* get the current token bucket regulator */
870 if ((fd = open(ALTQ_DEVICE, O_RDWR)) < 0)
871 err(1, "can't open altq device");
872 strncpy(req.ifname, ifname, IFNAMSIZ-1);
873 if (ioctl(fd, ALTQTBRGET, &req) < 0)
874 err(1, "ALTQTBRGET for interface %s", req.ifname);
875
876 /* save the current values */
877 info->otb_prof.rate = req.tb_prof.rate;
878 info->otb_prof.depth = req.tb_prof.depth;
879
880 /*
881 * if tbr is not specified in the config file and tbr is already
882 * configured, do not change.
883 */
884 if (req.tb_prof.rate != 0) {
885 LOG(LOG_INFO, 0,
886 "tbr is already installed on %s,\n"
887 " using the current setting (rate:%.2fM size:%.2fK).\n",
888 info->ifname,
889 (double)req.tb_prof.rate/1000000.0,
890 (double)req.tb_prof.depth/1024.0);
891 close (fd);
892 return;
893 }
894
895 /* if the new size is not specified, use heuristics */
896 if (info->tb_prof.depth == 0) {
897 u_int rate, size;
898
899 rate = info->tb_prof.rate;
900 if (rate <= 1*1000*1000)
901 size = 1;
902 else if (rate <= 10*1000*1000)
903 size = 4;
904 else if (rate <= 200*1000*1000)
905 size = 8;
906 else
907 size = 24;
908 size = size * 1500; /* assume the default mtu is 1500 */
909 info->tb_prof.depth = size;
910 }
911
912 /* install the new tbr */
913 strncpy(req.ifname, ifname, IFNAMSIZ-1);
914 req.tb_prof.rate = info->tb_prof.rate;
915 req.tb_prof.depth = info->tb_prof.depth;
916 if (ioctl(fd, ALTQTBRSET, &req) < 0)
917 err(1, "ALTQTBRSET for interface %s", req.ifname);
918 LOG(LOG_INFO, 0,
919 "tbr installed on %s (rate:%.2fM size:%.2fK)\n",
920 info->ifname,
921 (double)info->tb_prof.rate/1000000.0,
922 (double)info->tb_prof.depth/1024.0);
923 close(fd);
924 info->installed = 1;
925 }
926
927 static void
928 tbr_deinstall(const char *ifname)
929 {
930 struct tbrinfo *info;
931 struct tbrreq req;
932 int fd;
933
934 LIST_FOREACH(info, &tbr_list, link)
935 if (strcmp(info->ifname, ifname) == 0)
936 break;
937 if (info == NULL)
938 return;
939
940 /* if we installed tbr, restore the old values */
941 if (info->installed != 0) {
942 strncpy(req.ifname, ifname, IFNAMSIZ-1);
943 req.tb_prof.rate = info->otb_prof.rate;
944 req.tb_prof.depth = info->otb_prof.depth;
945 if ((fd = open(ALTQ_DEVICE, O_RDWR)) < 0)
946 err(1, "can't open altq device");
947 if (ioctl(fd, ALTQTBRSET, &req) < 0)
948 err(1, "ALTQTBRSET for interface %s", req.ifname);
949 close(fd);
950 }
951 LIST_REMOVE(info, link);
952 free(info);
953 }
954
955 void
956 print_filter(const struct flow_filter *filt)
957 {
958 if (filt->ff_flow.fi_family == AF_INET) {
959 struct in_addr in_addr;
960
961 in_addr.s_addr = filt->ff_flow.fi_dst.s_addr;
962 LOG(LOG_DEBUG, 0,
963 " Filter Dest Addr: %s (mask %#x) Port: %d\n",
964 inet_ntoa(in_addr), ntoh32(filt->ff_mask.mask_dst.s_addr),
965 ntoh16(filt->ff_flow.fi_dport));
966 in_addr.s_addr = filt->ff_flow.fi_src.s_addr;
967 LOG(LOG_DEBUG, 0,
968 " Src Addr: %s (mask %#x) Port: %d\n",
969 inet_ntoa(in_addr), ntoh32(filt->ff_mask.mask_src.s_addr),
970 ntoh16(filt->ff_flow.fi_sport));
971 LOG(LOG_DEBUG, 0, " Protocol: %d TOS %#x (mask %#x)\n",
972 filt->ff_flow.fi_proto, filt->ff_flow.fi_tos,
973 filt->ff_mask.mask_tos);
974 }
975 #ifdef INET6
976 else if (filt->ff_flow.fi_family == AF_INET6) {
977 char str1[INET6_ADDRSTRLEN], str2[INET6_ADDRSTRLEN];
978 const struct flow_filter6 *sfilt6;
979
980 sfilt6 = (const struct flow_filter6 *)filt;
981 LOG(LOG_DEBUG, 0, "Filter6 Dest Addr: %s (mask %s) Port: %d",
982 inet_ntop(AF_INET6, &sfilt6->ff_flow6.fi6_dst,
983 str1, sizeof(str1)),
984 inet_ntop(AF_INET6, &sfilt6->ff_mask6.mask6_dst,
985 str2, sizeof(str2)),
986 ntoh16(sfilt6->ff_flow6.fi6_dport));
987 LOG(LOG_DEBUG, 0, " Src Addr: %s (mask %s) Port: %d",
988 inet_ntop(AF_INET6, &sfilt6->ff_flow6.fi6_src,
989 str1, sizeof(str1)),
990 inet_ntop(AF_INET6, &sfilt6->ff_mask6.mask6_src,
991 str2, sizeof(str2)),
992 ntoh16(sfilt6->ff_flow6.fi6_sport));
993 LOG(LOG_DEBUG, 0, " Protocol: %d TCLASS %#x (mask %#x)\n",
994 sfilt6->ff_flow6.fi6_proto, sfilt6->ff_flow6.fi6_tclass,
995 sfilt6->ff_mask6.mask6_tclass);
996 }
997 #endif /* INET6 */
998 }
999
1000 /*
1001 * functions to check the filter-rules.
1002 * when a new filter is added, we check the relation to the existing filters
1003 * and if some inconsistency is found, produce an error or a warning message.
1004 *
1005 * filter matching is performed from the head of the list.
1006 * let
1007 * S: a set of packets that filter s matches
1008 * T: a set of packets that filter t matches
1009 * filter relations are:
1010 * disjoint: S ^ T = empty
1011 * subset: S <= T
1012 * intersect: S ^ T = not empty
1013 *
1014 * a new filter is disjoint or subset of the existing filters --> ok
1015 * a new filter is superset of an existing filter --> order problem
1016 * a new filter intersect an existing filter --> warning
1017 *
1018 * port-intersect: a special case we don't make warning
1019 * - intersection is only port numbers
1020 * - one specifies src port and the other specifies dst port
1021 * there must be no packet with well-known port numbers in
1022 * both src and dst ports. so this is ok.
1023 */
1024
1025 #define FILT_DISJOINT 1
1026 #define FILT_SUBSET 2
1027 #define FILT_SUPERSET 3
1028 #define FILT_INTERSECT 4
1029 #define FILT_PORTINTERSECT 5
1030
1031 static int
1032 add_filter_rule(struct ifinfo *ifinfo, struct fltrinfo *fltrinfo,
1033 struct fltrinfo **conflict)
1034 {
1035 struct fltrinfo *fp, *front, *back, *prev = NULL;
1036 int relation;
1037
1038 LIST_FOREACH(fp, &ifinfo->fltr_rules, nextrule) {
1039 if (fp->fltr.ff_ruleno > fltrinfo->fltr.ff_ruleno) {
1040 front = fp;
1041 back = fltrinfo;
1042 prev = fp;
1043 } else {
1044 front = fltrinfo;
1045 back = fp;
1046 }
1047
1048 relation = filt_check_relation(&front->fltr, &back->fltr);
1049
1050 switch (relation) {
1051 case FILT_SUBSET:
1052 case FILT_DISJOINT:
1053 /* OK */
1054 break;
1055 case FILT_SUPERSET:
1056 if (front->dontwarn == 0 && back->dontwarn == 0)
1057 LOG(LOG_ERR, 0,
1058 "filters for \"%s\" at line %d and for \"%s\" at line %d has an order problem!\n",
1059 front->clinfo->clname, front->line_no,
1060 back->clinfo->clname, back->line_no);
1061
1062 if (conflict != NULL)
1063 *conflict = fp;
1064 return (QOPERR_FILTER_SHADOW);
1065 case FILT_PORTINTERSECT:
1066 break;
1067 case FILT_INTERSECT:
1068 /*
1069 * if the intersecting two filters beloging to the
1070 * same class, it's ok.
1071 */
1072 if (front->clinfo == back->clinfo)
1073 break;
1074 if (front->dontwarn == 0 && back->dontwarn == 0)
1075 LOG(LOG_WARNING, 0,
1076 "warning: filter for \"%s\" at line %d could override filter for \"%s\" at line %d\n",
1077 front->clinfo->clname, front->line_no,
1078 back->clinfo->clname, back->line_no);
1079 break;
1080 }
1081 }
1082
1083 if (prev == NULL)
1084 LIST_INSERT_HEAD(&ifinfo->fltr_rules, fltrinfo, nextrule);
1085 else
1086 LIST_INSERT_AFTER(prev, fltrinfo, nextrule);
1087 return (0);
1088 }
1089
1090 static int
1091 remove_filter_rule(struct ifinfo *ifinfo, struct fltrinfo *fltrinfo)
1092 {
1093 LIST_REMOVE(fltrinfo, nextrule);
1094 return (0);
1095 }
1096
1097 static int
1098 filt_check_relation(struct flow_filter *front, struct flow_filter *back)
1099 {
1100 int rval;
1101
1102 if (front->ff_flow.fi_family != back->ff_flow.fi_family)
1103 return (FILT_DISJOINT);
1104
1105 if (filt_disjoint(front, back))
1106 return (FILT_DISJOINT);
1107
1108 if ((rval = filt_subset(front, back)) == 1)
1109 return (FILT_SUBSET);
1110
1111 if (filt_subset(back, front) == 1)
1112 return (FILT_SUPERSET);
1113
1114 if (rval == 2)
1115 return (FILT_PORTINTERSECT);
1116
1117 return (FILT_INTERSECT);
1118 }
1119
1120 static int
1121 filt_disjoint(struct flow_filter *front, struct flow_filter *back)
1122 {
1123 u_int32_t mask;
1124 u_int8_t tosmask;
1125
1126 if (front->ff_flow.fi_family == AF_INET) {
1127 if (front->ff_flow.fi_proto != 0 && back->ff_flow.fi_proto != 0
1128 && front->ff_flow.fi_proto != back->ff_flow.fi_proto)
1129 return (1);
1130 if (front->ff_flow.fi_sport != 0 && back->ff_flow.fi_sport != 0
1131 && front->ff_flow.fi_sport != back->ff_flow.fi_sport)
1132 return (1);
1133 if (front->ff_flow.fi_dport != 0 && back->ff_flow.fi_dport != 0
1134 && front->ff_flow.fi_dport != back->ff_flow.fi_dport)
1135 return (1);
1136 if (front->ff_flow.fi_gpi != 0 && back->ff_flow.fi_gpi != 0
1137 && front->ff_flow.fi_gpi != back->ff_flow.fi_gpi)
1138 return (1);
1139 if (front->ff_flow.fi_src.s_addr != 0 &&
1140 back->ff_flow.fi_src.s_addr != 0) {
1141 mask = front->ff_mask.mask_src.s_addr &
1142 back->ff_mask.mask_src.s_addr;
1143 if ((front->ff_flow.fi_src.s_addr & mask) !=
1144 (back->ff_flow.fi_src.s_addr & mask))
1145 return (1);
1146 }
1147 if (front->ff_flow.fi_dst.s_addr != 0 &&
1148 back->ff_flow.fi_dst.s_addr != 0) {
1149 mask = front->ff_mask.mask_dst.s_addr &
1150 back->ff_mask.mask_dst.s_addr;
1151 if ((front->ff_flow.fi_dst.s_addr & mask) !=
1152 (back->ff_flow.fi_dst.s_addr & mask))
1153 return (1);
1154 }
1155 if (front->ff_flow.fi_tos != 0 && back->ff_flow.fi_tos != 0) {
1156 tosmask = front->ff_mask.mask_tos &
1157 back->ff_mask.mask_tos;
1158 if ((front->ff_flow.fi_tos & tosmask) !=
1159 (back->ff_flow.fi_tos & tosmask))
1160 return (1);
1161 }
1162 return (0);
1163 }
1164 #ifdef INET6
1165 else if (front->ff_flow.fi_family == AF_INET6) {
1166 struct flow_filter6 *front6, *back6;
1167 int i;
1168
1169 front6 = (struct flow_filter6 *)front;
1170 back6 = (struct flow_filter6 *)back;
1171
1172 if (front6->ff_flow6.fi6_proto != 0 &&
1173 back6->ff_flow6.fi6_proto != 0 &&
1174 front6->ff_flow6.fi6_proto != back6->ff_flow6.fi6_proto)
1175 return (1);
1176 if (front6->ff_flow6.fi6_flowlabel != 0 &&
1177 back6->ff_flow6.fi6_flowlabel != 0 &&
1178 front6->ff_flow6.fi6_flowlabel !=
1179 back6->ff_flow6.fi6_flowlabel)
1180 return (1);
1181 if (front6->ff_flow6.fi6_sport != 0 &&
1182 back6->ff_flow6.fi6_sport != 0 &&
1183 front6->ff_flow6.fi6_sport != back6->ff_flow6.fi6_sport)
1184 return (1);
1185 if (front6->ff_flow6.fi6_dport != 0 &&
1186 back6->ff_flow6.fi6_dport != 0 &&
1187 front6->ff_flow6.fi6_dport != back6->ff_flow6.fi6_dport)
1188 return (1);
1189 if (front6->ff_flow6.fi6_gpi != 0 &&
1190 back6->ff_flow6.fi6_gpi != 0 &&
1191 front6->ff_flow6.fi6_gpi != back6->ff_flow6.fi6_gpi)
1192 return (1);
1193 if (!IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_src) &&
1194 !IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src)) {
1195 for (i=0; i<4; i++) {
1196 mask = IN6ADDR32(&front6->ff_mask6.mask6_src, i)
1197 & IN6ADDR32(&back6->ff_mask6.mask6_src, i);
1198 if ((IN6ADDR32(&front6->ff_flow6.fi6_src, i) & mask) !=
1199 (IN6ADDR32(&back6->ff_flow6.fi6_src, i) & mask))
1200 return (1);
1201 }
1202 }
1203 if (!IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_dst) &&
1204 !IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst)) {
1205 for (i=0; i<4; i++) {
1206 mask = IN6ADDR32(&front6->ff_mask6.mask6_dst, i)
1207 & IN6ADDR32(&back6->ff_mask6.mask6_dst, i);
1208 if ((IN6ADDR32(&front6->ff_flow6.fi6_dst, i) & mask) !=
1209 (IN6ADDR32(&back6->ff_flow6.fi6_dst, i) & mask))
1210 return (1);
1211 }
1212 }
1213 if (front6->ff_flow6.fi6_tclass != 0 &&
1214 back6->ff_flow6.fi6_tclass != 0) {
1215 tosmask = front6->ff_mask6.mask6_tclass &
1216 back6->ff_mask6.mask6_tclass;
1217 if ((front6->ff_flow6.fi6_tclass & tosmask) !=
1218 (back6->ff_flow6.fi6_tclass & tosmask))
1219 return (1);
1220 }
1221 return (0);
1222 }
1223 #endif /* INET6 */
1224 return (0);
1225 }
1226
1227 /*
1228 * check if "front" is a subset of "back". assumes they are not disjoint
1229 * return value 0: not a subset
1230 * 1: subset
1231 * 2: subset except src & dst ports
1232 * (possible port-intersect)
1233 */
1234 static int
1235 filt_subset(struct flow_filter *front, struct flow_filter *back)
1236 {
1237 u_int16_t srcport, dstport;
1238
1239 if (front->ff_flow.fi_family == AF_INET) {
1240 if (front->ff_flow.fi_proto == 0 &&
1241 back->ff_flow.fi_proto != 0)
1242 return (0);
1243 if (front->ff_flow.fi_gpi == 0 && back->ff_flow.fi_gpi != 0)
1244 return (0);
1245 if (front->ff_flow.fi_src.s_addr == 0) {
1246 if (back->ff_flow.fi_src.s_addr != 0)
1247 return (0);
1248 } else if (back->ff_flow.fi_src.s_addr != 0 &&
1249 (~front->ff_mask.mask_src.s_addr &
1250 back->ff_mask.mask_src.s_addr))
1251 return (0);
1252 if (front->ff_flow.fi_dst.s_addr == 0) {
1253 if (back->ff_flow.fi_dst.s_addr != 0)
1254 return (0);
1255 } else if (back->ff_flow.fi_dst.s_addr != 0 &&
1256 (~front->ff_mask.mask_dst.s_addr &
1257 back->ff_mask.mask_dst.s_addr))
1258 return (0);
1259 if (~front->ff_mask.mask_tos & back->ff_mask.mask_tos)
1260 return (0);
1261
1262 if (front->ff_flow.fi_sport == 0 &&
1263 back->ff_flow.fi_sport != 0) {
1264 srcport = ntohs(back->ff_flow.fi_sport);
1265 dstport = ntohs(front->ff_flow.fi_dport);
1266 if (dstport > 0 /* && dstport < 1024 */ &&
1267 srcport > 0 /* && srcport < 1024 */)
1268 return (2);
1269 return (0);
1270 }
1271 if (front->ff_flow.fi_dport == 0 &&
1272 back->ff_flow.fi_dport != 0) {
1273 dstport = ntohs(back->ff_flow.fi_dport);
1274 srcport = ntohs(front->ff_flow.fi_sport);
1275 if (srcport > 0 /* && srcport < 1024 */ &&
1276 dstport > 0 /* && dstport < 1024 */)
1277 return (2);
1278 return (0);
1279 }
1280
1281 return (1);
1282 }
1283 #ifdef INET6
1284 else if (front->ff_flow.fi_family == AF_INET6) {
1285 struct flow_filter6 *front6, *back6;
1286 int i;
1287
1288 front6 = (struct flow_filter6 *)front;
1289 back6 = (struct flow_filter6 *)back;
1290
1291 if (front6->ff_flow6.fi6_proto == 0 &&
1292 back6->ff_flow6.fi6_proto != 0)
1293 return (0);
1294 if (front6->ff_flow6.fi6_flowlabel == 0 &&
1295 back6->ff_flow6.fi6_flowlabel != 0)
1296 return (0);
1297 if (front6->ff_flow6.fi6_gpi == 0 &&
1298 back6->ff_flow6.fi6_gpi != 0)
1299 return (0);
1300
1301 if (IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_src)) {
1302 if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src))
1303 return (0);
1304 } else if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src))
1305 for (i=0; i<4; i++)
1306 if (~IN6ADDR32(&front6->ff_mask6.mask6_src, i) &
1307 IN6ADDR32(&back6->ff_mask6.mask6_src, i))
1308 return (0);
1309 if (IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_dst)) {
1310 if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst))
1311 return (0);
1312 } else if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst))
1313 for (i=0; i<4; i++)
1314 if (~IN6ADDR32(&front6->ff_mask6.mask6_dst, i) &
1315 IN6ADDR32(&back6->ff_mask6.mask6_dst, i))
1316 return (0);
1317
1318 if (~front6->ff_mask6.mask6_tclass &
1319 back6->ff_mask6.mask6_tclass)
1320 return (0);
1321
1322 if (front6->ff_flow6.fi6_sport == 0 &&
1323 back6->ff_flow6.fi6_sport != 0) {
1324 srcport = ntohs(back6->ff_flow6.fi6_sport);
1325 dstport = ntohs(front6->ff_flow6.fi6_dport);
1326 if (dstport > 0 /* && dstport < 1024 */ &&
1327 srcport > 0 /* && srcport < 1024 */)
1328 return (2);
1329 return (0);
1330 }
1331 if (front6->ff_flow6.fi6_dport == 0 &&
1332 back6->ff_flow6.fi6_dport != 0) {
1333 dstport = ntohs(back6->ff_flow6.fi6_dport);
1334 srcport = ntohs(front6->ff_flow6.fi6_sport);
1335 if (srcport > 0 /* && srcport < 1024 */ &&
1336 dstport > 0 /* && dstport < 1024 */)
1337 return (2);
1338 return (0);
1339 }
1340 }
1341 #endif /* INET6 */
1342 return (1);
1343 }
1344
1345
1346 /*
1347 * setting RED or RIO default parameters
1348 */
1349 int
1350 qop_red_set_defaults(int th_min, int th_max, int inv_pmax)
1351 {
1352 struct redparams params;
1353 int fd;
1354
1355 if ((fd = open(RED_DEVICE, O_RDWR)) < 0) {
1356 LOG(LOG_ERR, errno, "RED open\n");
1357 return (QOPERR_SYSCALL);
1358 }
1359
1360 params.th_min = th_min;
1361 params.th_max = th_max;
1362 params.inv_pmax = inv_pmax;
1363
1364 if (ioctl(fd, RED_SETDEFAULTS, ¶ms) < 0) {
1365 LOG(LOG_ERR, errno, "RED_SETDEFAULTS\n");
1366 return (QOPERR_SYSCALL);
1367 }
1368
1369 (void)close(fd);
1370 return (0);
1371 }
1372
1373 int
1374 qop_rio_set_defaults(struct redparams *params)
1375 {
1376 int i, fd;
1377
1378 /* sanity check */
1379 for (i = 1; i < RIO_NDROPPREC; i++) {
1380 if (params[i].th_max > params[i-1].th_min)
1381 LOG(LOG_WARNING, 0,
1382 "warning: overlap found in RIO thresholds\n");
1383 }
1384
1385 if ((fd = open(RIO_DEVICE, O_RDWR)) < 0) {
1386 LOG(LOG_ERR, errno, "RIO open\n");
1387 return (QOPERR_SYSCALL);
1388 }
1389
1390 if (ioctl(fd, RIO_SETDEFAULTS, params) < 0) {
1391 LOG(LOG_ERR, errno, "RIO_SETDEFAULTS\n");
1392 return (QOPERR_SYSCALL);
1393 }
1394
1395 (void)close(fd);
1396 return (0);
1397 }
1398
1399 /*
1400 * try to load and open KLD module
1401 */
1402 int
1403 open_module(const char *devname, int flags)
1404 {
1405 #if defined(__FreeBSD__) && (__FreeBSD_version > 300000)
1406 char modname[64], filename[MAXPATHLEN], *cp;
1407 int fd;
1408 struct stat sbuf;
1409
1410 /* turn discipline name into module name */
1411 strlcpy(modname, "altq_", sizeof(modname));
1412 if ((cp = strrchr(devname, '/')) == NULL)
1413 return (-1);
1414 strlcat(modname, cp + 1, sizeof(modname));
1415
1416 /* check if the kld module exists */
1417 snprintf(filename, sizeof(filename), "/modules/%s.ko", modname);
1418 if (stat(filename, &sbuf) < 0) {
1419 /* module file doesn't exist */
1420 return (-1);
1421 }
1422
1423 if (kldload(modname) < 0) {
1424 LOG(LOG_ERR, errno, "kldload %s failed!\n", modname);
1425 return (-1);
1426 }
1427
1428 /* successfully loaded, open the device */
1429 LOG(LOG_INFO, 0, "kld module %s loaded\n", modname);
1430 fd = open(devname, flags);
1431 return (fd);
1432 #else
1433 return (-1);
1434 #endif
1435 }
1436