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 (at) 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 return (0); 453 } 454 455 int 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 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 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 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 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 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 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 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 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 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 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