1 /* 2 * lib/route/qdisc/htb.c HTB Qdisc 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2003-2011 Thomas Graf <tgraf (at) suug.ch> 10 * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard (at) siemens.com> 11 * Copyright (c) 2005-2006 Siemens AG Oesterreich 12 */ 13 14 /** 15 * @ingroup qdisc 16 * @ingroup class 17 * @defgroup qdisc_htb Hierachical Token Bucket (HTB) 18 * @{ 19 */ 20 21 #include <netlink-private/netlink.h> 22 #include <netlink-private/tc.h> 23 #include <netlink/netlink.h> 24 #include <netlink/cache.h> 25 #include <netlink/utils.h> 26 #include <netlink-private/route/tc-api.h> 27 #include <netlink/route/qdisc.h> 28 #include <netlink/route/class.h> 29 #include <netlink/route/link.h> 30 #include <netlink/route/qdisc/htb.h> 31 32 /** @cond SKIP */ 33 #define SCH_HTB_HAS_RATE2QUANTUM 0x01 34 #define SCH_HTB_HAS_DEFCLS 0x02 35 36 #define SCH_HTB_HAS_PRIO 0x001 37 #define SCH_HTB_HAS_RATE 0x002 38 #define SCH_HTB_HAS_CEIL 0x004 39 #define SCH_HTB_HAS_RBUFFER 0x008 40 #define SCH_HTB_HAS_CBUFFER 0x010 41 #define SCH_HTB_HAS_QUANTUM 0x020 42 #define SCH_HTB_HAS_LEVEL 0x040 43 /** @endcond */ 44 45 static struct nla_policy htb_policy[TCA_HTB_MAX+1] = { 46 [TCA_HTB_INIT] = { .minlen = sizeof(struct tc_htb_glob) }, 47 [TCA_HTB_PARMS] = { .minlen = sizeof(struct tc_htb_opt) }, 48 }; 49 50 static int htb_qdisc_msg_parser(struct rtnl_tc *tc, void *data) 51 { 52 struct nlattr *tb[TCA_HTB_MAX + 1]; 53 struct rtnl_htb_qdisc *htb = data; 54 int err; 55 56 if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0) 57 return err; 58 59 if (tb[TCA_HTB_INIT]) { 60 struct tc_htb_glob opts; 61 62 nla_memcpy(&opts, tb[TCA_HTB_INIT], sizeof(opts)); 63 htb->qh_rate2quantum = opts.rate2quantum; 64 htb->qh_defcls = opts.defcls; 65 htb->qh_direct_pkts = opts.direct_pkts; 66 67 htb->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS); 68 } 69 70 return 0; 71 } 72 73 static int htb_class_msg_parser(struct rtnl_tc *tc, void *data) 74 { 75 struct nlattr *tb[TCA_HTB_MAX + 1]; 76 struct rtnl_htb_class *htb = data; 77 int err; 78 79 if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0) 80 return err; 81 82 if (tb[TCA_HTB_PARMS]) { 83 struct tc_htb_opt opts; 84 85 nla_memcpy(&opts, tb[TCA_HTB_PARMS], sizeof(opts)); 86 htb->ch_prio = opts.prio; 87 rtnl_copy_ratespec(&htb->ch_rate, &opts.rate); 88 rtnl_copy_ratespec(&htb->ch_ceil, &opts.ceil); 89 htb->ch_rbuffer = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer), 90 opts.rate.rate); 91 htb->ch_cbuffer = rtnl_tc_calc_bufsize(nl_ticks2us(opts.cbuffer), 92 opts.ceil.rate); 93 htb->ch_quantum = opts.quantum; 94 htb->ch_level = opts.level; 95 96 rtnl_tc_set_mpu(tc, htb->ch_rate.rs_mpu); 97 rtnl_tc_set_overhead(tc, htb->ch_rate.rs_overhead); 98 99 htb->ch_mask = (SCH_HTB_HAS_PRIO | SCH_HTB_HAS_RATE | 100 SCH_HTB_HAS_CEIL | SCH_HTB_HAS_RBUFFER | 101 SCH_HTB_HAS_CBUFFER | SCH_HTB_HAS_QUANTUM | 102 SCH_HTB_HAS_LEVEL); 103 } 104 105 return 0; 106 } 107 108 static void htb_qdisc_dump_line(struct rtnl_tc *tc, void *data, 109 struct nl_dump_params *p) 110 { 111 struct rtnl_htb_qdisc *htb = data; 112 113 if (!htb) 114 return; 115 116 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM) 117 nl_dump(p, " r2q %u", htb->qh_rate2quantum); 118 119 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) { 120 char buf[64]; 121 nl_dump(p, " default-class %s", 122 rtnl_tc_handle2str(htb->qh_defcls, buf, sizeof(buf))); 123 } 124 } 125 126 static void htb_class_dump_line(struct rtnl_tc *tc, void *data, 127 struct nl_dump_params *p) 128 { 129 struct rtnl_htb_class *htb = data; 130 131 if (!htb) 132 return; 133 134 if (htb->ch_mask & SCH_HTB_HAS_RATE) { 135 double r, rbit; 136 char *ru, *rubit; 137 138 r = nl_cancel_down_bytes(htb->ch_rate.rs_rate, &ru); 139 rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate*8, &rubit); 140 141 nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u", 142 r, ru, rbit, rubit, 1<<htb->ch_rate.rs_cell_log); 143 } 144 } 145 146 static void htb_class_dump_details(struct rtnl_tc *tc, void *data, 147 struct nl_dump_params *p) 148 { 149 struct rtnl_htb_class *htb = data; 150 151 if (!htb) 152 return; 153 154 /* line 1 */ 155 if (htb->ch_mask & SCH_HTB_HAS_CEIL) { 156 double r, rbit; 157 char *ru, *rubit; 158 159 r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate, &ru); 160 rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate*8, &rubit); 161 162 nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u", 163 r, ru, rbit, rubit, 1<<htb->ch_ceil.rs_cell_log); 164 } 165 166 if (htb->ch_mask & SCH_HTB_HAS_PRIO) 167 nl_dump(p, " prio %u", htb->ch_prio); 168 169 if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) { 170 double b; 171 char *bu; 172 173 b = nl_cancel_down_bytes(htb->ch_rbuffer, &bu); 174 nl_dump(p, " rbuffer %.2f%s", b, bu); 175 } 176 177 if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) { 178 double b; 179 char *bu; 180 181 b = nl_cancel_down_bytes(htb->ch_cbuffer, &bu); 182 nl_dump(p, " cbuffer %.2f%s", b, bu); 183 } 184 185 if (htb->ch_mask & SCH_HTB_HAS_QUANTUM) 186 nl_dump(p, " quantum %u", htb->ch_quantum); 187 } 188 189 static int htb_qdisc_msg_fill(struct rtnl_tc *tc, void *data, 190 struct nl_msg *msg) 191 { 192 struct rtnl_htb_qdisc *htb = data; 193 struct tc_htb_glob opts = { 194 .version = TC_HTB_PROTOVER, 195 .rate2quantum = 10, 196 }; 197 198 if (htb) { 199 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM) 200 opts.rate2quantum = htb->qh_rate2quantum; 201 202 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) 203 opts.defcls = htb->qh_defcls; 204 } 205 206 return nla_put(msg, TCA_HTB_INIT, sizeof(opts), &opts); 207 } 208 209 static int htb_class_msg_fill(struct rtnl_tc *tc, void *data, 210 struct nl_msg *msg) 211 { 212 struct rtnl_htb_class *htb = data; 213 uint32_t mtu, rtable[RTNL_TC_RTABLE_SIZE], ctable[RTNL_TC_RTABLE_SIZE]; 214 struct tc_htb_opt opts; 215 int buffer, cbuffer; 216 217 if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE)) 218 BUG(); 219 220 memset(&opts, 0, sizeof(opts)); 221 222 /* if not set, zero (0) is used as priority */ 223 if (htb->ch_mask & SCH_HTB_HAS_PRIO) 224 opts.prio = htb->ch_prio; 225 226 mtu = rtnl_tc_get_mtu(tc); 227 228 rtnl_tc_build_rate_table(tc, &htb->ch_rate, rtable); 229 rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate); 230 231 if (htb->ch_mask & SCH_HTB_HAS_CEIL) { 232 rtnl_tc_build_rate_table(tc, &htb->ch_ceil, ctable); 233 rtnl_rcopy_ratespec(&opts.ceil, &htb->ch_ceil); 234 } else { 235 /* 236 * If not set, configured rate is used as ceil, which implies 237 * no borrowing. 238 */ 239 memcpy(&opts.ceil, &opts.rate, sizeof(struct tc_ratespec)); 240 } 241 242 if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) 243 buffer = htb->ch_rbuffer; 244 else 245 buffer = opts.rate.rate / nl_get_psched_hz() + mtu; /* XXX */ 246 247 opts.buffer = nl_us2ticks(rtnl_tc_calc_txtime(buffer, opts.rate.rate)); 248 249 if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) 250 cbuffer = htb->ch_cbuffer; 251 else 252 cbuffer = opts.ceil.rate / nl_get_psched_hz() + mtu; /* XXX */ 253 254 opts.cbuffer = nl_us2ticks(rtnl_tc_calc_txtime(cbuffer, opts.ceil.rate)); 255 256 if (htb->ch_mask & SCH_HTB_HAS_QUANTUM) 257 opts.quantum = htb->ch_quantum; 258 259 NLA_PUT(msg, TCA_HTB_PARMS, sizeof(opts), &opts); 260 NLA_PUT(msg, TCA_HTB_RTAB, sizeof(rtable), &rtable); 261 NLA_PUT(msg, TCA_HTB_CTAB, sizeof(ctable), &ctable); 262 263 return 0; 264 265 nla_put_failure: 266 return -NLE_MSGSIZE; 267 } 268 269 static struct rtnl_tc_ops htb_qdisc_ops; 270 static struct rtnl_tc_ops htb_class_ops; 271 272 static struct rtnl_htb_qdisc *htb_qdisc_data(struct rtnl_qdisc *qdisc) 273 { 274 return rtnl_tc_data_check(TC_CAST(qdisc), &htb_qdisc_ops); 275 } 276 277 static struct rtnl_htb_class *htb_class_data(struct rtnl_class *class) 278 { 279 return rtnl_tc_data_check(TC_CAST(class), &htb_class_ops); 280 } 281 282 /** 283 * @name Attribute Modifications 284 * @{ 285 */ 286 287 /** 288 * Return rate/quantum ratio of HTB qdisc 289 * @arg qdisc htb qdisc object 290 * 291 * @return rate/quantum ratio or 0 if unspecified 292 */ 293 uint32_t rtnl_htb_get_rate2quantum(struct rtnl_qdisc *qdisc) 294 { 295 struct rtnl_htb_qdisc *htb; 296 297 if ((htb = htb_qdisc_data(qdisc)) && 298 htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM) 299 return htb->qh_rate2quantum; 300 301 return 0; 302 } 303 304 int rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum) 305 { 306 struct rtnl_htb_qdisc *htb; 307 308 if (!(htb = htb_qdisc_data(qdisc))) 309 return -NLE_OPNOTSUPP; 310 311 htb->qh_rate2quantum = rate2quantum; 312 htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM; 313 314 return 0; 315 } 316 317 /** 318 * Return default class of HTB qdisc 319 * @arg qdisc htb qdisc object 320 * 321 * Returns the classid of the class where all unclassified traffic 322 * goes to. 323 * 324 * @return classid or TC_H_UNSPEC if unspecified. 325 */ 326 uint32_t rtnl_htb_get_defcls(struct rtnl_qdisc *qdisc) 327 { 328 struct rtnl_htb_qdisc *htb; 329 330 if ((htb = htb_qdisc_data(qdisc)) && 331 htb->qh_mask & SCH_HTB_HAS_DEFCLS) 332 return htb->qh_defcls; 333 334 return TC_H_UNSPEC; 335 } 336 337 /** 338 * Set default class of the htb qdisc to the specified value 339 * @arg qdisc qdisc to change 340 * @arg defcls new default class 341 */ 342 int rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls) 343 { 344 struct rtnl_htb_qdisc *htb; 345 346 if (!(htb = htb_qdisc_data(qdisc))) 347 return -NLE_OPNOTSUPP; 348 349 htb->qh_defcls = defcls; 350 htb->qh_mask |= SCH_HTB_HAS_DEFCLS; 351 352 return 0; 353 } 354 355 uint32_t rtnl_htb_get_prio(struct rtnl_class *class) 356 { 357 struct rtnl_htb_class *htb; 358 359 if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_PRIO) 360 return htb->ch_prio; 361 362 return 0; 363 } 364 365 int rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio) 366 { 367 struct rtnl_htb_class *htb; 368 369 if (!(htb = htb_class_data(class))) 370 return -NLE_OPNOTSUPP; 371 372 htb->ch_prio = prio; 373 htb->ch_mask |= SCH_HTB_HAS_PRIO; 374 375 return 0; 376 } 377 378 /** 379 * Return rate of HTB class 380 * @arg class htb class object 381 * 382 * @return Rate in bytes/s or 0 if unspecified. 383 */ 384 uint32_t rtnl_htb_get_rate(struct rtnl_class *class) 385 { 386 struct rtnl_htb_class *htb; 387 388 if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_RATE) 389 return htb->ch_rate.rs_rate; 390 391 return 0; 392 } 393 394 /** 395 * Set rate of HTB class 396 * @arg class htb class object 397 * @arg rate new rate in bytes per second 398 * 399 * @return 0 on success or a negative error code. 400 */ 401 int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate) 402 { 403 struct rtnl_htb_class *htb; 404 405 if (!(htb = htb_class_data(class))) 406 return -NLE_OPNOTSUPP; 407 408 htb->ch_rate.rs_cell_log = UINT8_MAX; /* use default value */ 409 htb->ch_rate.rs_rate = rate; 410 htb->ch_mask |= SCH_HTB_HAS_RATE; 411 412 return 0; 413 } 414 415 /** 416 * Return ceil rate of HTB class 417 * @arg class htb class object 418 * 419 * @return Ceil rate in bytes/s or 0 if unspecified 420 */ 421 uint32_t rtnl_htb_get_ceil(struct rtnl_class *class) 422 { 423 struct rtnl_htb_class *htb; 424 425 if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_CEIL) 426 return htb->ch_ceil.rs_rate; 427 428 return 0; 429 } 430 431 /** 432 * Set ceil rate of HTB class 433 * @arg class htb class object 434 * @arg ceil new ceil rate number of bytes per second 435 * 436 * @return 0 on success or a negative error code. 437 */ 438 int rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil) 439 { 440 struct rtnl_htb_class *htb; 441 442 if (!(htb = htb_class_data(class))) 443 return -NLE_OPNOTSUPP; 444 445 htb->ch_ceil.rs_cell_log = UINT8_MAX; /* use default value */ 446 htb->ch_ceil.rs_rate = ceil; 447 htb->ch_mask |= SCH_HTB_HAS_CEIL; 448 449 return 0; 450 } 451 452 /** 453 * Return burst buffer size of HTB class 454 * @arg class htb class object 455 * 456 * @return Burst buffer size or 0 if unspecified 457 */ 458 uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *class) 459 { 460 struct rtnl_htb_class *htb; 461 462 if ((htb = htb_class_data(class)) && 463 htb->ch_mask & SCH_HTB_HAS_RBUFFER) 464 return htb->ch_rbuffer; 465 466 return 0; 467 } 468 469 /** 470 * Set size of the rate bucket of HTB class. 471 * @arg class HTB class to be modified. 472 * @arg rbuffer New size in bytes. 473 */ 474 int rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer) 475 { 476 struct rtnl_htb_class *htb; 477 478 if (!(htb = htb_class_data(class))) 479 return -NLE_OPNOTSUPP; 480 481 htb->ch_rbuffer = rbuffer; 482 htb->ch_mask |= SCH_HTB_HAS_RBUFFER; 483 484 return 0; 485 } 486 487 /** 488 * Return ceil burst buffer size of HTB class 489 * @arg class htb class object 490 * 491 * @return Ceil burst buffer size or 0 if unspecified 492 */ 493 uint32_t rtnl_htb_get_cbuffer(struct rtnl_class *class) 494 { 495 struct rtnl_htb_class *htb; 496 497 if ((htb = htb_class_data(class)) && 498 htb->ch_mask & SCH_HTB_HAS_CBUFFER) 499 return htb->ch_cbuffer; 500 501 return 0; 502 } 503 504 /** 505 * Set size of the ceil bucket of HTB class. 506 * @arg class HTB class to be modified. 507 * @arg cbuffer New size in bytes. 508 */ 509 int rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer) 510 { 511 struct rtnl_htb_class *htb; 512 513 if (!(htb = htb_class_data(class))) 514 return -NLE_OPNOTSUPP; 515 516 htb->ch_cbuffer = cbuffer; 517 htb->ch_mask |= SCH_HTB_HAS_CBUFFER; 518 519 return 0; 520 } 521 522 /** 523 * Return quantum of HTB class 524 * @arg class htb class object 525 * 526 * See XXX[quantum def] 527 * 528 * @return Quantum or 0 if unspecified. 529 */ 530 uint32_t rtnl_htb_get_quantum(struct rtnl_class *class) 531 { 532 struct rtnl_htb_class *htb; 533 534 if ((htb = htb_class_data(class)) && 535 htb->ch_mask & SCH_HTB_HAS_QUANTUM) 536 return htb->ch_quantum; 537 538 return 0; 539 } 540 541 /** 542 * Set quantum of HTB class (overwrites value calculated based on r2q) 543 * @arg class htb class object 544 * @arg quantum new quantum in number of bytes 545 * 546 * See XXX[quantum def] 547 * 548 * @return 0 on success or a negative error code. 549 */ 550 int rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum) 551 { 552 struct rtnl_htb_class *htb; 553 554 if (!(htb = htb_class_data(class))) 555 return -NLE_OPNOTSUPP; 556 557 htb->ch_quantum = quantum; 558 htb->ch_mask |= SCH_HTB_HAS_QUANTUM; 559 560 return 0; 561 } 562 563 /** 564 * Return level of HTB class 565 * @arg class htb class object 566 * 567 * Returns the level of the HTB class. Leaf classes are assigned level 568 * 0, root classes have level (TC_HTB_MAXDEPTH - 1). Interior classes 569 * have a level of one less than their parent. 570 * 571 * @return Level or -NLE_OPNOTSUPP 572 */ 573 int rtnl_htb_get_level(struct rtnl_class *class) 574 { 575 struct rtnl_htb_class *htb; 576 577 if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_LEVEL) 578 return htb->ch_level; 579 580 return -NLE_OPNOTSUPP; 581 } 582 583 /** 584 * Set level of HTB class 585 * @arg class htb class object 586 * @arg level new level of HTB class 587 * 588 * Sets the level of a HTB class. Note that changing the level of a HTB 589 * class does not change the level of its in kernel counterpart. This 590 * function is provided only to create HTB objects which can be compared 591 * against or filtered upon. 592 * 593 * @return 0 on success or a negative error code. 594 */ 595 int rtnl_htb_set_level(struct rtnl_class *class, int level) 596 { 597 struct rtnl_htb_class *htb; 598 599 if (!(htb = htb_class_data(class))) 600 return -NLE_OPNOTSUPP; 601 602 htb->ch_level = level; 603 htb->ch_mask |= SCH_HTB_HAS_LEVEL; 604 605 return 0; 606 } 607 608 /** @} */ 609 610 static struct rtnl_tc_ops htb_qdisc_ops = { 611 .to_kind = "htb", 612 .to_type = RTNL_TC_TYPE_QDISC, 613 .to_size = sizeof(struct rtnl_htb_qdisc), 614 .to_msg_parser = htb_qdisc_msg_parser, 615 .to_dump[NL_DUMP_LINE] = htb_qdisc_dump_line, 616 .to_msg_fill = htb_qdisc_msg_fill, 617 }; 618 619 static struct rtnl_tc_ops htb_class_ops = { 620 .to_kind = "htb", 621 .to_type = RTNL_TC_TYPE_CLASS, 622 .to_size = sizeof(struct rtnl_htb_class), 623 .to_msg_parser = htb_class_msg_parser, 624 .to_dump = { 625 [NL_DUMP_LINE] = htb_class_dump_line, 626 [NL_DUMP_DETAILS] = htb_class_dump_details, 627 }, 628 .to_msg_fill = htb_class_msg_fill, 629 }; 630 631 static void __init htb_init(void) 632 { 633 rtnl_tc_register(&htb_qdisc_ops); 634 rtnl_tc_register(&htb_class_ops); 635 } 636 637 static void __exit htb_exit(void) 638 { 639 rtnl_tc_unregister(&htb_qdisc_ops); 640 rtnl_tc_unregister(&htb_class_ops); 641 } 642 643 /** @} */ 644