Sync usage with man page.
[netbsd-mini2440.git] / usr.sbin / altq / libaltq / qop_jobs.c
blob029c4b9d6ac97f23f79fb8b93c0960dcf6992e29
1 /* $KAME: qop_jobs.c,v 1.2 2002/10/26 07:09:22 kjc Exp $ */
2 /*
3 * Copyright (c) 2001-2002, by the Rector and Board of Visitors of
4 * the University of Virginia.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms,
8 * with or without modification, are permitted provided
9 * that the following conditions are met:
11 * Redistributions of source code must retain the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer.
15 * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided
18 * with the distribution.
20 * Neither the name of the University of Virginia nor the names
21 * of its contributors may be used to endorse or promote products
22 * derived from this software without specific prior written
23 * permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
26 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
27 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
34 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
36 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
37 * THE POSSIBILITY OF SUCH DAMAGE.
40 * Copyright (C) 1999-2000
41 * Sony Computer Science Laboratories, Inc. All rights reserved.
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
52 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
64 /*
65 * JoBS - altq prototype implementation
67 * Author: Nicolas Christin <nicolas@cs.virginia.edu>
69 * JoBS algorithms originally devised and proposed by
70 * Nicolas Christin and Jorg Liebeherr.
71 * Grateful Acknowledgments to Tarek Abdelzaher for his help and
72 * comments, and to Kenjiro Cho for some helpful advice.
73 * Contributed by the Multimedia Networks Group at the University
74 * of Virginia.
76 * http://qosbox.cs.virginia.edu
78 */
80 #include <sys/param.h>
81 #include <sys/socket.h>
82 #include <sys/sockio.h>
83 #include <sys/ioctl.h>
84 #include <sys/fcntl.h>
85 #include <net/if.h>
86 #include <netinet/in.h>
87 #include <arpa/inet.h>
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <unistd.h>
92 #include <stddef.h>
93 #include <string.h>
94 #include <ctype.h>
95 #include <errno.h>
96 #include <syslog.h>
97 #include <netdb.h>
99 #include <altq/altq.h>
100 #include <altq/altq_var.h>
101 #include <altq/altq_jobs.h>
102 #include "altq_qop.h"
103 #include "qop_jobs.h"
104 #define SCALE_LOSS 32
106 #if 0
107 static int qop_jobs_enable_hook(struct ifinfo *);
108 #endif
109 static int qop_jobs_delete_class_hook(struct classinfo *);
111 static int jobs_attach(struct ifinfo *);
112 static int jobs_detach(struct ifinfo *);
113 static int jobs_clear(struct ifinfo *);
114 static int jobs_enable(struct ifinfo *);
115 static int jobs_disable(struct ifinfo *);
116 static int jobs_add_class(struct classinfo *);
117 static int jobs_modify_class(struct classinfo *, void *);
118 static int jobs_delete_class(struct classinfo *);
119 static int jobs_add_filter(struct fltrinfo *);
120 static int jobs_delete_filter(struct fltrinfo *);
122 #define JOBS_DEVICE "/dev/altq/jobs"
124 static int jobs_fd = -1;
125 static int jobs_refcount = 0;
127 static struct qdisc_ops jobs_qdisc = {
128 ALTQT_JOBS,
129 "jobs",
130 jobs_attach,
131 jobs_detach,
132 jobs_clear,
133 jobs_enable,
134 jobs_disable,
135 jobs_add_class,
136 jobs_modify_class,
137 jobs_delete_class,
138 jobs_add_filter,
139 jobs_delete_filter
143 * parser interface
145 #define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
148 jobs_interface_parser(const char *ifname, int argc, char **argv)
150 u_int bandwidth = 100000000; /* 100 Mbps */
151 u_int tbrsize = 0;
152 int qlimit = 200; /* 200 packets */
153 int separate = 0; /* by default: shared buffer */
156 * process options
158 while (argc > 0) {
159 if (EQUAL(*argv, "bandwidth")) {
160 argc--; argv++;
161 if (argc > 0)
162 bandwidth = atobps(*argv);
163 } else if (EQUAL(*argv, "tbrsize")) {
164 argc--; argv++;
165 if (argc > 0)
166 tbrsize = atobytes(*argv);
167 } else if (EQUAL(*argv, "qlimit")) {
168 argc--; argv++;
169 if (argc > 0)
170 qlimit = (int)strtol(*argv, NULL, 0);
171 } else if (EQUAL(*argv, "separate")) {
172 argc--; argv++;
173 separate = 1;
174 } else if (EQUAL(*argv, "jobs")) {
175 /* just skip */
176 } else {
177 LOG(LOG_ERR, 0, "Unknown keyword '%s'", *argv);
178 return (0);
180 argc--; argv++;
183 if (qcmd_tbr_register(ifname, bandwidth, tbrsize) != 0)
184 return (0);
186 if (qcmd_jobs_add_if(ifname, bandwidth, qlimit, separate) != 0)
187 return (0);
188 return (1);
192 jobs_class_parser(const char *ifname, const char *class_name,
193 const char *parent_name, int argc, char **argv)
195 int64_t adc, rdc, alc, rlc, arc;
196 int pri = 0;
197 int flags = 0;
198 int error;
200 /* disable everything by default */
201 adc = -1;
202 rdc = -1;
203 arc = -1;
204 alc = -1;
205 rlc = -1;
207 while (argc > 0) {
208 if (EQUAL(*argv, "priority")) {
209 argc--; argv++;
210 if (argc > 0) {
211 if (strtol(*argv, NULL, 0) < 0)
212 pri = 0;
213 else
214 pri = strtol(*argv, NULL, 0);
216 } else if (EQUAL(*argv, "adc")) {
217 argc--; argv++;
218 if (argc > 0) {
219 if (strtol(*argv, NULL, 0) < 0)
220 adc = -1;
221 else
222 adc = strtol(*argv, NULL, 0);
224 } else if (EQUAL(*argv, "rdc")) {
225 argc--; argv++;
226 if (argc > 0) {
227 if (strtol(*argv, NULL, 0) < 0)
228 rdc = -1;
229 else
230 rdc = strtol(*argv, NULL, 0);
232 } else if (EQUAL(*argv, "alc")) {
233 argc--; argv++;
234 if (argc > 0) {
235 if (strtol(*argv, NULL, 0) < 0)
236 alc = -1;
237 else
238 alc = (int64_t)(strtod(*argv, NULL)
239 * ((int64_t)1 << SCALE_LOSS));
241 * alc is given in fraction of 1, convert it
242 * to a fraction of 2^(SCALE_LOSS)
245 } else if (EQUAL(*argv, "rlc")) {
246 argc--; argv++;
247 if (argc > 0) {
248 if (strtol(*argv, NULL, 0) < 0)
249 rlc = -1;
250 else
251 rlc = strtol(*argv, NULL, 0);
253 } else if (EQUAL(*argv, "arc")) {
254 argc--; argv++;
255 if (argc > 0) {
256 if (EQUAL(*argv,"-1"))
257 arc = -1;
258 else
259 arc = atobps(*argv);
261 } else if (EQUAL(*argv, "default")) {
262 flags |= JOCF_DEFAULTCLASS;
263 } else {
264 LOG(LOG_ERR, 0,
265 "Unknown keyword '%s' in %s, line %d",
266 *argv, altqconfigfile, line_no);
267 return (0);
269 argc--; argv++;
272 error = qcmd_jobs_add_class(ifname, class_name, pri,
273 adc, rdc, alc, rlc, arc, flags);
275 if (error) {
276 LOG(LOG_ERR, errno, "jobs_class_parser: %s",
277 qoperror(error));
278 return (0);
280 return (1);
284 * qcmd api
287 qcmd_jobs_add_if(const char *ifname, u_int bandwidth, int qlimit, int separate)
289 int error;
291 error = qop_jobs_add_if(NULL, ifname, bandwidth, qlimit, separate);
292 if (error != 0)
293 LOG(LOG_ERR, errno, "%s: can't add jobs on interface '%s'",
294 qoperror(error), ifname);
295 return (error);
299 qcmd_jobs_add_class(const char *ifname, const char *class_name, int pri,
300 int64_t adc, int64_t rdc, int64_t alc, int64_t rlc, int64_t arc,
301 int flags)
303 struct ifinfo *ifinfo;
304 int error = 0;
305 char name_adc[20],name_alc[20],name_rdc[20],name_rlc[20],name_arc[20];
307 if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
308 error = QOPERR_BADIF;
309 if (error == 0)
310 error = qop_jobs_add_class(NULL, class_name, ifinfo,
311 pri, adc, rdc, alc, rlc, arc, flags);
312 if (error != 0)
313 LOG(LOG_ERR, errno,
314 "jobs: %s: can't add class '%s' on interface '%s'",
315 qoperror(error), class_name, ifname);
316 else {
317 if (adc > 0)
318 sprintf(name_adc,"%.3f ms",(double)adc/1000.);
319 else
320 sprintf(name_adc,"N/A");
321 if (alc > 0)
322 sprintf(name_alc,"%.2f%%",
323 (double)100*alc/((u_int64_t)1 << SCALE_LOSS));
324 else
325 sprintf(name_alc,"N/A");
326 if (rdc > 0)
327 sprintf(name_rdc,"%d",(int)rdc);
328 else
329 sprintf(name_rdc,"N/A");
330 if (rlc > 0)
331 sprintf(name_rlc,"%d",(int)rlc);
332 else
333 sprintf(name_rlc,"N/A");
334 if (arc > 0)
335 sprintf(name_arc,"%.2f Mbps",(double)arc/1000000.);
336 else
337 sprintf(name_arc,"N/A");
339 LOG(LOG_INFO, 0,
340 "added '%s' (pri=%d,adc=%s,rdc=%s,alc=%s,rlc=%s,arc=%s) on interface '%s'\n",
341 class_name,pri,name_adc,name_rdc,name_alc,name_rlc,name_arc,ifname);
343 return (error);
347 qcmd_jobs_modify_class(const char *ifname, const char *class_name, int pri,
348 int64_t adc, int64_t rdc, int64_t alc, int64_t rlc, int64_t arc)
350 struct ifinfo *ifinfo;
351 struct classinfo *clinfo;
353 if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
354 return (QOPERR_BADIF);
356 if ((clinfo = clname2clinfo(ifinfo, class_name)) == NULL)
357 return (QOPERR_BADCLASS);
359 return qop_jobs_modify_class(clinfo, pri, adc, rdc, alc, rlc, arc);
363 * qop api
366 qop_jobs_add_if(struct ifinfo **rp, const char *ifname,
367 u_int bandwidth, int qlimit, int separate)
369 struct ifinfo *ifinfo = NULL;
370 struct jobs_ifinfo *jobs_ifinfo;
371 int error;
373 if ((jobs_ifinfo = calloc(1, sizeof(*jobs_ifinfo))) == NULL)
374 return (QOPERR_NOMEM);
375 jobs_ifinfo->qlimit = qlimit;
376 jobs_ifinfo->separate = separate;
378 error = qop_add_if(&ifinfo, ifname, bandwidth,
379 &jobs_qdisc, jobs_ifinfo);
380 if (error != 0) {
381 free(jobs_ifinfo);
382 return (error);
385 if (rp != NULL)
386 *rp = ifinfo;
387 return (0);
390 int
391 qop_jobs_add_class(struct classinfo **rp, const char *class_name,
392 struct ifinfo *ifinfo, int pri,
393 int64_t adc, int64_t rdc, int64_t alc, int64_t rlc, int64_t arc,
394 int flags)
396 struct classinfo *clinfo;
397 struct jobs_ifinfo *jobs_ifinfo;
398 struct jobs_classinfo *jobs_clinfo = NULL;
399 int error;
401 jobs_ifinfo = ifinfo->private;
402 if ((flags & JOCF_DEFAULTCLASS) && jobs_ifinfo->default_class != NULL)
403 return (QOPERR_CLASS_INVAL);
405 if ((jobs_clinfo = calloc(1, sizeof(*jobs_clinfo))) == NULL) {
406 error = QOPERR_NOMEM;
407 goto err_ret;
410 jobs_clinfo->pri = pri;
411 jobs_clinfo->adc = adc;
412 jobs_clinfo->rdc = rdc;
413 jobs_clinfo->alc = alc;
414 jobs_clinfo->rlc = rlc;
415 jobs_clinfo->arc = arc;
416 jobs_clinfo->flags = flags;
418 if ((error = qop_add_class(&clinfo, class_name, ifinfo, NULL,
419 jobs_clinfo)) != 0)
420 goto err_ret;
422 /* set delete hook */
423 clinfo->delete_hook = qop_jobs_delete_class_hook;
425 if (flags & JOCF_DEFAULTCLASS)
426 jobs_ifinfo->default_class = clinfo;
428 if (rp != NULL)
429 *rp = clinfo;
430 return (0);
432 err_ret:
433 if (jobs_clinfo != NULL) {
434 free(jobs_clinfo);
435 clinfo->private = NULL;
438 return (error);
442 * this is called from qop_delete_class() before a class is destroyed
443 * for discipline specific cleanup.
445 static int
446 qop_jobs_delete_class_hook(struct classinfo *clinfo)
448 /* in fact this function doesn't do anything
449 * i'm not sure how/when it's used, so I just
450 * leave it here
452 struct jobs_classinfo *jobs_clinfo;
454 jobs_clinfo = clinfo->private;
455 return (0);
459 qop_jobs_modify_class(struct classinfo *clinfo, int pri,
460 int64_t adc, int64_t rdc, int64_t alc, int64_t rlc, int64_t arc)
462 struct jobs_classinfo *jobs_clinfo = clinfo->private;
463 int error;
464 int pri_old;
465 int64_t adc_old, rdc_old, alc_old, rlc_old, arc_old;
467 pri_old = jobs_clinfo->pri;
468 adc_old = jobs_clinfo->adc;
469 rdc_old = jobs_clinfo->rdc;
470 alc_old = jobs_clinfo->alc;
471 rlc_old = jobs_clinfo->rlc;
472 arc_old = jobs_clinfo->arc;
474 jobs_clinfo = clinfo->private;
475 jobs_clinfo->adc = adc;
476 jobs_clinfo->rdc = rdc;
477 jobs_clinfo->alc = alc;
478 jobs_clinfo->rlc = rlc;
479 jobs_clinfo->arc = arc;
480 jobs_clinfo->pri = pri;
482 error = qop_modify_class(clinfo, NULL);
483 if (error == 0)
484 return (0);
486 /* modify failed!, restore the old service guarantees */
487 jobs_clinfo->adc = adc_old;
488 jobs_clinfo->rdc = rdc_old;
489 jobs_clinfo->alc = alc_old;
490 jobs_clinfo->rlc = rlc_old;
491 jobs_clinfo->arc = arc_old;
492 jobs_clinfo->pri = pri_old;
493 return (error);
496 #if 0
498 * sanity check at enabling jobs:
499 * there must one default class for an interface
501 static int
502 qop_jobs_enable_hook(struct ifinfo *ifinfo)
504 struct jobs_ifinfo *jobs_ifinfo;
506 jobs_ifinfo = ifinfo->private;
507 if (jobs_ifinfo->default_class == NULL) {
508 LOG(LOG_ERR, 0, "jobs: no default class on interface %s!",
509 ifinfo->ifname);
510 return (QOPERR_CLASS);
512 return (0);
514 #endif
517 * system call interfaces for qdisc_ops
519 static int
520 jobs_attach(struct ifinfo *ifinfo)
522 struct jobs_attach attach;
524 if (jobs_fd < 0 &&
525 (jobs_fd = open(JOBS_DEVICE, O_RDWR)) < 0 &&
526 (jobs_fd = open_module(JOBS_DEVICE, O_RDWR)) < 0) {
527 LOG(LOG_ERR, errno, "JOBS open");
528 return (QOPERR_SYSCALL);
531 jobs_refcount++;
532 memset(&attach, 0, sizeof(attach));
533 strncpy(attach.iface.jobs_ifname, ifinfo->ifname, IFNAMSIZ);
534 attach.bandwidth = ifinfo->bandwidth;
535 attach.qlimit = (u_int)((struct jobs_ifinfo*)ifinfo->private)->qlimit;
536 attach.separate = (u_int)((struct jobs_ifinfo*)ifinfo->private)->separate;
538 if (ioctl(jobs_fd, JOBS_IF_ATTACH, (struct jobs_attach*) &attach) < 0)
539 return (QOPERR_SYSCALL);
541 #if 1
542 LOG(LOG_INFO, 0,
543 "jobs attached to %s (b/w = %d bps, buff = %d pkts [%s])\n",
544 attach.iface.jobs_ifname,
545 (int) attach.bandwidth, (int) attach.qlimit,
546 attach.separate?"separate buffers":"shared buffer");
547 #endif
548 return (0);
551 static int
552 jobs_detach(struct ifinfo *ifinfo)
554 struct jobs_interface iface;
556 memset(&iface, 0, sizeof(iface));
557 strncpy(iface.jobs_ifname, ifinfo->ifname, IFNAMSIZ);
559 if (ioctl(jobs_fd, JOBS_IF_DETACH, &iface) < 0)
560 return (QOPERR_SYSCALL);
562 if (--jobs_refcount == 0) {
563 close(jobs_fd);
564 jobs_fd = -1;
566 return (0);
569 static int
570 jobs_enable(struct ifinfo *ifinfo)
572 struct jobs_interface iface;
574 memset(&iface, 0, sizeof(iface));
575 strncpy(iface.jobs_ifname, ifinfo->ifname, IFNAMSIZ);
577 if (ioctl(jobs_fd, JOBS_ENABLE, &iface) < 0)
578 return (QOPERR_SYSCALL);
579 return (0);
582 static int
583 jobs_disable(struct ifinfo *ifinfo)
585 struct jobs_interface iface;
587 memset(&iface, 0, sizeof(iface));
588 strncpy(iface.jobs_ifname, ifinfo->ifname, IFNAMSIZ);
590 if (ioctl(jobs_fd, JOBS_DISABLE, &iface) < 0)
591 return (QOPERR_SYSCALL);
592 return (0);
595 static int
596 jobs_clear(struct ifinfo *ifinfo)
598 struct jobs_interface iface;
600 memset(&iface, 0, sizeof(iface));
601 strncpy(iface.jobs_ifname, ifinfo->ifname, IFNAMSIZ);
603 if (ioctl(jobs_fd, JOBS_CLEAR, &iface) < 0)
604 return (QOPERR_SYSCALL);
605 return (0);
608 static int
609 jobs_add_class(struct classinfo *clinfo)
611 struct jobs_add_class class_add;
612 struct jobs_classinfo *jobs_clinfo;
613 struct jobs_ifinfo *jobs_ifinfo;
615 jobs_ifinfo = clinfo->ifinfo->private;
616 jobs_clinfo = clinfo->private;
618 memset(&class_add, 0, sizeof(class_add));
619 strncpy(class_add.iface.jobs_ifname, clinfo->ifinfo->ifname, IFNAMSIZ);
620 class_add.pri = jobs_clinfo->pri;
621 class_add.cl_adc = jobs_clinfo->adc;
622 class_add.cl_rdc = jobs_clinfo->rdc;
623 class_add.cl_alc = jobs_clinfo->alc;
624 class_add.cl_rlc = jobs_clinfo->rlc;
625 class_add.cl_arc = jobs_clinfo->arc;
626 class_add.flags = jobs_clinfo->flags;
627 if (ioctl(jobs_fd, JOBS_ADD_CLASS, &class_add) < 0) {
628 clinfo->handle = JOBS_NULLCLASS_HANDLE;
629 return (QOPERR_SYSCALL);
631 clinfo->handle = class_add.class_handle;
632 return (0);
635 static int
636 jobs_modify_class(struct classinfo *clinfo, void *arg)
638 struct jobs_modify_class class_mod;
639 struct jobs_classinfo *jobs_clinfo;
641 jobs_clinfo = clinfo->private;
643 memset(&class_mod, 0, sizeof(class_mod));
644 strncpy(class_mod.iface.jobs_ifname, clinfo->ifinfo->ifname, IFNAMSIZ);
645 class_mod.class_handle = clinfo->handle;
647 class_mod.pri = jobs_clinfo->pri;
648 class_mod.cl_adc = jobs_clinfo->adc;
649 class_mod.cl_rdc = jobs_clinfo->rdc;
650 class_mod.cl_alc = jobs_clinfo->alc;
651 class_mod.cl_rlc = jobs_clinfo->rlc;
652 class_mod.cl_arc = jobs_clinfo->arc;
653 class_mod.flags = jobs_clinfo->flags;
655 if (ioctl(jobs_fd, JOBS_MOD_CLASS, &class_mod) < 0)
656 return (QOPERR_SYSCALL);
657 return (0);
660 static int
661 jobs_delete_class(struct classinfo *clinfo)
663 struct jobs_delete_class class_delete;
665 if (clinfo->handle == JOBS_NULLCLASS_HANDLE)
666 return (0);
668 memset(&class_delete, 0, sizeof(class_delete));
669 strncpy(class_delete.iface.jobs_ifname, clinfo->ifinfo->ifname,
670 IFNAMSIZ);
671 class_delete.class_handle = clinfo->handle;
673 if (ioctl(jobs_fd, JOBS_DEL_CLASS, &class_delete) < 0)
674 return (QOPERR_SYSCALL);
675 return (0);
678 static int
679 jobs_add_filter(struct fltrinfo *fltrinfo)
681 struct jobs_add_filter fltr_add;
683 memset(&fltr_add, 0, sizeof(fltr_add));
684 strncpy(fltr_add.iface.jobs_ifname, fltrinfo->clinfo->ifinfo->ifname,
685 IFNAMSIZ);
686 fltr_add.class_handle = fltrinfo->clinfo->handle;
687 fltr_add.filter = fltrinfo->fltr;
689 if (ioctl(jobs_fd, JOBS_ADD_FILTER, &fltr_add) < 0)
690 return (QOPERR_SYSCALL);
691 fltrinfo->handle = fltr_add.filter_handle;
692 return (0);
695 static int
696 jobs_delete_filter(struct fltrinfo *fltrinfo)
698 struct jobs_delete_filter fltr_del;
700 memset(&fltr_del, 0, sizeof(fltr_del));
701 strncpy(fltr_del.iface.jobs_ifname, fltrinfo->clinfo->ifinfo->ifname,
702 IFNAMSIZ);
703 fltr_del.filter_handle = fltrinfo->handle;
705 if (ioctl(jobs_fd, JOBS_DEL_FILTER, &fltr_del) < 0)
706 return (QOPERR_SYSCALL);
707 return (0);