qop_cdnr.c revision 1.1 1 /* $KAME: qop_cdnr.c,v 1.6 2000/10/18 09:15:19 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 <net/if.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <stddef.h>
41 #include <string.h>
42 #include <ctype.h>
43 #include <errno.h>
44 #include <syslog.h>
45 #include <netdb.h>
46
47 #include <altq/altq.h>
48 #include <altq/altq_cdnr.h>
49 #include "altq_qop.h"
50 #include "qop_cdnr.h"
51 /*
52 * diffserve traffic conditioner support
53 *
54 * we use the existing qop interface to support conditioner.
55 */
56
57 static struct ifinfo *cdnr_ifname2ifinfo(const char *ifname);
58 static int cdnr_attach(struct ifinfo *ifinfo);
59 static int cdnr_detach(struct ifinfo *ifinfo);
60 static int cdnr_enable(struct ifinfo *ifinfo);
61 static int cdnr_disable(struct ifinfo *ifinfo);
62 static int cdnr_add_class(struct classinfo *clinfo);
63 static int cdnr_modify_class(struct classinfo *clinfo, void *arg);
64 static int cdnr_delete_class(struct classinfo *clinfo);
65 static int cdnr_add_filter(struct fltrinfo *fltrinfo);
66 static int cdnr_delete_filter(struct fltrinfo *fltrinfo);
67 static int verify_tbprofile(struct tb_profile *profile, const char *cdnr_name);
68
69 #define CDNR_DEVICE "/dev/altq/cdnr"
70
71 static int cdnr_fd = -1;
72 static int cdnr_refcount = 0;
73
74 static struct qdisc_ops cdnr_qdisc = {
75 ALTQT_CDNR,
76 "cdnr",
77 cdnr_attach,
78 cdnr_detach,
79 NULL, /* clear */
80 cdnr_enable,
81 cdnr_disable,
82 cdnr_add_class,
83 cdnr_modify_class,
84 cdnr_delete_class,
85 cdnr_add_filter,
86 cdnr_delete_filter,
87 };
88
89 u_long
90 cdnr_name2handle(const char *ifname, const char *cdnr_name)
91 {
92 struct ifinfo *ifinfo;
93 struct classinfo *clinfo;
94
95 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
96 return (CDNR_NULL_HANDLE);
97
98 if ((clinfo = clname2clinfo(ifinfo, cdnr_name)) == NULL)
99 return (CDNR_NULL_HANDLE);
100
101 return (clinfo->handle);
102 }
103
104 static struct ifinfo *
105 cdnr_ifname2ifinfo(const char *ifname)
106 {
107 struct ifinfo *ifinfo;
108 char input_ifname[64];
109
110 /*
111 * search for an existing input interface
112 */
113 if ((ifinfo = input_ifname2ifinfo(ifname)) != NULL)
114 return (ifinfo);
115
116 /*
117 * if there is a corresponding output interface,
118 * create an input interface by prepending "_" to
119 * its name.
120 */
121 if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
122 return (NULL);
123
124 input_ifname[0] = '_';
125 strcpy(input_ifname+1, ifname);
126 if (qop_add_if(&ifinfo, input_ifname, 0, &cdnr_qdisc, NULL) != 0) {
127 LOG(LOG_ERR, errno,
128 "cdnr_ifname2ifinfo: can't add a input interface %s\n",
129 ifname);
130 return (NULL);
131 }
132 return (ifinfo);
133 }
134
135 int
136 qcmd_cdnr_add_element(struct tc_action *rp, const char *ifname,
137 const char *cdnr_name, struct tc_action *action)
138 {
139 struct ifinfo *ifinfo;
140 struct classinfo *clinfo;
141 int error;
142
143 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
144 return (QOPERR_BADIF);
145
146 if ((error = qop_cdnr_add_element(&clinfo, cdnr_name, ifinfo,
147 action)) != 0) {
148 LOG(LOG_ERR, errno, "%s: add element failed!\n",
149 qoperror(error));
150 return (error);
151 }
152
153 if (rp != NULL) {
154 rp->tca_code = TCACODE_HANDLE;
155 rp->tca_handle = clinfo->handle;
156 }
157 return (0);
158 }
159
160 int
161 qcmd_cdnr_add_tbmeter(struct tc_action *rp, const char *ifname,
162 const char *cdnr_name,
163 struct tb_profile *profile,
164 struct tc_action *in_action,
165 struct tc_action *out_action)
166 {
167 struct ifinfo *ifinfo;
168 struct classinfo *clinfo;
169 int error;
170
171 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
172 return (QOPERR_BADIF);
173
174 verify_tbprofile(profile, cdnr_name);
175
176 if ((error = qop_cdnr_add_tbmeter(&clinfo, cdnr_name, ifinfo,
177 profile, in_action, out_action)) != 0) {
178 LOG(LOG_ERR, errno, "%s: add tbmeter failed!\n",
179 qoperror(error));
180 return (error);
181 }
182
183 if (rp != NULL) {
184 rp->tca_code = TCACODE_HANDLE;
185 rp->tca_handle = clinfo->handle;
186 }
187 return (0);
188 }
189
190 int
191 qcmd_cdnr_add_trtcm(struct tc_action *rp, const char *ifname,
192 const char *cdnr_name,
193 struct tb_profile *cmtd_profile,
194 struct tb_profile *peak_profile,
195 struct tc_action *green_action,
196 struct tc_action *yellow_action,
197 struct tc_action *red_action, int coloraware)
198 {
199 struct ifinfo *ifinfo;
200 struct classinfo *clinfo;
201 int error;
202
203 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
204 return (QOPERR_BADIF);
205
206 verify_tbprofile(cmtd_profile, cdnr_name);
207 verify_tbprofile(peak_profile, cdnr_name);
208
209 if ((error = qop_cdnr_add_trtcm(&clinfo, cdnr_name, ifinfo,
210 cmtd_profile, peak_profile,
211 green_action, yellow_action, red_action,
212 coloraware)) != 0) {
213 LOG(LOG_ERR, errno, "%s: add trtcm failed!\n",
214 qoperror(error));
215 return (error);
216 }
217
218 if (rp != NULL) {
219 rp->tca_code = TCACODE_HANDLE;
220 rp->tca_handle = clinfo->handle;
221 }
222 return (0);
223 }
224
225 int
226 qcmd_cdnr_add_tswtcm(struct tc_action *rp, const char *ifname,
227 const char *cdnr_name, const u_int32_t cmtd_rate,
228 const u_int32_t peak_rate, const u_int32_t avg_interval,
229 struct tc_action *green_action,
230 struct tc_action *yellow_action,
231 struct tc_action *red_action)
232 {
233 struct ifinfo *ifinfo;
234 struct classinfo *clinfo;
235 int error;
236
237 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
238 return (QOPERR_BADIF);
239
240 if (cmtd_rate > peak_rate) {
241 LOG(LOG_ERR, 0,
242 "add tswtcm: cmtd_rate larger than peak_rate!\n");
243 return (QOPERR_INVAL);
244 }
245
246 if ((error = qop_cdnr_add_tswtcm(&clinfo, cdnr_name, ifinfo,
247 cmtd_rate, peak_rate, avg_interval,
248 green_action, yellow_action,
249 red_action)) != 0) {
250 LOG(LOG_ERR, errno, "%s: add tswtcm failed!\n",
251 qoperror(error));
252 return (error);
253 }
254
255 if (rp != NULL) {
256 rp->tca_code = TCACODE_HANDLE;
257 rp->tca_handle = clinfo->handle;
258 }
259 return (0);
260 }
261
262 int
263 qcmd_cdnr_delete(const char *ifname, const char *cdnr_name)
264 {
265 struct ifinfo *ifinfo;
266 struct classinfo *clinfo;
267
268 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
269 return (QOPERR_BADIF);
270
271 if ((clinfo = clname2clinfo(ifinfo, cdnr_name)) == NULL)
272 return (QOPERR_BADCLASS);
273
274 return qop_delete_cdnr(clinfo);
275 }
276
277 /*
278 * class operations:
279 * class structure is used to hold conditioners.
280 * XXX
281 * conditioners has dependencies in the reverse order; parent nodes
282 * refere to child nodes, and thus, a child is created first and
283 * parents should be removed first.
284 * qop_add_cdnr() and qop_delete_cdnr() are wrapper functions
285 * of qop_add_class() and qop_delete_class(), and takes care
286 * of dependencies.
287 * 1. when adding a conditioner, it is created as a child of a
288 * dummy root class. then, the child conditioners are made
289 * as its children.
290 * 2. when deleting a conditioner, its child conditioners are made
291 * as children of the dummy root class. then, the conditioner
292 * is deleted.
293 */
294
295 int
296 qop_add_cdnr(struct classinfo **rp, const char *cdnr_name,
297 struct ifinfo *ifinfo, struct classinfo **childlist,
298 void *cdnr_private)
299 {
300 struct classinfo *clinfo, *root, *cl, *prev;
301 int error;
302
303 /*
304 * if there is no root cdnr, create one.
305 */
306 if ((root = get_rootclass(ifinfo)) == NULL) {
307 if ((error = qop_add_class(&root, "cdnr_root",
308 ifinfo, NULL, NULL)) != 0) {
309 LOG(LOG_ERR, errno,
310 "cdnr: %s: can't create dummy root cdnr on %s!\n",
311 qoperror(error), ifinfo->ifname);
312 return (QOPERR_CLASS);
313 }
314 }
315
316 /*
317 * create a class as a child of a root class.
318 */
319 if ((error = qop_add_class(&clinfo, cdnr_name,
320 ifinfo, root, cdnr_private)) != 0)
321 return (error);
322 /*
323 * move child nodes
324 */
325 for (cl = *childlist; cl != NULL; cl = *++childlist) {
326 if (cl->parent != root) {
327 /*
328 * this conditioner already has a non-root parent.
329 * we can't track down a multi-parent node by a
330 * tree structure; leave it as it is.
331 * (we need a mechanism similar to a symbolic link
332 * in a file system)
333 */
334 continue;
335 }
336 /* remove this child from the root */
337 if (root->child == cl)
338 root->child = cl->sibling;
339 else for (prev = root->child;
340 prev->sibling != NULL; prev = prev->sibling)
341 if (prev->sibling == cl) {
342 prev->sibling = cl->sibling;
343 break;
344 }
345
346 /* add as a child */
347 cl->sibling = clinfo->child;
348 clinfo->child = cl;
349 cl->parent = clinfo;
350 }
351
352 if (rp != NULL)
353 *rp = clinfo;
354 return (0);
355 }
356
357 int
358 qop_delete_cdnr(struct classinfo *clinfo)
359 {
360 struct classinfo *cl, *root;
361 int error;
362
363 if ((root = get_rootclass(clinfo->ifinfo)) == NULL) {
364 LOG(LOG_ERR, 0, "qop_delete_cdnr: no root cdnr!\n");
365 return (QOPERR_CLASS);
366 }
367
368 if (clinfo->parent != root)
369 return (QOPERR_CLASS_PERM);
370
371 if ((cl = clinfo->child) != NULL) {
372 /* change child's parent to root, find the last child */
373 while (cl->sibling != NULL) {
374 cl->parent = root;
375 cl = cl->sibling;
376 }
377 cl->parent = root;
378
379 /* move children to siblings */
380 cl->sibling = clinfo->sibling;
381 clinfo->sibling = cl;
382 clinfo->child = NULL;
383 }
384
385 error = qop_delete_class(clinfo);
386
387 if (error) {
388 /* ick! restore the class tree */
389 if (cl != NULL) {
390 clinfo->child = clinfo->sibling;
391 clinfo->sibling = cl->sibling;
392 cl->sibling = NULL;
393 /* restore parent field */
394 for (cl = clinfo->child; cl != NULL; cl = cl->sibling)
395 cl->parent = clinfo;
396 }
397 }
398 return (error);
399 }
400
401 int
402 qop_cdnr_add_element(struct classinfo **rp, const char *cdnr_name,
403 struct ifinfo *ifinfo, struct tc_action *action)
404 {
405 struct classinfo *clinfo, *clist[2];
406 struct cdnrinfo *cdnrinfo = NULL;
407 int error;
408
409 if (action->tca_code == TCACODE_HANDLE) {
410 clinfo = clhandle2clinfo(ifinfo, action->tca_handle);
411 if (clinfo == NULL)
412 return (QOPERR_BADCLASS);
413 clist[0] = clinfo;
414 clist[1] = NULL;
415 #if 1
416 /*
417 * if the conditioner referred to doesn't have a name,
418 * this is called just to add a name to it.
419 * we can simply add the name to the existing conditioner
420 * and return it.
421 */
422 if (cdnr_name != NULL &&
423 strcmp(clinfo->clname, "(null)") == 0) {
424 free(clinfo->clname);
425 clinfo->clname = strdup(cdnr_name);
426 if (rp != NULL)
427 *rp = clinfo;
428 return (0);
429 }
430 #endif
431 } else
432 clist[0] = NULL;
433
434 if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
435 return (QOPERR_NOMEM);
436
437 cdnrinfo->tce_type = TCETYPE_ELEMENT;
438 cdnrinfo->tce_un.element.action = *action;
439
440 if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
441 cdnrinfo)) != 0)
442 goto err_ret;
443
444 if (rp != NULL)
445 *rp = clinfo;
446 return (0);
447
448 err_ret:
449 if (cdnrinfo != NULL)
450 free(cdnrinfo);
451 return (error);
452 }
453
454 int
455 qop_cdnr_add_tbmeter(struct classinfo **rp, const char *cdnr_name,
456 struct ifinfo *ifinfo,
457 struct tb_profile *profile,
458 struct tc_action *in_action,
459 struct tc_action *out_action)
460 {
461 struct classinfo *clinfo, *clist[3];
462 struct cdnrinfo *cdnrinfo = NULL;
463 int n, error;
464
465 n = 0;
466 if (in_action->tca_code == TCACODE_HANDLE) {
467 clist[n] = clhandle2clinfo(ifinfo, in_action->tca_handle);
468 if (clist[n] == NULL)
469 return (QOPERR_BADCLASS);
470 n++;
471 }
472 if (out_action->tca_code == TCACODE_HANDLE) {
473 clist[n] = clhandle2clinfo(ifinfo, out_action->tca_handle);
474 if (clist[n] == NULL)
475 return (QOPERR_BADCLASS);
476 n++;
477 }
478 clist[n] = NULL;
479
480 if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
481 return (QOPERR_NOMEM);
482
483 cdnrinfo->tce_type = TCETYPE_TBMETER;
484 cdnrinfo->tce_un.tbmeter.profile = *profile;
485 cdnrinfo->tce_un.tbmeter.in_action = *in_action;
486 cdnrinfo->tce_un.tbmeter.out_action = *out_action;
487
488 if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
489 cdnrinfo)) != 0)
490 goto err_ret;
491
492 if (rp != NULL)
493 *rp = clinfo;
494 return (0);
495
496 err_ret:
497 if (cdnrinfo != NULL)
498 free(cdnrinfo);
499 return (error);
500 }
501
502 int
503 qop_cdnr_modify_tbmeter(struct classinfo *clinfo, struct tb_profile *profile)
504 {
505 struct cdnrinfo *cdnrinfo = clinfo->private;
506
507 if (cdnrinfo->tce_type != TCETYPE_TBMETER)
508 return (QOPERR_CLASS_INVAL);
509 cdnrinfo->tce_un.tbmeter.profile = *profile;
510
511 return qop_modify_class(clinfo, NULL);
512 }
513
514 int
515 qop_cdnr_add_trtcm(struct classinfo **rp, const char *cdnr_name,
516 struct ifinfo *ifinfo,
517 struct tb_profile *cmtd_profile,
518 struct tb_profile *peak_profile,
519 struct tc_action *green_action,
520 struct tc_action *yellow_action,
521 struct tc_action *red_action, int coloraware)
522 {
523 struct classinfo *clinfo, *clist[4];
524 struct cdnrinfo *cdnrinfo = NULL;
525 int n, error;
526
527 n = 0;
528 if (green_action->tca_code == TCACODE_HANDLE) {
529 clist[n] = clhandle2clinfo(ifinfo, green_action->tca_handle);
530 if (clist[n] == NULL)
531 return (QOPERR_BADCLASS);
532 n++;
533 }
534 if (yellow_action->tca_code == TCACODE_HANDLE) {
535 clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
536 if (clist[n] == NULL)
537 return (QOPERR_BADCLASS);
538 n++;
539 }
540 if (red_action->tca_code == TCACODE_HANDLE) {
541 clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
542 if (clist[n] == NULL)
543 return (QOPERR_BADCLASS);
544 n++;
545 }
546 clist[n] = NULL;
547
548 if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
549 return (QOPERR_NOMEM);
550
551 cdnrinfo->tce_type = TCETYPE_TRTCM;
552 cdnrinfo->tce_un.trtcm.cmtd_profile = *cmtd_profile;
553 cdnrinfo->tce_un.trtcm.peak_profile = *peak_profile;
554 cdnrinfo->tce_un.trtcm.green_action = *green_action;
555 cdnrinfo->tce_un.trtcm.yellow_action = *yellow_action;
556 cdnrinfo->tce_un.trtcm.red_action = *red_action;
557 cdnrinfo->tce_un.trtcm.coloraware = coloraware;
558
559 if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
560 cdnrinfo)) != 0)
561 goto err_ret;
562
563 if (rp != NULL)
564 *rp = clinfo;
565 return (0);
566
567 err_ret:
568 if (cdnrinfo != NULL)
569 free(cdnrinfo);
570 return (error);
571 }
572
573 int
574 qop_cdnr_modify_trtcm(struct classinfo *clinfo,
575 struct tb_profile *cmtd_profile,
576 struct tb_profile *peak_profile, int coloraware)
577 {
578 struct cdnrinfo *cdnrinfo = clinfo->private;
579
580 if (cdnrinfo->tce_type != TCETYPE_TRTCM)
581 return (QOPERR_CLASS_INVAL);
582 cdnrinfo->tce_un.trtcm.cmtd_profile = *cmtd_profile;
583 cdnrinfo->tce_un.trtcm.peak_profile = *peak_profile;
584 cdnrinfo->tce_un.trtcm.coloraware = coloraware;
585
586 return qop_modify_class(clinfo, NULL);
587 }
588
589 int
590 qop_cdnr_add_tswtcm(struct classinfo **rp, const char *cdnr_name,
591 struct ifinfo *ifinfo, const u_int32_t cmtd_rate,
592 const u_int32_t peak_rate, const u_int32_t avg_interval,
593 struct tc_action *green_action,
594 struct tc_action *yellow_action,
595 struct tc_action *red_action)
596 {
597 struct classinfo *clinfo, *clist[4];
598 struct cdnrinfo *cdnrinfo = NULL;
599 int n, error;
600
601 n = 0;
602 if (green_action->tca_code == TCACODE_HANDLE) {
603 clist[n] = clhandle2clinfo(ifinfo, green_action->tca_handle);
604 if (clist[n] == NULL)
605 return (QOPERR_BADCLASS);
606 n++;
607 }
608 if (yellow_action->tca_code == TCACODE_HANDLE) {
609 clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
610 if (clist[n] == NULL)
611 return (QOPERR_BADCLASS);
612 n++;
613 }
614 if (red_action->tca_code == TCACODE_HANDLE) {
615 clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
616 if (clist[n] == NULL)
617 return (QOPERR_BADCLASS);
618 n++;
619 }
620 clist[n] = NULL;
621
622 if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
623 return (QOPERR_NOMEM);
624
625 cdnrinfo->tce_type = TCETYPE_TSWTCM;
626 cdnrinfo->tce_un.tswtcm.cmtd_rate = cmtd_rate;
627 cdnrinfo->tce_un.tswtcm.peak_rate = peak_rate;
628 cdnrinfo->tce_un.tswtcm.avg_interval = avg_interval;
629 cdnrinfo->tce_un.tswtcm.green_action = *green_action;
630 cdnrinfo->tce_un.tswtcm.yellow_action = *yellow_action;
631 cdnrinfo->tce_un.tswtcm.red_action = *red_action;
632
633 if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
634 cdnrinfo)) != 0)
635 goto err_ret;
636
637 if (rp != NULL)
638 *rp = clinfo;
639 return (0);
640
641 err_ret:
642 if (cdnrinfo != NULL)
643 free(cdnrinfo);
644 return (error);
645 }
646
647 int
648 qop_cdnr_modify_tswtcm(struct classinfo *clinfo, const u_int32_t cmtd_rate,
649 const u_int32_t peak_rate, const u_int32_t avg_interval)
650 {
651 struct cdnrinfo *cdnrinfo = clinfo->private;
652
653 if (cdnrinfo->tce_type != TCETYPE_TSWTCM)
654 return (QOPERR_CLASS_INVAL);
655 cdnrinfo->tce_un.tswtcm.cmtd_rate = cmtd_rate;
656 cdnrinfo->tce_un.tswtcm.peak_rate = peak_rate;
657 cdnrinfo->tce_un.tswtcm.avg_interval = avg_interval;
658
659 return qop_modify_class(clinfo, NULL);
660 }
661
662 /*
663 * system call interfaces for qdisc_ops
664 */
665 static int
666 cdnr_attach(struct ifinfo *ifinfo)
667 {
668 struct cdnr_interface iface;
669
670 if (cdnr_fd < 0 &&
671 (cdnr_fd = open(CDNR_DEVICE, O_RDWR)) < 0 &&
672 (cdnr_fd = open_module(CDNR_DEVICE, O_RDWR)) < 0) {
673 LOG(LOG_ERR, errno, "CDNR open\n");
674 return (QOPERR_SYSCALL);
675 }
676
677 cdnr_refcount++;
678 memset(&iface, 0, sizeof(iface));
679 strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
680
681 if (ioctl(cdnr_fd, CDNR_IF_ATTACH, &iface) < 0)
682 return (QOPERR_SYSCALL);
683 #if 1
684 LOG(LOG_INFO, 0, "conditioner attached to %s\n", iface.cdnr_ifname);
685 #endif
686 return (0);
687 }
688
689 static int
690 cdnr_detach(struct ifinfo *ifinfo)
691 {
692 struct cdnr_interface iface;
693
694 memset(&iface, 0, sizeof(iface));
695 strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
696
697 if (ioctl(cdnr_fd, CDNR_IF_DETACH, &iface) < 0)
698 return (QOPERR_SYSCALL);
699
700 if (--cdnr_refcount == 0) {
701 close(cdnr_fd);
702 cdnr_fd = -1;
703 }
704 return (0);
705 }
706
707 static int
708 cdnr_enable(struct ifinfo *ifinfo)
709 {
710 struct cdnr_interface iface;
711
712 memset(&iface, 0, sizeof(iface));
713 strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
714
715 if (ioctl(cdnr_fd, CDNR_ENABLE, &iface) < 0)
716 return (QOPERR_SYSCALL);
717 return (0);
718 }
719
720 static int
721 cdnr_disable(struct ifinfo *ifinfo)
722 {
723 struct cdnr_interface iface;
724
725 memset(&iface, 0, sizeof(iface));
726 strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
727
728 if (ioctl(cdnr_fd, CDNR_DISABLE, &iface) < 0)
729 return (QOPERR_SYSCALL);
730 return (0);
731 }
732
733 static int
734 cdnr_add_class(struct classinfo *clinfo)
735 {
736 struct cdnr_add_element element_add;
737 struct cdnr_add_tbmeter tbmeter_add;
738 struct cdnr_add_trtcm trtcm_add;
739 struct cdnr_add_tswtcm tswtcm_add;
740 struct cdnrinfo *cdnrinfo;
741
742 cdnrinfo = clinfo->private;
743
744 /* root class is a dummy class */
745 if (clinfo->parent == NULL) {
746 clinfo->handle = 0;
747 return (0);
748 }
749
750 switch (cdnrinfo->tce_type) {
751 case TCETYPE_ELEMENT:
752 memset(&element_add, 0, sizeof(element_add));
753 strncpy(element_add.iface.cdnr_ifname,
754 clinfo->ifinfo->ifname+1, IFNAMSIZ);
755 element_add.action = cdnrinfo->tce_un.element.action;
756 if (ioctl(cdnr_fd, CDNR_ADD_ELEM, &element_add) < 0) {
757 clinfo->handle = CDNR_NULL_HANDLE;
758 return (QOPERR_SYSCALL);
759 }
760 clinfo->handle = element_add.cdnr_handle;
761 break;
762
763 case TCETYPE_TBMETER:
764 memset(&tbmeter_add, 0, sizeof(tbmeter_add));
765 strncpy(tbmeter_add.iface.cdnr_ifname,
766 clinfo->ifinfo->ifname+1, IFNAMSIZ);
767 tbmeter_add.profile = cdnrinfo->tce_un.tbmeter.profile;
768 tbmeter_add.in_action = cdnrinfo->tce_un.tbmeter.in_action;
769 tbmeter_add.out_action = cdnrinfo->tce_un.tbmeter.out_action;
770 if (ioctl(cdnr_fd, CDNR_ADD_TBM, &tbmeter_add) < 0) {
771 clinfo->handle = CDNR_NULL_HANDLE;
772 return (QOPERR_SYSCALL);
773 }
774 clinfo->handle = tbmeter_add.cdnr_handle;
775 break;
776
777 case TCETYPE_TRTCM:
778 memset(&trtcm_add, 0, sizeof(trtcm_add));
779 strncpy(trtcm_add.iface.cdnr_ifname,
780 clinfo->ifinfo->ifname+1, IFNAMSIZ);
781 trtcm_add.cmtd_profile = cdnrinfo->tce_un.trtcm.cmtd_profile;
782 trtcm_add.peak_profile = cdnrinfo->tce_un.trtcm.peak_profile;
783 trtcm_add.green_action = cdnrinfo->tce_un.trtcm.green_action;
784 trtcm_add.yellow_action = cdnrinfo->tce_un.trtcm.yellow_action;
785 trtcm_add.red_action = cdnrinfo->tce_un.trtcm.red_action;
786 trtcm_add.coloraware = cdnrinfo->tce_un.trtcm.coloraware;
787 if (ioctl(cdnr_fd, CDNR_ADD_TCM, &trtcm_add) < 0) {
788 clinfo->handle = CDNR_NULL_HANDLE;
789 return (QOPERR_SYSCALL);
790 }
791 clinfo->handle = trtcm_add.cdnr_handle;
792 break;
793
794 case TCETYPE_TSWTCM:
795 memset(&tswtcm_add, 0, sizeof(tswtcm_add));
796 strncpy(tswtcm_add.iface.cdnr_ifname,
797 clinfo->ifinfo->ifname+1, IFNAMSIZ);
798 tswtcm_add.cmtd_rate = cdnrinfo->tce_un.tswtcm.cmtd_rate;
799 tswtcm_add.peak_rate = cdnrinfo->tce_un.tswtcm.peak_rate;
800 tswtcm_add.avg_interval = cdnrinfo->tce_un.tswtcm.avg_interval;
801 tswtcm_add.green_action = cdnrinfo->tce_un.tswtcm.green_action;
802 tswtcm_add.yellow_action = cdnrinfo->tce_un.tswtcm.yellow_action;
803 tswtcm_add.red_action = cdnrinfo->tce_un.tswtcm.red_action;
804 if (ioctl(cdnr_fd, CDNR_ADD_TSW, &tswtcm_add) < 0) {
805 clinfo->handle = CDNR_NULL_HANDLE;
806 return (QOPERR_SYSCALL);
807 }
808 clinfo->handle = tswtcm_add.cdnr_handle;
809 break;
810
811 default:
812 return (QOPERR_CLASS_INVAL);
813 }
814 return (0);
815 }
816
817 static int
818 cdnr_modify_class(struct classinfo *clinfo, void *arg)
819 {
820 struct cdnr_modify_tbmeter tbmeter_modify;
821 struct cdnr_modify_trtcm trtcm_modify;
822 struct cdnr_modify_tswtcm tswtcm_modify;
823 struct cdnrinfo *cdnrinfo;
824
825 cdnrinfo = clinfo->private;
826
827 switch (cdnrinfo->tce_type) {
828 case TCETYPE_TBMETER:
829 memset(&tbmeter_modify, 0, sizeof(tbmeter_modify));
830 strncpy(tbmeter_modify.iface.cdnr_ifname,
831 clinfo->ifinfo->ifname+1, IFNAMSIZ);
832 tbmeter_modify.cdnr_handle = clinfo->handle;
833 tbmeter_modify.profile = cdnrinfo->tce_un.tbmeter.profile;
834 if (ioctl(cdnr_fd, CDNR_MOD_TBM, &tbmeter_modify) < 0)
835 return (QOPERR_SYSCALL);
836 break;
837
838 case TCETYPE_TRTCM:
839 memset(&trtcm_modify, 0, sizeof(trtcm_modify));
840 strncpy(trtcm_modify.iface.cdnr_ifname,
841 clinfo->ifinfo->ifname+1, IFNAMSIZ);
842 trtcm_modify.cdnr_handle = clinfo->handle;
843 trtcm_modify.cmtd_profile =
844 cdnrinfo->tce_un.trtcm.cmtd_profile;
845 trtcm_modify.peak_profile =
846 cdnrinfo->tce_un.trtcm.peak_profile;
847 trtcm_modify.coloraware = cdnrinfo->tce_un.trtcm.coloraware;
848 if (ioctl(cdnr_fd, CDNR_MOD_TCM, &trtcm_modify) < 0)
849 return (QOPERR_SYSCALL);
850 break;
851
852 case TCETYPE_TSWTCM:
853 memset(&tswtcm_modify, 0, sizeof(tswtcm_modify));
854 strncpy(tswtcm_modify.iface.cdnr_ifname,
855 clinfo->ifinfo->ifname+1, IFNAMSIZ);
856 tswtcm_modify.cdnr_handle = clinfo->handle;
857 tswtcm_modify.cmtd_rate = cdnrinfo->tce_un.tswtcm.cmtd_rate;
858 tswtcm_modify.peak_rate = cdnrinfo->tce_un.tswtcm.peak_rate;
859 tswtcm_modify.avg_interval = cdnrinfo->tce_un.tswtcm.avg_interval;
860 if (ioctl(cdnr_fd, CDNR_MOD_TSW, &tswtcm_modify) < 0)
861 return (QOPERR_SYSCALL);
862 break;
863
864 default:
865 return (QOPERR_CLASS_INVAL);
866 }
867 return (0);
868 }
869
870 static int
871 cdnr_delete_class(struct classinfo *clinfo)
872 {
873 struct cdnr_delete_element element_delete;
874
875 if (clinfo->handle == CDNR_NULL_HANDLE)
876 return (0);
877
878 memset(&element_delete, 0, sizeof(element_delete));
879 strncpy(element_delete.iface.cdnr_ifname, clinfo->ifinfo->ifname+1,
880 IFNAMSIZ);
881 element_delete.cdnr_handle = clinfo->handle;
882
883 if (ioctl(cdnr_fd, CDNR_DEL_ELEM, &element_delete) < 0)
884 return (QOPERR_SYSCALL);
885 return (0);
886 }
887
888 static int
889 cdnr_add_filter(struct fltrinfo *fltrinfo)
890 {
891 struct cdnr_add_filter fltr_add;
892
893 memset(&fltr_add, 0, sizeof(fltr_add));
894 strncpy(fltr_add.iface.cdnr_ifname,
895 fltrinfo->clinfo->ifinfo->ifname+1, IFNAMSIZ);
896 fltr_add.cdnr_handle = fltrinfo->clinfo->handle;
897 fltr_add.filter = fltrinfo->fltr;
898
899 if (ioctl(cdnr_fd, CDNR_ADD_FILTER, &fltr_add) < 0)
900 return (QOPERR_SYSCALL);
901 fltrinfo->handle = fltr_add.filter_handle;
902 return (0);
903 }
904
905 static int
906 cdnr_delete_filter(struct fltrinfo *fltrinfo)
907 {
908 struct cdnr_delete_filter fltr_del;
909
910 memset(&fltr_del, 0, sizeof(fltr_del));
911 strncpy(fltr_del.iface.cdnr_ifname,
912 fltrinfo->clinfo->ifinfo->ifname+1, IFNAMSIZ);
913 fltr_del.filter_handle = fltrinfo->handle;
914
915 if (ioctl(cdnr_fd, CDNR_DEL_FILTER, &fltr_del) < 0)
916 return (QOPERR_SYSCALL);
917 return (0);
918 }
919
920
921 static int
922 verify_tbprofile(struct tb_profile *profile, const char *cdnr_name)
923 {
924 if (profile->depth < 1500) {
925 LOG(LOG_WARNING, 0,
926 "warning: token bucket depth for %s is too small (%d)\n",
927 cdnr_name, profile->depth);
928 return (-1);
929 }
930 return (0);
931 }
932
933