xref: /netbsd-src/usr.sbin/altq/libaltq/qop_jobs.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
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.
6  *
7  * Redistribution and use in source and binary forms,
8  * with or without modification, are permitted provided
9  * that the following conditions are met:
10  *
11  * Redistributions of source code must retain the above
12  * copyright notice, this list of conditions and the following
13  * disclaimer.
14  *
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.
19  *
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.
24  *
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.
38  */
39 /*
40  * Copyright (C) 1999-2000
41  *	Sony Computer Science Laboratories, Inc.  All rights reserved.
42  *
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.
51  *
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.
63  */
64 /*
65  * JoBS - altq prototype implementation
66  *
67  * Author: Nicolas Christin <nicolas@cs.virginia.edu>
68  *
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.
75  *
76  * http://qosbox.cs.virginia.edu
77  *
78  */
79 
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>
88 
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>
98 
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
105 
106 #if 0
107 static int qop_jobs_enable_hook(struct ifinfo *);
108 #endif
109 static int qop_jobs_delete_class_hook(struct classinfo *);
110 
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 *);
121 
122 #define JOBS_DEVICE	"/dev/altq/jobs"
123 
124 static int jobs_fd = -1;
125 static int jobs_refcount = 0;
126 
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
140 };
141 
142 /*
143  * parser interface
144  */
145 #define EQUAL(s1, s2)	(strcmp((s1), (s2)) == 0)
146 
147 int
148 jobs_interface_parser(const char *ifname, int argc, char **argv)
149 {
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 */
154 
155 	/*
156 	 * process options
157 	 */
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);
179 		}
180 		argc--; argv++;
181 	}
182 
183 	if (qcmd_tbr_register(ifname, bandwidth, tbrsize) != 0)
184 		return (0);
185 
186 	if (qcmd_jobs_add_if(ifname, bandwidth, qlimit, separate) != 0)
187 		return (0);
188 	return (1);
189 }
190 
191 int
192 jobs_class_parser(const char *ifname, const char *class_name,
193 		  const char *parent_name, int argc, char **argv)
194 {
195 	int64_t adc, rdc, alc, rlc, arc;
196 	int	pri = 0;
197 	int	flags = 0;
198 	int	error;
199 
200 	/* disable everything by default */
201 	adc = -1;
202 	rdc = -1;
203 	arc = -1;
204 	alc = -1;
205 	rlc = -1;
206 
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);
215 			}
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);
223 			}
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);
231 			}
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));
240 				/*
241 				 * alc is given in fraction of 1, convert it
242 				 * to a fraction of 2^(SCALE_LOSS)
243 				 */
244 			}
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);
252 			}
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);
260 			}
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);
268 		}
269 		argc--; argv++;
270 	}
271 
272 	error = qcmd_jobs_add_class(ifname, class_name, pri,
273 	    adc, rdc, alc, rlc, arc, flags);
274 
275 	if (error) {
276 		LOG(LOG_ERR, errno, "jobs_class_parser: %s",
277 		    qoperror(error));
278 		return (0);
279 	}
280 	return (1);
281 }
282 
283 /*
284  * qcmd api
285  */
286 int
287 qcmd_jobs_add_if(const char *ifname, u_int bandwidth, int qlimit, int separate)
288 {
289 	int error;
290 
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);
296 }
297 
298 int
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)
302 {
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];
306 
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");
338 
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);
342 	}
343 	return (error);
344 }
345 
346 int
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)
349 {
350 	struct ifinfo *ifinfo;
351 	struct classinfo *clinfo;
352 
353 	if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
354 		return (QOPERR_BADIF);
355 
356 	if ((clinfo = clname2clinfo(ifinfo, class_name)) == NULL)
357 		return (QOPERR_BADCLASS);
358 
359 	return qop_jobs_modify_class(clinfo, pri, adc, rdc, alc, rlc, arc);
360 }
361 
362 /*
363  * qop api
364  */
365 int
366 qop_jobs_add_if(struct ifinfo **rp, const char *ifname,
367     u_int bandwidth, int qlimit, int separate)
368 {
369 	struct ifinfo *ifinfo = NULL;
370 	struct jobs_ifinfo *jobs_ifinfo;
371 	int error;
372 
373 	if ((jobs_ifinfo = calloc(1, sizeof(*jobs_ifinfo))) == NULL)
374 		return (QOPERR_NOMEM);
375 	jobs_ifinfo->qlimit   = qlimit;
376 	jobs_ifinfo->separate = separate;
377 
378 	error = qop_add_if(&ifinfo, ifname, bandwidth,
379 	    &jobs_qdisc, jobs_ifinfo);
380 	if (error != 0) {
381 		free(jobs_ifinfo);
382 		return (error);
383 	}
384 
385 	if (rp != NULL)
386 		*rp = ifinfo;
387 	return (0);
388 }
389 
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)
395 {
396 	struct classinfo *clinfo;
397 	struct jobs_ifinfo *jobs_ifinfo;
398 	struct jobs_classinfo *jobs_clinfo = NULL;
399 	int error;
400 
401 	jobs_ifinfo = ifinfo->private;
402 	if ((flags & JOCF_DEFAULTCLASS) && jobs_ifinfo->default_class != NULL)
403 		return (QOPERR_CLASS_INVAL);
404 
405 	if ((jobs_clinfo = calloc(1, sizeof(*jobs_clinfo))) == NULL) {
406 		error = QOPERR_NOMEM;
407 		goto err_ret;
408 	}
409 
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;
417 
418 	if ((error = qop_add_class(&clinfo, class_name, ifinfo, NULL,
419 	    jobs_clinfo)) != 0)
420 		goto err_ret;
421 
422 	/* set delete hook */
423 	clinfo->delete_hook = qop_jobs_delete_class_hook;
424 
425 	if (flags & JOCF_DEFAULTCLASS)
426 		jobs_ifinfo->default_class = clinfo;
427 
428 	if (rp != NULL)
429 		*rp = clinfo;
430 	return (0);
431 
432 err_ret:
433 	if (jobs_clinfo != NULL) {
434 		free(jobs_clinfo);
435 		clinfo->private = NULL;
436 	}
437 
438 	return (error);
439 }
440 
441 /*
442  * this is called from qop_delete_class() before a class is destroyed
443  * for discipline specific cleanup.
444  */
445 static int
446 qop_jobs_delete_class_hook(struct classinfo *clinfo)
447 {
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
451 	 */
452 	struct jobs_classinfo *jobs_clinfo;
453 
454 	jobs_clinfo = clinfo->private;
455 	return (0);
456 }
457 
458 int
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)
461 {
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;
466 
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;
473 
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;
481 
482 	error = qop_modify_class(clinfo, NULL);
483 	if (error == 0)
484 		return (0);
485 
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);
494 }
495 
496 #if 0
497 /*
498  * sanity check at enabling jobs:
499  *  there must one default class for an interface
500  */
501 static int
502 qop_jobs_enable_hook(struct ifinfo *ifinfo)
503 {
504 	struct jobs_ifinfo *jobs_ifinfo;
505 
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);
511 	}
512 	return (0);
513 }
514 #endif
515 
516 /*
517  *  system call interfaces for qdisc_ops
518  */
519 static int
520 jobs_attach(struct ifinfo *ifinfo)
521 {
522 	struct jobs_attach attach;
523 
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);
529 	}
530 
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;
537 
538 	if (ioctl(jobs_fd, JOBS_IF_ATTACH, (struct jobs_attach*) &attach) < 0)
539 		return (QOPERR_SYSCALL);
540 
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);
549 }
550 
551 static int
552 jobs_detach(struct ifinfo *ifinfo)
553 {
554 	struct jobs_interface iface;
555 
556 	memset(&iface, 0, sizeof(iface));
557 	strncpy(iface.jobs_ifname, ifinfo->ifname, IFNAMSIZ);
558 
559 	if (ioctl(jobs_fd, JOBS_IF_DETACH, &iface) < 0)
560 		return (QOPERR_SYSCALL);
561 
562 	if (--jobs_refcount == 0) {
563 		close(jobs_fd);
564 		jobs_fd = -1;
565 	}
566 	return (0);
567 }
568 
569 static int
570 jobs_enable(struct ifinfo *ifinfo)
571 {
572 	struct jobs_interface iface;
573 
574 	memset(&iface, 0, sizeof(iface));
575 	strncpy(iface.jobs_ifname, ifinfo->ifname, IFNAMSIZ);
576 
577 	if (ioctl(jobs_fd, JOBS_ENABLE, &iface) < 0)
578 		return (QOPERR_SYSCALL);
579 	return (0);
580 }
581 
582 static int
583 jobs_disable(struct ifinfo *ifinfo)
584 {
585 	struct jobs_interface iface;
586 
587 	memset(&iface, 0, sizeof(iface));
588 	strncpy(iface.jobs_ifname, ifinfo->ifname, IFNAMSIZ);
589 
590 	if (ioctl(jobs_fd, JOBS_DISABLE, &iface) < 0)
591 		return (QOPERR_SYSCALL);
592 	return (0);
593 }
594 
595 static int
596 jobs_clear(struct ifinfo *ifinfo)
597 {
598 	struct jobs_interface iface;
599 
600 	memset(&iface, 0, sizeof(iface));
601 	strncpy(iface.jobs_ifname, ifinfo->ifname, IFNAMSIZ);
602 
603 	if (ioctl(jobs_fd, JOBS_CLEAR, &iface) < 0)
604 		return (QOPERR_SYSCALL);
605 	return (0);
606 }
607 
608 static int
609 jobs_add_class(struct classinfo *clinfo)
610 {
611 	struct jobs_add_class class_add;
612 	struct jobs_classinfo *jobs_clinfo;
613 	struct jobs_ifinfo *jobs_ifinfo;
614 
615 	jobs_ifinfo = clinfo->ifinfo->private;
616 	jobs_clinfo = clinfo->private;
617 
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);
630 	}
631 	clinfo->handle = class_add.class_handle;
632 	return (0);
633 }
634 
635 static int
636 jobs_modify_class(struct classinfo *clinfo, void *arg)
637 {
638 	struct jobs_modify_class class_mod;
639 	struct jobs_classinfo *jobs_clinfo;
640 
641 	jobs_clinfo = clinfo->private;
642 
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;
646 
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;
654 
655 	if (ioctl(jobs_fd, JOBS_MOD_CLASS, &class_mod) < 0)
656 		return (QOPERR_SYSCALL);
657 	return (0);
658 }
659 
660 static int
661 jobs_delete_class(struct classinfo *clinfo)
662 {
663 	struct jobs_delete_class class_delete;
664 
665 	if (clinfo->handle == JOBS_NULLCLASS_HANDLE)
666 		return (0);
667 
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;
672 
673 	if (ioctl(jobs_fd, JOBS_DEL_CLASS, &class_delete) < 0)
674 		return (QOPERR_SYSCALL);
675 	return (0);
676 }
677 
678 static int
679 jobs_add_filter(struct fltrinfo *fltrinfo)
680 {
681 	struct jobs_add_filter fltr_add;
682 
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;
688 
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);
693 }
694 
695 static int
696 jobs_delete_filter(struct fltrinfo *fltrinfo)
697 {
698 	struct jobs_delete_filter fltr_del;
699 
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;
704 
705 	if (ioctl(jobs_fd, JOBS_DEL_FILTER, &fltr_del) < 0)
706 		return (QOPERR_SYSCALL);
707 	return (0);
708 }
709