xref: /netbsd-src/usr.sbin/altq/libaltq/qop_jobs.c (revision 0a77b69ab60e06bb70aa1a4d61d4cfa9d106f2ca)
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
jobs_interface_parser(const char * ifname,int argc,char ** argv)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
jobs_class_parser(const char * ifname,const char * class_name,const char * parent_name,int argc,char ** argv)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
qcmd_jobs_add_if(const char * ifname,u_int bandwidth,int qlimit,int separate)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
qcmd_jobs_add_class(const char * ifname,const char * class_name,int pri,int64_t adc,int64_t rdc,int64_t alc,int64_t rlc,int64_t arc,int flags)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
qcmd_jobs_modify_class(const char * ifname,const char * class_name,int pri,int64_t adc,int64_t rdc,int64_t alc,int64_t rlc,int64_t arc)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
qop_jobs_add_if(struct ifinfo ** rp,const char * ifname,u_int bandwidth,int qlimit,int separate)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
qop_jobs_add_class(struct classinfo ** rp,const char * class_name,struct ifinfo * ifinfo,int pri,int64_t adc,int64_t rdc,int64_t alc,int64_t rlc,int64_t arc,int flags)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
qop_jobs_delete_class_hook(struct classinfo * clinfo)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 	return (0);
453 }
454 
455 int
qop_jobs_modify_class(struct classinfo * clinfo,int pri,int64_t adc,int64_t rdc,int64_t alc,int64_t rlc,int64_t arc)456 qop_jobs_modify_class(struct classinfo *clinfo, int pri,
457     int64_t adc, int64_t rdc, int64_t alc, int64_t rlc, int64_t arc)
458 {
459 	struct jobs_classinfo *jobs_clinfo = clinfo->private;
460 	int error;
461 	int pri_old;
462 	int64_t adc_old, rdc_old, alc_old, rlc_old, arc_old;
463 
464 	pri_old = jobs_clinfo->pri;
465 	adc_old = jobs_clinfo->adc;
466 	rdc_old = jobs_clinfo->rdc;
467 	alc_old = jobs_clinfo->alc;
468 	rlc_old = jobs_clinfo->rlc;
469 	arc_old = jobs_clinfo->arc;
470 
471 	jobs_clinfo = clinfo->private;
472 	jobs_clinfo->adc = adc;
473 	jobs_clinfo->rdc = rdc;
474 	jobs_clinfo->alc = alc;
475 	jobs_clinfo->rlc = rlc;
476 	jobs_clinfo->arc = arc;
477 	jobs_clinfo->pri = pri;
478 
479 	error = qop_modify_class(clinfo, NULL);
480 	if (error == 0)
481 		return (0);
482 
483 	/* modify failed!, restore the old service guarantees */
484 	jobs_clinfo->adc = adc_old;
485 	jobs_clinfo->rdc = rdc_old;
486 	jobs_clinfo->alc = alc_old;
487 	jobs_clinfo->rlc = rlc_old;
488 	jobs_clinfo->arc = arc_old;
489 	jobs_clinfo->pri = pri_old;
490 	return (error);
491 }
492 
493 #if 0
494 /*
495  * sanity check at enabling jobs:
496  *  there must one default class for an interface
497  */
498 static int
499 qop_jobs_enable_hook(struct ifinfo *ifinfo)
500 {
501 	struct jobs_ifinfo *jobs_ifinfo;
502 
503 	jobs_ifinfo = ifinfo->private;
504 	if (jobs_ifinfo->default_class == NULL) {
505 		LOG(LOG_ERR, 0, "jobs: no default class on interface %s!",
506 		    ifinfo->ifname);
507 		return (QOPERR_CLASS);
508 	}
509 	return (0);
510 }
511 #endif
512 
513 /*
514  *  system call interfaces for qdisc_ops
515  */
516 static int
jobs_attach(struct ifinfo * ifinfo)517 jobs_attach(struct ifinfo *ifinfo)
518 {
519 	struct jobs_attach attach;
520 
521 	if (jobs_fd < 0 &&
522 	    (jobs_fd = open(JOBS_DEVICE, O_RDWR)) < 0 &&
523 	    (jobs_fd = open_module(JOBS_DEVICE, O_RDWR)) < 0) {
524 		LOG(LOG_ERR, errno, "JOBS open");
525 		return (QOPERR_SYSCALL);
526 	}
527 
528 	jobs_refcount++;
529 	memset(&attach, 0, sizeof(attach));
530 	strncpy(attach.iface.jobs_ifname, ifinfo->ifname, IFNAMSIZ);
531 	attach.bandwidth = ifinfo->bandwidth;
532 	attach.qlimit = (u_int)((struct jobs_ifinfo*)ifinfo->private)->qlimit;
533 	attach.separate = (u_int)((struct jobs_ifinfo*)ifinfo->private)->separate;
534 
535 	if (ioctl(jobs_fd, JOBS_IF_ATTACH, (struct jobs_attach*) &attach) < 0)
536 		return (QOPERR_SYSCALL);
537 
538 #if 1
539 	LOG(LOG_INFO, 0,
540 	    "jobs attached to %s (b/w = %d bps, buff = %d pkts [%s])\n",
541 	    attach.iface.jobs_ifname,
542 	    (int) attach.bandwidth, (int) attach.qlimit,
543 	    attach.separate?"separate buffers":"shared buffer");
544 #endif
545 	return (0);
546 }
547 
548 static int
jobs_detach(struct ifinfo * ifinfo)549 jobs_detach(struct ifinfo *ifinfo)
550 {
551 	struct jobs_interface iface;
552 
553 	memset(&iface, 0, sizeof(iface));
554 	strncpy(iface.jobs_ifname, ifinfo->ifname, IFNAMSIZ);
555 
556 	if (ioctl(jobs_fd, JOBS_IF_DETACH, &iface) < 0)
557 		return (QOPERR_SYSCALL);
558 
559 	if (--jobs_refcount == 0) {
560 		close(jobs_fd);
561 		jobs_fd = -1;
562 	}
563 	return (0);
564 }
565 
566 static int
jobs_enable(struct ifinfo * ifinfo)567 jobs_enable(struct ifinfo *ifinfo)
568 {
569 	struct jobs_interface iface;
570 
571 	memset(&iface, 0, sizeof(iface));
572 	strncpy(iface.jobs_ifname, ifinfo->ifname, IFNAMSIZ);
573 
574 	if (ioctl(jobs_fd, JOBS_ENABLE, &iface) < 0)
575 		return (QOPERR_SYSCALL);
576 	return (0);
577 }
578 
579 static int
jobs_disable(struct ifinfo * ifinfo)580 jobs_disable(struct ifinfo *ifinfo)
581 {
582 	struct jobs_interface iface;
583 
584 	memset(&iface, 0, sizeof(iface));
585 	strncpy(iface.jobs_ifname, ifinfo->ifname, IFNAMSIZ);
586 
587 	if (ioctl(jobs_fd, JOBS_DISABLE, &iface) < 0)
588 		return (QOPERR_SYSCALL);
589 	return (0);
590 }
591 
592 static int
jobs_clear(struct ifinfo * ifinfo)593 jobs_clear(struct ifinfo *ifinfo)
594 {
595 	struct jobs_interface iface;
596 
597 	memset(&iface, 0, sizeof(iface));
598 	strncpy(iface.jobs_ifname, ifinfo->ifname, IFNAMSIZ);
599 
600 	if (ioctl(jobs_fd, JOBS_CLEAR, &iface) < 0)
601 		return (QOPERR_SYSCALL);
602 	return (0);
603 }
604 
605 static int
jobs_add_class(struct classinfo * clinfo)606 jobs_add_class(struct classinfo *clinfo)
607 {
608 	struct jobs_add_class class_add;
609 	struct jobs_classinfo *jobs_clinfo;
610 
611 	jobs_clinfo = clinfo->private;
612 
613 	memset(&class_add, 0, sizeof(class_add));
614 	strncpy(class_add.iface.jobs_ifname, clinfo->ifinfo->ifname, IFNAMSIZ);
615 	class_add.pri = jobs_clinfo->pri;
616 	class_add.cl_adc = jobs_clinfo->adc;
617 	class_add.cl_rdc = jobs_clinfo->rdc;
618 	class_add.cl_alc = jobs_clinfo->alc;
619 	class_add.cl_rlc = jobs_clinfo->rlc;
620 	class_add.cl_arc = jobs_clinfo->arc;
621 	class_add.flags = jobs_clinfo->flags;
622 	if (ioctl(jobs_fd, JOBS_ADD_CLASS, &class_add) < 0) {
623 		clinfo->handle = JOBS_NULLCLASS_HANDLE;
624 		return (QOPERR_SYSCALL);
625 	}
626 	clinfo->handle = class_add.class_handle;
627 	return (0);
628 }
629 
630 static int
jobs_modify_class(struct classinfo * clinfo,void * arg)631 jobs_modify_class(struct classinfo *clinfo, void *arg)
632 {
633 	struct jobs_modify_class class_mod;
634 	struct jobs_classinfo *jobs_clinfo;
635 
636 	jobs_clinfo = clinfo->private;
637 
638 	memset(&class_mod, 0, sizeof(class_mod));
639 	strncpy(class_mod.iface.jobs_ifname, clinfo->ifinfo->ifname, IFNAMSIZ);
640 	class_mod.class_handle = clinfo->handle;
641 
642 	class_mod.pri = jobs_clinfo->pri;
643 	class_mod.cl_adc = jobs_clinfo->adc;
644 	class_mod.cl_rdc = jobs_clinfo->rdc;
645 	class_mod.cl_alc = jobs_clinfo->alc;
646 	class_mod.cl_rlc = jobs_clinfo->rlc;
647 	class_mod.cl_arc = jobs_clinfo->arc;
648 	class_mod.flags = jobs_clinfo->flags;
649 
650 	if (ioctl(jobs_fd, JOBS_MOD_CLASS, &class_mod) < 0)
651 		return (QOPERR_SYSCALL);
652 	return (0);
653 }
654 
655 static int
jobs_delete_class(struct classinfo * clinfo)656 jobs_delete_class(struct classinfo *clinfo)
657 {
658 	struct jobs_delete_class class_delete;
659 
660 	if (clinfo->handle == JOBS_NULLCLASS_HANDLE)
661 		return (0);
662 
663 	memset(&class_delete, 0, sizeof(class_delete));
664 	strncpy(class_delete.iface.jobs_ifname, clinfo->ifinfo->ifname,
665 	    IFNAMSIZ);
666 	class_delete.class_handle = clinfo->handle;
667 
668 	if (ioctl(jobs_fd, JOBS_DEL_CLASS, &class_delete) < 0)
669 		return (QOPERR_SYSCALL);
670 	return (0);
671 }
672 
673 static int
jobs_add_filter(struct fltrinfo * fltrinfo)674 jobs_add_filter(struct fltrinfo *fltrinfo)
675 {
676 	struct jobs_add_filter fltr_add;
677 
678 	memset(&fltr_add, 0, sizeof(fltr_add));
679 	strncpy(fltr_add.iface.jobs_ifname, fltrinfo->clinfo->ifinfo->ifname,
680 	    IFNAMSIZ);
681 	fltr_add.class_handle = fltrinfo->clinfo->handle;
682 	fltr_add.filter = fltrinfo->fltr;
683 
684 	if (ioctl(jobs_fd, JOBS_ADD_FILTER, &fltr_add) < 0)
685 		return (QOPERR_SYSCALL);
686 	fltrinfo->handle = fltr_add.filter_handle;
687 	return (0);
688 }
689 
690 static int
jobs_delete_filter(struct fltrinfo * fltrinfo)691 jobs_delete_filter(struct fltrinfo *fltrinfo)
692 {
693 	struct jobs_delete_filter fltr_del;
694 
695 	memset(&fltr_del, 0, sizeof(fltr_del));
696 	strncpy(fltr_del.iface.jobs_ifname, fltrinfo->clinfo->ifinfo->ifname,
697 	    IFNAMSIZ);
698 	fltr_del.filter_handle = fltrinfo->handle;
699 
700 	if (ioctl(jobs_fd, JOBS_DEL_FILTER, &fltr_del) < 0)
701 		return (QOPERR_SYSCALL);
702 	return (0);
703 }
704